From 78580f1e4ea86eda0f8f737fa679f0b730075d54 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Thu, 9 Apr 2026 04:56:30 +0000 Subject: [PATCH 01/90] 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 a9b35220de39..d2ab41cb8310 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; - -public class GetMethodsReturnClones { + 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"; - 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 02/90] 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 d4efaa7e6310..b4f9efff8304 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 91b7113ac14f..2d6ca8222a47 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 static void runB64toB512() throws Throwable { } @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 bd3a8f6c12df..92755b96acbd 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 @@ */ 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 static void runB64toB512() throws Throwable { } @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 2143eb3b5003..d3283e991a47 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 @@ */ 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 static void runB64toS64() throws Throwable { } @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 static void runB64toI64() throws Throwable { } @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 static void runB64toL64() throws Throwable { } @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 static void runB64toF64() throws Throwable { } @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 static void runB64toD64() throws Throwable { } @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 static void runS64toB64() throws Throwable { } @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 static void runS64toI64() throws Throwable { } @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 static void runS64toL64() throws Throwable { } @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 static void runS64toF64() throws Throwable { } @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 static void runS64toD64() throws Throwable { } @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 static void runI64toB64() throws Throwable { } @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 static void runI64toS64() throws Throwable { } @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 static void runI64toL64() throws Throwable { } @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 static void runI64toF64() throws Throwable { } @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 static void runI64toD64() throws Throwable { } @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 static void runL64toB64() throws Throwable { } @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 static void runL64toS64() throws Throwable { } @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 static void runL64toI64() throws Throwable { } @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 static void runL64toF64() throws Throwable { } @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 static void runL64toD64() throws Throwable { } @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 static void runF64toB64() throws Throwable { } @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 static void runF64toS64() throws Throwable { } @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 static void runF64toI64() throws Throwable { } @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 static void runF64toL64() throws Throwable { } @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 static void runF64toD64() throws Throwable { } @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 static void runD64toB64() throws Throwable { } @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 static void runD64toS64() throws Throwable { } @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 static void runD64toI64() throws Throwable { } @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 static void runD64toL64() throws Throwable { } @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 03/90] 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 dab0ca989118..2f64482f55b5 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 483a3a862672..aa62ee05cd0c 100644 --- a/src/hotspot/share/opto/arraycopynode.hpp +++ b/src/hotspot/share/opto/arraycopynode.hpp @@ -104,6 +104,10 @@ class ArrayCopyNode : public CallNode { 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 000000000000..251c053ff5da --- /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 04/90] 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 3d6013f557c0..dbffec82e282 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 4dedfed97b12..bae8d55c8cc2 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 fb67cf025667..df6c9902cf95 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 59ad2179b902..dd6f9b065b7e 100644 --- a/test/jdk/java/net/httpclient/AltServiceUsageTest.java +++ b/test/jdk/java/net/httpclient/AltServiceUsageTest.java @@ -56,7 +56,7 @@ * * @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 6e9c4e676cf3..fca920cb13cd 100644 --- a/test/jdk/java/net/httpclient/AsFileDownloadTest.java +++ b/test/jdk/java/net/httpclient/AsFileDownloadTest.java @@ -87,7 +87,7 @@ * 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 308288bb9bf4..ed2482e80b57 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 7dc13cf08e2c..39e13b782c9b 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 0d87055ff513..9fb231de8585 100644 --- a/test/jdk/java/net/httpclient/AuthFilterCacheTest.java +++ b/test/jdk/java/net/httpclient/AuthFilterCacheTest.java @@ -67,7 +67,7 @@ * @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 8e0231c8eafb..128cae0ed20b 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 fc1f1d4e5aa7..f9458fff6a61 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 4175aceea3d5..6f53dd1081c9 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 aec21e421f96..b37640168182 100644 --- a/test/jdk/java/net/httpclient/BasicHTTP3Test.java +++ b/test/jdk/java/net/httpclient/BasicHTTP3Test.java @@ -76,7 +76,7 @@ * @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 d873a64bb1bf..44e3cadd8cdc 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 1f316c2a64d5..c82910cc76b8 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 @@ * @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 abd86693b830..f27642a47a6f 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 e4f2b998cc73..2d7f34f315a7 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 @@ * 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 d9695dce3cb0..f5f77bb4778c 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 @@ * @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 4d73ec312803..dbcfae4d4761 100644 --- a/test/jdk/java/net/httpclient/BufferingSubscriberCancelTest.java +++ b/test/jdk/java/net/httpclient/BufferingSubscriberCancelTest.java @@ -46,7 +46,7 @@ /* * @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 255946232be9..5895df7d3dc0 100644 --- a/test/jdk/java/net/httpclient/BufferingSubscriberErrorCompleteTest.java +++ b/test/jdk/java/net/httpclient/BufferingSubscriberErrorCompleteTest.java @@ -44,7 +44,7 @@ /* * @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 bb33b18ed9ca..7957c7ab6ae9 100644 --- a/test/jdk/java/net/httpclient/BufferingSubscriberTest.java +++ b/test/jdk/java/net/httpclient/BufferingSubscriberTest.java @@ -55,7 +55,7 @@ * @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 114ebcd18a58..b42c2c4613e8 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 dcb60a55061b..f21d13d5e987 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 48f23ebf370f..000602d3c0c3 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 33df36100ad7..5b4d2bff1c2c 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 5449a68418ad..d1ead0abad65 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 @@ * @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 6604fadea204..d08fd027bb5f 100644 --- a/test/jdk/java/net/httpclient/CancelledResponse2.java +++ b/test/jdk/java/net/httpclient/CancelledResponse2.java @@ -66,7 +66,7 @@ * @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 53c85b8e3839..e1f48e1251b5 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 0745e2af934d..22ba26c3ac84 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 e1f4aee1d51d..d91c73f97a18 100644 --- a/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java +++ b/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java @@ -33,7 +33,7 @@ * @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 eb571b2d16c2..fac007df8adf 100644 --- a/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java +++ b/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java @@ -33,7 +33,7 @@ * @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 01c166dcb1b3..c90ba1ffdf38 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 62e62680e034..74faf8ec8011 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 c8d22419852f..58acfc4feac8 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 b26952710356..ef5d0a305523 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 8d81e5cbe695..a5d16e65993c 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 @@ * @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 fcfbb393e5ae..571e124ca5d6 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 e045f4e22f10..42d2b509c1b5 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 6df4ccac9fb1..6fbffab95ea9 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 @@ * @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 ecf043f58c83..25dfaf71fc02 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 1beb31f74e54..12a852262a6e 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 @@ * @library /test/jdk/java/net/httpclient/lib * /test/lib * - * @run junit DurationOverflowTest + * @run junit ${test.main.class} */ /* @@ -81,19 +81,19 @@ * * @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 81bbbf3ca5be..4da5592fb85a 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 19b0a1d651b5..3c8483a4c6dd 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 6ef71b7d22de..406f82501b1c 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 a46ea66f3aec..d12a9f3e5d7a 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 e9ae894f3e19..656a887002f7 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 56fa363870ab..0233ffb069c5 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 292f770fc30c..dafb6e593b22 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 7fd3061aa3c8..31dd6d560de1 100644 --- a/test/jdk/java/net/httpclient/FlowAdapterPublisherTest.java +++ b/test/jdk/java/net/httpclient/FlowAdapterPublisherTest.java @@ -64,7 +64,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 -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 32003023d7fe..e85a752940cd 100644 --- a/test/jdk/java/net/httpclient/FlowAdapterSubscriberTest.java +++ b/test/jdk/java/net/httpclient/FlowAdapterSubscriberTest.java @@ -74,7 +74,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 -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 f2011766b2b2..0a6824d289d3 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 1cbb24d81ce8..8e34f100524d 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 e07dfacbd852..e9e23753ed30 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 @@ /** * @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 3a52cd101b87..c0bef2405209 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 00a709a33873..b082f59dd238 100644 --- a/test/jdk/java/net/httpclient/HeadersLowerCaseTest.java +++ b/test/jdk/java/net/httpclient/HeadersLowerCaseTest.java @@ -60,7 +60,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 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 26733c1c9280..220978b419cb 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 f51ccf9fd384..23bcc541a18d 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 @@ * @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 4cfee56e8555..7a220c77fdae 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 a5fb1a39e66f..7e5db68b8d34 100644 --- a/test/jdk/java/net/httpclient/HttpClientBuilderTest.java +++ b/test/jdk/java/net/httpclient/HttpClientBuilderTest.java @@ -62,7 +62,7 @@ * @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 0a3fc03424a1..aa1f399ba309 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 dff7219c0c8b..dc9f34868bd3 100644 --- a/test/jdk/java/net/httpclient/HttpClientExceptionTest.java +++ b/test/jdk/java/net/httpclient/HttpClientExceptionTest.java @@ -41,7 +41,7 @@ * @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 f1e8aecbaa45..a98f180d0823 100644 --- a/test/jdk/java/net/httpclient/HttpClientLocalAddrTest.java +++ b/test/jdk/java/net/httpclient/HttpClientLocalAddrTest.java @@ -65,7 +65,7 @@ * -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 1f7377f745da..08f725b0c524 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 @@ * @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 f4a1f3cca82c..27562ea22771 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 @@ * @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 8532146c1e2e..36057a025dbb 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 80e49f207056..9ea477574022 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 @@ * @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 77a800b7cf28..fbddcf3e4be5 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 99897a69a8c4..395cb50d0583 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 2eb7899e1f0b..1e04f592f31e 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 @@ /* * @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 2bf90bbe02ce..d611a82967b2 100644 --- a/test/jdk/java/net/httpclient/HttpRedirectTest.java +++ b/test/jdk/java/net/httpclient/HttpRedirectTest.java @@ -76,7 +76,7 @@ * @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 10784f7dbeeb..c12dd91e104d 100644 --- a/test/jdk/java/net/httpclient/HttpRequestBodyPublishers/OfByteArraysTest.java +++ b/test/jdk/java/net/httpclient/HttpRequestBodyPublishers/OfByteArraysTest.java @@ -52,10 +52,10 @@ * 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 19afbfbd99b1..1558711d741a 100644 --- a/test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java +++ b/test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java @@ -58,7 +58,7 @@ * @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 29c4bcc80727..034144841a1a 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 3b955b8feb7a..95f554b64e6d 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 633c68777161..f7f9b38b7fc4 100644 --- a/test/jdk/java/net/httpclient/HttpResponseInputStreamTest.java +++ b/test/jdk/java/net/httpclient/HttpResponseInputStreamTest.java @@ -45,7 +45,7 @@ * @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 450fce35f545..c3471c7ccc01 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 f62f6fa49780..2e56ef232c65 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 @@ * -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 f047e2902e86..17fed7255901 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 c83abd9cf623..f127b552d2a0 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 @@ * -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 bb0afacaacb9..86e09bcd6696 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 @@ * 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 103284c9d544..474b5866f762 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 be7e1db00339..8eaba1d4aa04 100644 --- a/test/jdk/java/net/httpclient/IdleConnectionTimeoutTest.java +++ b/test/jdk/java/net/httpclient/IdleConnectionTimeoutTest.java @@ -70,27 +70,27 @@ * 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 e42e2e21a6e3..a47c57a92308 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 e8d2e5166bb4..2ce2234132b5 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 9b5c7961c2f7..a7c9deddac72 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 @@ * 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 0dcd2ca02c22..7605b6270387 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 @@ * @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 c83d9d675283..83c09b356ed8 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 bbbd1e486ca0..418c55364b53 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 692e4d0bea4c..929148430440 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 ff3981e8b3d9..59cdad27cbc8 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 @@ * -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 7a1bca73d13f..e510f44c9e48 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 @@ * @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 727cc1768dfa..f41a40f29608 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 @@ * -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 ddca2e1f7d27..d18c3b170ee3 100644 --- a/test/jdk/java/net/httpclient/LineBodyHandlerTest.java +++ b/test/jdk/java/net/httpclient/LineBodyHandlerTest.java @@ -82,7 +82,7 @@ * @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 01a7ee9fdbf1..4dead4472952 100644 --- a/test/jdk/java/net/httpclient/LineStreamsAndSurrogatesTest.java +++ b/test/jdk/java/net/httpclient/LineStreamsAndSurrogatesTest.java @@ -49,7 +49,7 @@ * 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 7932744a4db2..fc51b1f7a4d8 100644 --- a/test/jdk/java/net/httpclient/LineSubscribersAndSurrogatesTest.java +++ b/test/jdk/java/net/httpclient/LineSubscribersAndSurrogatesTest.java @@ -54,7 +54,7 @@ * 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 3609aa8337a4..e8bcfb76b1bc 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 09fdc18f6879..5718e6958f74 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 f1c4f8810580..b0f7ffdd4cb0 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 00875aceb6f9..b3fc38e11f31 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 b0a5130e2b69..ab6ed2e5f944 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 c434591c894f..bdf18ee72383 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 980f4d8d1004..6fc4cf02e072 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 7020f7e2c253..ab9b38222630 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 9e7ceb11c55d..c59bc5e9b086 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 2e53479a6eea..2bde0c8bd9a5 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 58310ecd9adc..838f8f36df2c 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 @@ * @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 92d359e32c6c..93f1b36dfd1b 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 53b8607f294f..b0977efe69eb 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 da0c7220b6bc..665bf280aca2 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 cd7049285f1f..91a59019355a 100644 --- a/test/jdk/java/net/httpclient/PlainProxyConnectionTest.java +++ b/test/jdk/java/net/httpclient/PlainProxyConnectionTest.java @@ -62,7 +62,7 @@ * /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 84b29449d67b..92f1360d1e26 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 6d9d7e4f11bc..e02cbef658bf 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 a147e8944d22..630042899344 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 bb339e91bdc3..3920906d03a7 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 d8abea188bd1..45000f54f455 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 @@ * @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 73e27f6efff4..545d049d0d5d 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 8c2fa8707aee..eac97e4f73e1 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 void handle(HttpTestExchange exchange) throws IOException { } } } -} \ 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 ad94b124132d..d9ebf9e1faf1 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 e87cbc694c78..0c65a81c3ed5 100644 --- a/test/jdk/java/net/httpclient/RequestBodyTest.java +++ b/test/jdk/java/net/httpclient/RequestBodyTest.java @@ -62,7 +62,7 @@ * @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 12af908457b7..6ba00fcd10fa 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 9b54f852510b..d7e975fa7dc8 100644 --- a/test/jdk/java/net/httpclient/Response1xxTest.java +++ b/test/jdk/java/net/httpclient/Response1xxTest.java @@ -63,7 +63,7 @@ * @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 e68be645ff9f..5ee880655b1e 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 835f7aa65f76..517f6b0c5c62 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 19393d99ee98..562176b596a3 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 be135e84b31e..b436e6e6b182 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 f2ddf85b3f51..108ecb6259ae 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 67969306accd..a943b92aeea4 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 8638693b50dc..b90f9bb68098 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 cf94d1b50f77..e6c234fb9e83 100644 --- a/test/jdk/java/net/httpclient/SSLExceptionTest.java +++ b/test/jdk/java/net/httpclient/SSLExceptionTest.java @@ -37,7 +37,7 @@ * 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 2998522616fc..600a4a1f295d 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 d5e762b15a40..715a7b9f4a36 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 ffebdeec5ce0..274a129c320f 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 @@ * @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 47be508c8c1a..f5393fe940b2 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 60d2796b34fe..5a88455fc547 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 e48667d2c69a..0fdc7b2acc31 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 76117ef3075b..8ca08b9b65d1 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 @@ * @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 f87cc462fac7..487e6cbe21a4 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 d4d5f2a85e2d..4e022c5b273c 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 abc972fd591a..4e0c6b2ba6c3 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 @@ * @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 7b228e69de2a..49e03a54c597 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 93f55d066e92..1902abb4a268 100644 --- a/test/jdk/java/net/httpclient/SubscriberAPIExceptions.java +++ b/test/jdk/java/net/httpclient/SubscriberAPIExceptions.java @@ -49,7 +49,7 @@ * @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 2aba794426f0..28a1bab5a690 100644 --- a/test/jdk/java/net/httpclient/TestKitTest.java +++ b/test/jdk/java/net/httpclient/TestKitTest.java @@ -41,7 +41,7 @@ /* * @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 2c1aa2fd9b48..43d3bebf2e43 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 ba7341854647..e0ff3e2e42a5 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 a5e819942b44..023a2281bcee 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 e68f83052bde..54ddbebdd821 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 62d06fd60191..d690a2bbb3b6 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 f863f3598edf..c8255ba5fffc 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 ce1ad89dc056..400e28e17fcc 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 eee2f9ab7fb7..e14ced23514d 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 797507ac7ada..a70f8f1b3f3a 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 309f60c0f22f..04fd641f66a6 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 77c87151e194..59cae941d6d3 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 69deeec533a9..f346829fe19b 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 de38cf4f7826..7180784c553e 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 ec4d682d73ff..ea56f30e11fc 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 92f2ab3726dd..aeaec438ec48 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 a4c0fc72004b..77d1992e948d 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 aec4641917cd..68df5a2b8b32 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 603a8558856a..1a9ffe9c182e 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 e45c6d6487e6..31b807beea09 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 ba594166b725..9915b921b1ff 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 a76ff8824630..4fd41b987d09 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 ba5506750964..4fe15f994485 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 304d98e69392..879f0fad5a31 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 296e9151c9ee..9481d64e195d 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 cae1cda7ade6..ba986bbc0d20 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 @@ * @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 a39242c871ad..ebe8cb3324ef 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 @@ /** * @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 093885a6ba0a..9a09b5acf90c 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 @@ * -Djdk.httpclient.disableRetryConnect * -Djdk.httpclient.redirects.retrylimit=0 * -Dtest.requestTimeoutMillis=1000 - * TimeoutResponseBodyTest + * ${test.main.class} */ /* @@ -79,7 +79,7 @@ * -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 ab562f8eab8d..6ea2da4c21ea 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 @@ * -Djdk.httpclient.disableRetryConnect * -Djdk.httpclient.redirects.retrylimit=0 * -Dtest.requestTimeoutMillis=1000 - * TimeoutResponseHeaderTest + * ${test.main.class} */ /* @@ -76,7 +76,7 @@ * -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 95cb501d24ce..052b20f94eb3 100644 --- a/test/jdk/java/net/httpclient/TlsContextTest.java +++ b/test/jdk/java/net/httpclient/TlsContextTest.java @@ -63,7 +63,7 @@ * -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 1c72bac6cc96..931b96815599 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 6c7fabb7f00b..4b92eb83fdd3 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 @@ * @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 6062fcd9448f..3f5f004738a1 100644 --- a/test/jdk/java/net/httpclient/UserAuthWithAuthenticator.java +++ b/test/jdk/java/net/httpclient/UserAuthWithAuthenticator.java @@ -74,7 +74,7 @@ * @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 f49f44c157cf..664565f6bd7f 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 ff864202a9a0..546c0933ec58 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 a842ea579303..fe62cc9e77fb 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 0da1b238f607..fab27463d903 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 @@ * @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 3bb800311789..01ff090cba7a 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 8eed173409b5..8febbb8a12a7 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 ddcf707e8759..b76179f2e719 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 1b9396effbb6..36c46ed3aba9 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 360eabaee2b6..9396ccd169f0 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 @@ * 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 c72beb04d564..cd788db6c7dd 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 0f3bafa571d9..3e3ce97b5829 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 d788d39b4413..883e14e7d58d 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 08c32171d164..f656d72f2443 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 @@ * @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 7adfd57319ca..552e91473d50 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 @@ * 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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 907afc28fa68..71eb483793f5 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 @@ * 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 5bcaf95c6fc2..c273415ca631 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 2459c8eba4ba..a67d2cd250cf 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 84e86b556caa..132d69360396 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 void handle(Http2TestExchange exchange) throws IOException { 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 762a70b95fd8..75b48cb251b0 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 @@ * 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 2d5b5dd4f4ec..5d0bfe844f47 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 201b56513f60..b5b1ca2f1d58 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 d38b867132ba..41200bf89497 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 9cf2a3f7ae23..c77e258f3c52 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 5df3174f820f..1bc7e0974c79 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 e4009219bcaa..698a8c59ebe3 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 @@ * @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 42a51f56fab8..c2f0dfdd5a1e 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 @@ * @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 9ea331d2d842..bff009131a8a 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 @@ private void pushPromise(Http2TestExchange exchange) throws IOException { 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 3cea2d92570b..53d9dbe3c2b8 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 @@ * 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 fdfc498b21e0..2c38a4a47f44 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 d406ee491cb2..584acb9ef496 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 @@ * @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 800a02eb2c42..fd0bdb3c2941 100644 --- a/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java +++ b/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java @@ -79,7 +79,7 @@ * @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 fff11f4ceb48..adc4c4c7240e 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 bddb9879ae9c..982aa88b3bcb 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 4392f8292584..e15a6bbfc4d7 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 129566044849..21ab06f8a5c9 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 8a83b51a1740..51c30ccfe959 100644 --- a/test/jdk/java/net/httpclient/http3/H3DataLimitsTest.java +++ b/test/jdk/java/net/httpclient/http3/H3DataLimitsTest.java @@ -70,7 +70,7 @@ * @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 8e20eac95fa0..07e086f06764 100644 --- a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java +++ b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java @@ -84,7 +84,7 @@ * @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 b9d50ce29398..03d1f8b4ea47 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 @@ * @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 d5864989436e..d4cf941b007a 100644 --- a/test/jdk/java/net/httpclient/http3/H3HeaderSizeLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/H3HeaderSizeLimitTest.java @@ -58,7 +58,7 @@ * @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 6b7b24f049db..142856596e64 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 570f84ad6209..d9746d496f37 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 6eabc23677a2..35e5e56bc161 100644 --- a/test/jdk/java/net/httpclient/http3/H3InsertionsLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/H3InsertionsLimitTest.java @@ -67,7 +67,7 @@ * -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 85a4b6113f01..a69028ca7011 100644 --- a/test/jdk/java/net/httpclient/http3/H3LogHandshakeErrors.java +++ b/test/jdk/java/net/httpclient/http3/H3LogHandshakeErrors.java @@ -63,7 +63,7 @@ * 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 a93c6a375947..33d8c1db9945 100644 --- a/test/jdk/java/net/httpclient/http3/H3MaxInitialTimeoutTest.java +++ b/test/jdk/java/net/httpclient/http3/H3MaxInitialTimeoutTest.java @@ -75,15 +75,15 @@ * @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 0d107486fcde..548bd546dab9 100644 --- a/test/jdk/java/net/httpclient/http3/H3MemoryHandlingTest.java +++ b/test/jdk/java/net/httpclient/http3/H3MemoryHandlingTest.java @@ -67,7 +67,7 @@ * -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 f9ba35359bc0..c38671e65b84 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 58deeec1982e..fbb4e07fd60b 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 @@ * 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 b9e15b7d8e5a..969297a50bae 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 6086c26729b0..b66744d9f0d4 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 @@ * @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 7ea24d81ded4..b982528b5e3b 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 @@ * 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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 67a7d99fa717..4f6c80dc3a23 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 50aa817b1554..c53828b189dc 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 b34e2a1567e6..955023599d3c 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 00fe651c9cfc..018e7c2f11d5 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 @@ * /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 a863db43c29d..ecc3c828abf2 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 ae113322cd3f..4d58f7094b19 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 0294f2f69daa..6444f2ca90c9 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 4258f3bac73e..78a1b55fda69 100644 --- a/test/jdk/java/net/httpclient/http3/H3SimpleTest.java +++ b/test/jdk/java/net/httpclient/http3/H3SimpleTest.java @@ -54,22 +54,22 @@ * @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 86b12a1dae6e..3eb88c88f9ec 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 1ac4a750d77b..aa14087862b1 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 fedb4d46952f..befc8e5d1592 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 @@ * @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 790af245db8d..2a490884927d 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 @@ * @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 8eaad2ce4de5..ad5db51f48b5 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 @@ * @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 b43ce8dcf79b..fcd5b1eadb72 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 1cf6900ed5d9..0d34c197d1a3 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 fc6d43bb4726..7404a3cb1e97 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 1f109e27ebca..c783da4a10b2 100644 --- a/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java +++ b/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java @@ -85,7 +85,7 @@ * @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 8c9a6f84b65d..e13568740bbe 100644 --- a/test/jdk/java/net/httpclient/http3/StopSendingTest.java +++ b/test/jdk/java/net/httpclient/http3/StopSendingTest.java @@ -61,7 +61,7 @@ * 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 9e15db9ceb92..6505a542e8c3 100644 --- a/test/jdk/java/net/httpclient/http3/StreamLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/StreamLimitTest.java @@ -65,7 +65,7 @@ * @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 f36a457022e2..754a4233f3f0 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 778783ad64c7..afa61c0e5828 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 @@ * 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 e231d0dded37..ea945b76f83c 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 275dec34927c..539eb47dc539 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 1ad094916d4c..372554e824f5 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 15d4bef7cc93..799ea13d45fb 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 @@ * 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 c314688ab52e..0a93a2ed5948 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 @@ * @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 c340a25088a5..d87532329e50 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 c2bed98bc3c3..99680608db80 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 @@ * 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 7dc1bf739609..9b277c87c3cd 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 @@ * 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 5c31762cdb30..3a816f4203e5 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 fd1fc41d8f79..cbfe4c15cc82 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 @@ * 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 b721fa3d27ae..3612e027b793 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 @@ * 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 76d15d0ace99..b5b2348b7aba 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 b6fac8291f84..12b1ca60bb45 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 ac156e2b547e..0005c96df886 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 @@ * 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 eea9b31e9327..fcee35df53ee 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 7c94abf15046..56d26db31e4c 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 @@ * 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 1a175342c6b5..10b5b58b0e41 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 5d0129234f36..24a2195cdbd2 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 @@ * 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 7fbc00f91482..97da68c10311 100644 --- a/test/jdk/java/net/httpclient/quic/AckElicitingTest.java +++ b/test/jdk/java/net/httpclient/quic/AckElicitingTest.java @@ -89,8 +89,8 @@ * @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 3c8c027e73b3..513266285212 100644 --- a/test/jdk/java/net/httpclient/quic/AckFrameTest.java +++ b/test/jdk/java/net/httpclient/quic/AckFrameTest.java @@ -46,7 +46,7 @@ * @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 8d03f4265b38..d73178a88eca 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 @@ * @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 100a6112de54..dc2c4a986c34 100644 --- a/test/jdk/java/net/httpclient/quic/BuffersReaderVLTest.java +++ b/test/jdk/java/net/httpclient/quic/BuffersReaderVLTest.java @@ -39,7 +39,7 @@ * @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 96aeace08982..a54662f4f87e 100644 --- a/test/jdk/java/net/httpclient/quic/ConnectionIDSTest.java +++ b/test/jdk/java/net/httpclient/quic/ConnectionIDSTest.java @@ -35,7 +35,7 @@ /* * @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 422d71ca9646..6a87d859170d 100644 --- a/test/jdk/java/net/httpclient/quic/CryptoWriterQueueTest.java +++ b/test/jdk/java/net/httpclient/quic/CryptoWriterQueueTest.java @@ -34,7 +34,7 @@ * @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 f4b08e6d9b7e..711be0700fa7 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 @@ /* * @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 eaec0bc8b951..23b667d3953a 100644 --- a/test/jdk/java/net/httpclient/quic/KeyUpdateTest.java +++ b/test/jdk/java/net/httpclient/quic/KeyUpdateTest.java @@ -83,7 +83,7 @@ * @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 a1fafba8760d..f5f742d92266 100644 --- a/test/jdk/java/net/httpclient/quic/OrderedFlowTest.java +++ b/test/jdk/java/net/httpclient/quic/OrderedFlowTest.java @@ -50,11 +50,11 @@ * @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 aebbbce34d31..a624817bd4e1 100644 --- a/test/jdk/java/net/httpclient/quic/PacerTest.java +++ b/test/jdk/java/net/httpclient/quic/PacerTest.java @@ -40,7 +40,7 @@ /* * @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 a96904c84102..fa43baa853f4 100644 --- a/test/jdk/java/net/httpclient/quic/PacketEncodingTest.java +++ b/test/jdk/java/net/httpclient/quic/PacketEncodingTest.java @@ -80,17 +80,17 @@ * @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 a597c826e730..9ecb3444060e 100644 --- a/test/jdk/java/net/httpclient/quic/PacketLossTest.java +++ b/test/jdk/java/net/httpclient/quic/PacketLossTest.java @@ -63,7 +63,7 @@ * -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 c018079ea4ea..7c19e8b414ed 100644 --- a/test/jdk/java/net/httpclient/quic/PacketNumbersTest.java +++ b/test/jdk/java/net/httpclient/quic/PacketNumbersTest.java @@ -37,7 +37,7 @@ /* * @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 fe3b748a2faf..0a363e104ae1 100644 --- a/test/jdk/java/net/httpclient/quic/PacketSpaceManagerTest.java +++ b/test/jdk/java/net/httpclient/quic/PacketSpaceManagerTest.java @@ -94,14 +94,14 @@ * @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 ef0801e6c186..d6eeda32cada 100644 --- a/test/jdk/java/net/httpclient/quic/QuicFramesDecoderTest.java +++ b/test/jdk/java/net/httpclient/quic/QuicFramesDecoderTest.java @@ -37,7 +37,7 @@ * @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 2393ac7df12d..d70b5ac8443f 100644 --- a/test/jdk/java/net/httpclient/quic/QuicRequestResponseTest.java +++ b/test/jdk/java/net/httpclient/quic/QuicRequestResponseTest.java @@ -55,7 +55,7 @@ * 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 9f7852740b4f..bed76c9b0a25 100644 --- a/test/jdk/java/net/httpclient/quic/StatelessResetReceiptTest.java +++ b/test/jdk/java/net/httpclient/quic/StatelessResetReceiptTest.java @@ -71,7 +71,7 @@ * @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 6d805fbad5ad..f5dbb8f159c4 100644 --- a/test/jdk/java/net/httpclient/quic/VariableLengthTest.java +++ b/test/jdk/java/net/httpclient/quic/VariableLengthTest.java @@ -38,7 +38,7 @@ * @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 6b40bf84a8ec..bee9bfc7d2c8 100644 --- a/test/jdk/java/net/httpclient/quic/VersionNegotiationTest.java +++ b/test/jdk/java/net/httpclient/quic/VersionNegotiationTest.java @@ -59,7 +59,7 @@ * 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 d80e473696a1..bb69e3778601 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 @@ * 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 0b7e6875b963..5a10136470ba 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 @@ * @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 5767d81cc831..1fd37e32eaa1 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 @@ * 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 933d258f9122..f5c882a074db 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 @@ * 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 285fa2e4cd4c..6205c8f3c7b4 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 @@ * 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 361b053fe434..d703907c2eb7 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 c8d7bb64b363..ab03ee08d641 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 1d0502c9ce30..23f7aebf9fc7 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 @@ * @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 2e3644617932..0916022e89ac 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 @@ * @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 a6088f8cce27..6a388878db25 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 b438cb8e7280..a590790c29ad 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 1865ca05e4fd..191fd4bcb37c 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 30569fa80d74..0633fe9c20fa 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 6854cacbcc20..344e6fbc086f 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 4a5ae315e919..67d53eafd31b 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 a8330faeb3f4..f634fe8bd458 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 e07ebe0d03af..1f5263368f1c 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 eae01f804a42..ab7f3b0be874 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 32640853b009..2c631c798e02 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 f4d6c84c2f5e..33b0ade39e3c 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 76f124308041..a35f27f4b16f 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 a2a41a73d7ba..80c72297e43c 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 b3a433b5c298..124d15e1cc02 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 f28d84b2f201..cf77c66e7c77 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 beef8cb42a4c..a5b5f73077cc 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 0d532669a10d..dc28c5a33c2b 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 56474555235d..e0096a552976 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 a410aa9fe75b..d3aa4d968664 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 2b1df3d7e87c..4d395d9195e2 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 c8e4faa1ad37..7e9e296aa9d7 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 b9e5f2d58fe6..e4c3aeffac3e 100644 --- a/test/jdk/java/net/httpclient/whitebox/AltSvcFrameTest.java +++ b/test/jdk/java/net/httpclient/whitebox/AltSvcFrameTest.java @@ -89,7 +89,7 @@ * -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 682082ba9f85..7e7b2ba6bf37 100644 --- a/test/jdk/java/net/httpclient/whitebox/AltSvcRegistryTest.java +++ b/test/jdk/java/net/httpclient/whitebox/AltSvcRegistryTest.java @@ -80,7 +80,7 @@ * -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 05/90] 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 bf096897aa70..a87c0ab33fa1 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 d78fd331b56c..1cecdc0cb336 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 06/90] 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 8546e6e2d640..e12a8c284de0 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 07/90] 8381819: Test compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java fails after JDK-8364584 Reviewed-by: kvn, mbaesken --- src/hotspot/cpu/x86/vm_version_x86.cpp | 12 ++++++------ src/hotspot/share/runtime/abstract_vm_version.hpp | 2 +- .../cpuflags/TestAESIntrinsicsOnSupportedConfig.java | 1 - .../TestAESIntrinsicsOnUnsupportedConfig.java | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index d8f998520d12..39a9c618350e 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1207,22 +1207,22 @@ void VM_Version::get_processor_features() { } } } else { - if (!UseAES) { + if (!cpu_supports_aes()) { if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { - warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled."); + warning("AES intrinsics are not available on this CPU"); } 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."); + warning("AES-CTR intrinsics are not available on this CPU"); } FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); - } else if (!cpu_supports_aes()) { + } else if (!UseAES) { if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { - warning("AES intrinsics are not available on this CPU"); + 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 are not available on this CPU"); + 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 61a8aa840801..794fa4dabcf0 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 421307e85cad..b3aa0283fa5f 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 50677f5197e6..7fc6d7f86c1e 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java +++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java @@ -81,7 +81,7 @@ private void testUseAESIntrinsics() throws Throwable { /** * 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 08/90] 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 3223ff9dccd4..0280f7c33bb4 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 @@ private void endRead() { 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 000000000000..3fe915734eb8 --- /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 09/90] 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 a0fb3525381e..19768a8dc175 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java +++ b/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java @@ -123,12 +123,10 @@ public void testAArch64Flags() throws Throwable { 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 10/90] 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 6a1686b80e23..1c6904e74462 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 2a0256cc3163..c0b4918102ed 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 349cc652bf41..6384cb397b8f 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 a302df418d76..815c0c7b4b0a 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 0e4e211453b4..cf7744cfe03c 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 20d61b542b08..2b8d6a72be4e 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 983ac8a32c66..6974d50741e5 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 b5c19d8aa36a..ac1ddec7cbc5 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 000000000000..643cf3a8bbb2 --- /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 000000000000..dbefa3dc788c --- /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 000000000000..730a47d238aa --- /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 000000000000..d61cac791e1e --- /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 442b68e596a9..b83389a19290 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 1cbaaf0f52d5..c1638a27fd7c 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 static void main(String[] args) { // 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 cf993237a32e..e0a45e4cba6e 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 @@ private void test() { 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 @@ private void test() { } catch (VirtualMachineError e) { // Expected } + constraints.check(); // Free code cache space for (Long blob : blobs) { WHITE_BOX.freeCodeBlob(blob); @@ -143,4 +166,31 @@ private long getHeapSize() { 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 a5068b474542..e54fad3517e0 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 void run() throws Throwable { 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 void run() throws Throwable { 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 e7c68e71ab30..aa7e9e67f373 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 void run(CodeCacheCLITestCase.Description testCaseDescription, 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 4d52f470645d..b5ae98bc79f7 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 @@ 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 f1f18956f059..12a1a0c42cd2 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 eca5c70e0917..0f5af1c0a935 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 @@ * 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 enum CommonDescriptions { * 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 enum CommonDescriptions { * 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 enum CommonDescriptions { * 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 enum CommonDescriptions { * 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 f5243aaa4935..b8e386f4f7de 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 CodeCacheOptions(long reserved) { this.nonNmethods = 0; this.nonProfiled = 0; this.profiled = 0; + this.hot = 0; this.segmented = false; } @@ -70,6 +76,17 @@ public CodeCacheOptions(long reserved, long nonNmethods, long nonProfiled, 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 long sizeForHeap(BlobType heap) { 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 String[] prepareOptions(String... additionalOptions) { 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 String[] prepareOptions(String... additionalOptions) { 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 c0d826e59ec6..2e994336f54b 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 @@ 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 @@ private TestPrintCodeCacheOption() { .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 @@ private TestPrintCodeCacheOption() { .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 5bc10071b4dd..c669a7ece7db 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 d379296d5613..462d03ddcdfa 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 873b04944245..704236a3a850 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 a2343c236946..ad12a828fef3 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 b482cd4e5593..f04cd695f4f3 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 b91b7fa228d3..83215bce8ade 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 b808a6619041..ecd9db3a6c4a 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 07a5ec94c877..98959f284a07 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 a71a01a555c3..5c1624eeb187 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 6f3402848f85..cffe5cc87747 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 1dae00b0035a..7dd70bd0d04c 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 cb3f2c903643..a49a27a4d200 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 1c13c89884bc..0d75beb78da6 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 26d3556d10e8..d1d2da8523be 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 000000000000..dd02de668811 --- /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 000000000000..4a7f9d2cc21e --- /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 3d9cd083204c..12c9d6c40fa7 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java @@ -50,6 +50,12 @@ * @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 a2290acc7b61..e2d57f79484d 100644 --- a/test/lib/jdk/test/whitebox/code/BlobType.java +++ b/test/lib/jdk/test/whitebox/code/BlobType.java @@ -46,8 +46,16 @@ public boolean allowTypeWhenOverflow(BlobType type) { || 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 boolean allowTypeWhenOverflow(BlobType type) { } }, // 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 static EnumSet getAvailable() { // 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 11/90] 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 09ceb0a79b78..f3f30f15b2bd 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 @@ 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; + 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); } - 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); - } - } - } - - 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 12/90] 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 469cc488f16c..76695fc8dde9 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 d8a8719778df..7a17d150f40b 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 13/90] 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 d3888d1b7eb2..6594d94fa917 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 14/90] 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 000000000000..d3f63784ecec --- /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 15/90] 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 | 170 ++++++++------- .../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 | 42 +++- .../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, 748 insertions(+), 353 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 ed8de631dc35..da02e0dab394 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 62dbc84f88c4..cc03f3fc8326 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) \ - 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 + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser * Method: init0 * Signature: ()V */ extern "C" -JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_init0 +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/amd64/DwarfParser"); + 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("sun/jvm/hotspot/debugger/amd64/AMD64ThreadContext"); + 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 - 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); + + DWARF_REGLIST + +#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 caf948019af7..214e2f21ac6e 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 459e3cc57e9f..28eb92a285f2 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 0a38c9a0f2e8..2bfdba65a78f 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 000000000000..5a95e9405e16 --- /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 000000000000..8226bc0864c7 --- /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 a69496e77a4d..c584131e2852 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 029aac1f107b..815902045cff 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 62b1b4d0d6b4..d5aa74e73ad7 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 6298f569aaf8..c500360f39db 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; } -// 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) { +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); - // 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); + 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); - } else { + } + + 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; + + // Check vDSO binary first (for referring debuginfo if possible). + 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 fdaa30c3f5d0..9cbde7319f01 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 c8f3fb2ed4cf..8f8ce28be1e7 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 bc366ef02b5a..86f9e990af8f 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 000000000000..7baa399ea75e --- /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 53351c918d37..3e8099cf75b2 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 boolean isBPOffsetAvailable() { 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 15f6615421cc..57ba419aa9dc 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 @@ public CFrame topFrameForThread(ThreadProxy thread) throws DebuggerException { 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 a53b8a0a2824..c09af9881dd7 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 @@ 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 9a75511e44d3..856981bb73c3 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 Address findLibPtrByAddress(Address pc) { @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 5f76e6308e9f..c55aca2155c0 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); - // override base class impl to avoid ELF parsing - public ClosestSymbol closestSymbolToPC() { - // try native lookup in debugger. - return dbg.lookup(dbg.getAddressValue(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); } - public Address pc() { - return pc; + public static LinuxAARCH64CFrame getTopFrame(LinuxDebugger linuxDbg, ThreadContext context) { + return getFrameFromReg(linuxDbg, context::getRegisterAsAddress); } - public Address localVariableBase() { - return fp; + 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); } - @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) { + this(linuxDbg, sp, fp, cfa, pc, null, dwarf, false); } - @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, DwarfParser dwarf, boolean use1ByteBeforeToLookup) { + this(linuxDbg, sp, fp, cfa, pc, null, dwarf, use1ByteBeforeToLookup); + } - // Check alignment of fp - if (dbg.getAddressValue(fp) % (2 * ADDRESS_SIZE) != 0) { - 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); + } } } - if (nextFP == null) { - nextFP = fp.getAddressAt(0 * ADDRESS_SIZE); - } - if (nextFP == null) { - return null; - } + this.lr = lr; + } - if (nextPC == null) { - nextPC = fp.getAddressAt(1 * ADDRESS_SIZE); + 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 (nextPC == null) { - return null; + + 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 (nextSP == null) { + senderFP = getSenderFP(senderFP); + + if (senderSP == null) { CodeCache cc = VM.getVM().getCodeCache(); CodeBlob currentBlob = cc.findBlobUnsafe(pc()); @@ -99,29 +135,62 @@ public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address 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 77003168671d..422ca001624a 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 @@ 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 void setRegisterAsAddress(int index, Address value) { 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 4d3d9d5998d1..e58e2facdd7c 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 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); - } - - public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, ThreadContext context) { - return getFrameFromReg(dbg, 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 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; - } - - // 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; + : new LinuxAMD64CFrame(linuxDbg, rsp, rbp, cfa, rip, dwarf); } - public Address pc() { - return rip; + public static LinuxAMD64CFrame getTopFrame(LinuxDebugger linuxDbg, ThreadContext context) { + return getFrameFromReg(linuxDbg, context::getRegisterAsAddress); } - public Address localVariableBase() { - return (dwarf != null && dwarf.isBPOffsetAvailable()) - ? cfa.addOffsetTo(dwarf.getBasePointerOffsetFromCFA()) - : rbp; + private LinuxAMD64CFrame(LinuxDebugger linuxDbg, Address rsp, Address rbp, Address cfa, Address rip, DwarfParser dwarf) { + this(linuxDbg, rsp, rbp, cfa, rip, dwarf, false); } - 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 LinuxAMD64CFrame(LinuxDebugger linuxDbg, Address rsp, Address rbp, Address cfa, Address rip, DwarfParser dwarf, boolean use1ByteBeforeToLookup) { + super(linuxDbg, rsp, rbp, cfa, rip, dwarf, use1ByteBeforeToLookup); } - 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 CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { } } - 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 1ebf6c21a70b..a3880bc9f0e7 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java @@ -38,7 +38,7 @@ * @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 @@ * @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 @@ * @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 16/90] 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 bf0bf55ff98a..0206d2a51549 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 byte[] getExtra() { } /** - * 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 4ea4a103feff..d79b0a1bd9c2 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 @@ *

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 @@ private void ensureOpen() throws IOException { 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 ZipOutputStream(OutputStream out) { } /** - * 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 ZipOutputStream(OutputStream out, Charset charset) { } /** - * 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 000000000000..5879ae1497a2 --- /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 17/90] 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 5744bbc2f032..78a533d62c02 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 18/90] 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 | 153 +++++++++--------- .../PrinterJob/PageDialogCancelTest.java | 9 +- .../PrinterJob/PageDialogFormatTest.java | 63 ++++++++ 3 files changed, 144 insertions(+), 81 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 8d016d8b39f7..b18fa5a7e2ce 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; + AwtDialog::CheckUninstallModalHook(); + AwtDialog::ModalActivateNextWindow(NULL, target, peer); - /* 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); - } + 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); + AwtPrintControl::setPrintDC(env, self, newDC); } + ::GlobalUnlock(setup.hDevNames); + } - /* Get the Windows paper and margins description. - */ - retrievePaperInfo(&setup, &paperSize, &margins, &orientation, - AwtPrintControl::getPrintDC(env, self)); + /* 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; - } + /* 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); } - doIt = JNI_TRUE; + ::GlobalUnlock(setup.hDevMode); } - AwtDialog::CheckUninstallModalHook(); - - AwtDialog::ModalActivateNextWindow(NULL, target, peer); - 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 f9ce1b7c196a..fc3d251cb6c8 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 static void main(String[] args) throws Exception { } } } - 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 000000000000..b727ba12928d --- /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 19/90] 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 581884664a5f..13b5d0081139 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 20/90] 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 1c93c37698a5..7a8e6c6f4f19 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.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 boolean participatesInPreview(Symtab syms, ModuleSymbol m) { /** * 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 void checkSourceLevel(DiagnosticPosition pos, Feature feature) { 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 55f2f76e3583..d8b5b1ddd6be 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 @@ protected void checkSourceLevel(int pos, Feature feature) { 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 Token readToken() { // 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 df5da5cb954d..b4dfb04766cb 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 @@ protected Name ident(boolean allowClass, boolean asVariable) { } } 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 @@ boolean isInvalidUnqualifiedMethodIdentifier(int pos, Name name) { if (allowYieldStatement) { return true; } else { - log.warning(pos, Warnings.InvalidYield); + log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.InvalidYield); } } return false; @@ -3858,35 +3858,35 @@ Source restrictedTypeNameStartingAtSource(Name name, int pos, boolean shouldWarn 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 JCTree.JCCompilationUnit parseCompilationUnit() { 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 JCTree.JCCompilationUnit parseCompilationUnit() { 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 @@ protected void checkSourceLevel(int pos, Feature feature) { 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 809c19d5012e..11fa3a5aebf0 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 @@ void showDiagnostics(boolean showAll) { //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 ce3e56f2f3f0..b8b2a3af2546 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 void warning(int pos, Warning warningKey) { 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 000000000000..b611e7a8655b --- /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 21/90] 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 1d79c4d0488a..225e70740761 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 22/90] 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 6594d94fa917..79211e75db43 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 23/90] 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 ec63e7aa57f6..000000000000 --- 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 0a0c137ed071..000000000000 --- 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 8c6e8cb6503a..000000000000 --- 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 dc5a777d7b1a..57da12dee489 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 b5b8aa4ef554..c7fadeaea9ba 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 1a0251a2c2ac..10dec73e9fa8 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 @@ class ModuleEntry : public CHeapObj { // 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 @@ class ModuleEntry : public CHeapObj { 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 3e61f2e3a3e2..3eb50fcb5a7b 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 7b174a922878..e064e53b2633 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 @@ class PackageEntry : public CHeapObj { 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 0239eadf6929..0926b55b9a30 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 b6ba69d6f632..ac42dd13c6c9 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 @@ class MetaspaceClosure { // 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 @@ class MetaspaceClosure { }; //-------------------------------- - // 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 @@ class MetaspaceClosure { // 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 @@ class MetaspaceClosure { // 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 @@ class MetaspaceClosure { // 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 @@ class MetaspaceClosure { 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 6a1cb0b04142..9cc0813a1f64 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 e300bea6993f..14b54cfc4ea3 100644 --- a/src/hotspot/share/utilities/growableArray.hpp +++ b/src/hotspot/share/utilities/growableArray.hpp @@ -116,12 +116,6 @@ class GrowableArrayView : public GrowableArrayBase { ~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 @@ class GrowableArrayView : public GrowableArrayBase { } tty->print("}\n"); } + + // MetaspaceClosure support + E** data_addr() { + return &_data; + } }; template @@ -821,6 +820,8 @@ class GrowableArray : public GrowableArrayWithAllocator> { 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 c98b38b8c3c5..091767cc273a 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 24/90] 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 225e70740761..2d40ee1822ab 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 25/90] 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 df80009d3153..1a539f4d37bd 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 @@ import java.io.*; import java.lang.reflect.*; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -114,7 +115,7 @@ private static void runCase ( String caseName, 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 @@ public void runIteration() { } /**************************************************************************/ -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 9ecadf22f08c..962474e0d016 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 @@ import java.io.*; import java.lang.reflect.*; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -100,7 +101,7 @@ private void runCase ( String caseName, 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 @@ public void runIteration() { } /**************************************************************************/ -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 15e7aa1c63a9..60ca7cea8371 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 @@ import java.io.*; import java.lang.reflect.*; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -98,7 +99,7 @@ private void runCase ( String caseName, 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 @@ public void runIteration() { } /**************************************************************************/ -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 87a0de5d31d5..db5ddf45a7cd 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.jvmti.ArgumentHandler; import nsk.share.jvmti.DebugeeClass; +import jdk.test.lib.thread.ThreadWrapper; public class bi04t002 extends DebugeeClass { @@ -118,7 +119,7 @@ String methodName(int idx) { } } -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 0707f38b4dd3..2aa37d5d4cee 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 nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class tc04t001 extends DebugeeClass { @@ -92,7 +93,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 9f92bf5423ea..c37f0649067b 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 nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class em02t001 extends DebugeeClass { @@ -65,7 +66,7 @@ public int runIt(String argv[], PrintStream out) { 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 void generateEvents() { } // 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 a23732dc554c..0914b0129f21 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 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 int runIt(String args[], PrintStream out) { } Class loadedClass; - Thread thrd; + ThreadWrapper thrd; ClassUnloader unloader = new ClassUnloader(); for (int i = 0; i < 3; i++) { @@ -90,7 +92,7 @@ public int runIt(String args[], PrintStream out) { 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 int runIt(String args[], PrintStream out) { 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 32150e99ed6f..8b11a8cd9618 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 ee340084946e..89bd00f5f831 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 7e30300c41b9..a5a7e4298fe2 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 nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class em02t008 extends DebugeeClass { @@ -55,7 +56,7 @@ public int runIt(String args[], PrintStream out) { 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 int runIt(String args[], PrintStream out) { return status; } - class em02t008a extends Thread{ + class em02t008a extends ThreadWrapper { em02t008a() { setName("em02t008a"); @@ -90,7 +91,7 @@ public void run() { } } - 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 3fa8e0767295..11a7efd6bd84 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 nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class em05t001 extends DebugeeClass { @@ -95,7 +96,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ // 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 011f03e8cc01..378d770dd06b 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 nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class em05t002 extends DebugeeClass { @@ -98,7 +99,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ // 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 dcaca552073b..852549276ece 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 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 int runIt(String args[], PrintStream out) { 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 int runIt(String args[], PrintStream out) { 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 int runIt(String args[], PrintStream out) { 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 3f03fd955680..dc3abe492965 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 21fc0a0e1582..b3c1c25833c4 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 @@ import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -115,7 +116,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 368ed04a01e7..e654dde6db09 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 @@ import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -115,7 +116,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 2d554fd73ecc..f08d07f2c17f 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 @@ import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -115,7 +116,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 f43609ab0421..121cb4a0aac8 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 @@ import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -98,7 +99,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 afee53a23311..31bba4a409ac 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 @@ import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -98,7 +99,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 985685770327..a27521dcbd98 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 @@ import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -98,7 +99,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 f19805e9d1a6..270fd7751a48 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 @@ import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -95,7 +96,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 b421cf3c185d..9fca9678d0a2 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 @@ import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -95,7 +96,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 29d7aca69357..09ba44a5c32d 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 @@ import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -150,7 +151,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 a34f3f6c109e..c38fb07fb69b 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 @@ import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -150,7 +151,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 9f7d6e2f5c83..09fef278ca5d 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 404ab78ff551..5874a1e11fc2 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 771dfeeb054b..2c5dfcf070c5 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 6ebbc04b5c15..409a3f6ffcca 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 2f6e2b15db75..2cb0f1bc6839 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 nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class hs201t001 extends DebugeeClass { @@ -74,7 +75,7 @@ public int runIt(String args[], PrintStream out) { 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 int runIt(String args[], PrintStream out) { 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 c76a9b005d10..69d243d49b14 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 nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class hs201t002 extends DebugeeClass { @@ -74,7 +75,8 @@ public int runIt(String args[], PrintStream out) { 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 int runIt(String args[], PrintStream out) { // 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 int runIt(String args[], PrintStream out) { 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 f33afd148e80..fc0680f88ebe 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 @@ import java.io.*; import java.util.*; + +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -187,7 +189,7 @@ private static byte[] loadFromClassFile(String signature) { /** * 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 ecb702f18733..b94ed1f8faa3 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 c386a88dc12f..788d41144981 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 boolean agentMethod(){ 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 9fbccbbcfab0..7fc9dcf161a9 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 45ec4af6249f..c5e8fd6eb462 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 e78702cc5874..dd2951955439 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 boolean agentMethod() { 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 32a7a085a13f..1af54872316e 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 c5646af40246..109ea8ec9184 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 abbe82214448..e42bede4e011 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 boolean agentMethod() { 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 4ddbfc43c794..c5792c9789da 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 94eee8ebe07e..787da2529d6d 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 d9dd4a88c80f..f62bd49f674e 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 boolean agentMethod() { 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 cce4bd7326ea..185bb0bd5e17 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 dd07c191f38d..7942e7652998 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 348dc8b5ee4c..6c4a018e0b78 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 boolean agentMethod() { 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 boolean agentMethod() { 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 e60b3da5c4bc..105f90e360c4 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 8cf6750917aa..84eea67fe4aa 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 f9f1aa8a2706..c8b1f09bf1eb 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 boolean agentMethod() { 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 7276b8cc5fda..f63dcc4577e5 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 c502e1248141..5a220345c2d4 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 0556e5dd45e2..2fb796f1f569 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 7e9ba68c85de..51f8af209950 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 b0f716794dcd..6607f76899c4 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 boolean agentMethod() { 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 boolean agentMethod() { 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 be2bc2295383..b685015a2e3d 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 e06eceeb4254..08cd7d22d565 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 boolean agentMethod() { 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 boolean agentMethod() { 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 87751c5960ff..7aab6551203c 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 nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class ma03t001 extends DebugeeClass { @@ -79,7 +80,7 @@ public int runIt(String argv[], PrintStream out) { /* =================================================================== */ -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 7686e68952e6..4c9d9bc65a4a 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 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 static int run(String argv[], PrintStream out) { 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 int runIt(String argv[], PrintStream out) { 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 int runIt(String argv[], PrintStream out) { /* =================================================================== */ // 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 40db16504b64..93a4e05b1356 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 162f8fa84c6a..d92b1ef6b15d 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 @@ private static void compile(String name, String[] args) { 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 2f46ed873402..95b7a117b2c4 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 000000000000..ab850bf5a4ab --- /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 26/90] 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 a7c5398171b6..ae20418942d8 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 000000000000..5fcf93625a12 --- /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 27/90] 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 79211e75db43..a3dd3d2bfd05 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 c4ebe2717676..5b773a986f19 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -236,9 +236,10 @@ class AOTStubData : public StackObj { // 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 @@ class AOTStubData : public StackObj { ~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 0bc71c654718..f5509b9d9964 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 28/90] 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 45ba2740ea5b..a12f48c08774 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 d6551cffb73a..1a47cb756f42 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 @@ class ShenandoahGenerationalHeuristics : public ShenandoahAdaptiveHeuristics { 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 @@ class ShenandoahGenerationalHeuristics : public ShenandoahAdaptiveHeuristics { // 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 71fd6e376148..a81efa99d709 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 9c5baaedcd60..c140f445e210 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 c53d0a155544..0b89c59634ac 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp @@ -63,7 +63,7 @@ class ShenandoahAgeCensusTest : public ::testing::Test { 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 29/90] 8382022: jpackage: enhance CompositeProxy Reviewed-by: almatvee --- .../internal/util/CompositeProxy.java | 711 +++++++----- .../internal/util/CompositeProxyTest.java | 1028 ++++++++++++++++- .../tools/jdk/jpackage/test/JUnitUtils.java | 14 + 3 files changed, 1434 insertions(+), 319 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 39a9d319468b..e4257c87306c 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.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 @@ * } * }; * - * 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 static final class Builder { * 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 Builder invokeTunnel(InvokeTunnel v) { 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 static T create(Class interfaceType, Object... slices) { 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) { + + Objects.requireNonNull(interfaceType); + Objects.requireNonNull(methodConflictResolver); + Objects.requireNonNull(objectConflictResolver); + Stream.of(slices).forEach(Objects::requireNonNull); + + if (!interfaceType.isInterface()) { + throw new IllegalArgumentException(String.format("Type %s must be an interface", interfaceType.getName())); + } - validateTypeIsInterface(interfaceType); + final var uniqueSlices = Stream.of(slices).map(IdentityWrapper::new).collect(toSet()); - final var interfaces = interfaceType.getInterfaces(); - List.of(interfaces).forEach(CompositeProxy::validateTypeIsInterface); + final var unreferencedSlicesBuilder = SetBuilder.>build().emptyAllowed(true); - if (interfaces.length != slices.length) { - throw new IllegalArgumentException( - String.format("type %s must extend %d interfaces", interfaceType.getName(), slices.length)); + if (!allowUnreferencedSlices) { + unreferencedSlicesBuilder.add(uniqueSlices); } - final Map, Object> interfaceDispatch = createInterfaceDispatch(interfaces, slices); - 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; - } - }).filter(Objects::nonNull).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + return Map.entry(method, uniqueSlices.stream().flatMap(slice -> { + var sliceMethods = getImplementerMethods(slice.value()).filter(sliceMethod -> { + return signatureEquals(sliceMethod, method); + }).toList(); - @SuppressWarnings("unchecked") - T proxy = (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class[] { interfaceType }, - new CompositeProxyInvocationHandler(methodDispatch)); + if (sliceMethods.size() > 1) { + throw new AssertionError(); + } - return proxy; - } + 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)); + } - private record InterfaceDispatchBuilder(Set> interfaces, Collection slices) { + var candidateIdentity = IdentityWrapper.wrapIdentity(candidate); - InterfaceDispatchBuilder { - Objects.requireNonNull(interfaces); - Objects.requireNonNull(slices); + if (candidates.stream().map(IdentityWrapper::new).noneMatch(Predicate.isEqual(candidateIdentity))) { + throw new UnsupportedOperationException(); + } - if (interfaces.isEmpty()) { - throw new IllegalArgumentException("No interfaces to dispatch"); + sliceWithMethods = slicesWithMethods.stream().filter(v -> { + return candidateIdentity.equals(v.getKey()); + }).findFirst().orElseThrow(); + } } - if (slices.isEmpty()) { - throw createInterfaceNotImplementedException(interfaces); + 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); } - } - - 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); + return Optional.ofNullable(handler).map(h -> { + return Map.entry(method, h); + }).stream(); - if (!Collections.disjoint(dispatch.keySet(), unservedInterfaces)) { - throw new IllegalArgumentException(); - } + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); - if (!Collections.disjoint(toIdentitySet(dispatch.values()), toIdentitySet(unusedSlices))) { - throw new IllegalArgumentException(); - } + if (!allowUnreferencedSlices) { + var unreferencedSlices = unreferencedSlicesBuilder.create().stream().map(IdentityWrapper::value).toList(); + if (!unreferencedSlices.isEmpty()) { + throw new IllegalArgumentException(String.format("Unreferenced slices: %s", unreferencedSlices)); } } - private static Collection> toIdentitySet(Collection v) { - return v.stream().map(IdentityWrapper::new).collect(toSet()); - } - } + @SuppressWarnings("unchecked") + T proxy = (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class[] { interfaceType }, + new CompositeProxyInvocationHandler(Collections.unmodifiableMap(methodDispatch))); - private static Map, Object> createInterfaceDispatch(Class[] interfaces, Object[] slices) { + return proxy; + } - if (interfaces.length == 0) { - return Collections.emptyMap(); - } + private static Stream> unfoldInterface(Class interfaceType) { + return Stream.concat( + Stream.of(interfaceType), + Stream.of(interfaceType.getInterfaces() + ).flatMap(CompositeProxy::unfoldInterface)); + } - 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)); - } - } + private static List> getSuperclasses(Class type) { + List> superclasses = new ArrayList<>(); - 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; - } - } + var current = type.getSuperclass(); - builder = new InterfaceDispatchBuilder(result); + while (current != null) { + superclasses.add(current); + current = current.getSuperclass(); } - 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)); + return superclasses; } - private static Stream> unfoldInterface(Class interfaceType) { - return Stream.concat(Stream.of(interfaceType), - Stream.of(interfaceType.getInterfaces()).flatMap(CompositeProxy::unfoldInterface)); + 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 IllegalArgumentException createInterfaceNotImplementedException( - Collection> missingInterfaces) { - return new IllegalArgumentException(String.format("none of the slices implement %s", missingInterfaces)); + private static Stream getProxyableMethods(Class interfaceType) { + return removeRedundancy(getUnfilteredProxyableMethods(interfaceType)); } - private static void validateTypeIsInterface(Class type) { - if (!type.isInterface()) { - throw new IllegalArgumentException(String.format("type %s must be an interface", type.getName())); - } + private static Stream getUnfilteredImplementerMethods(Object slice) { + var sliceType = slice.getClass(); + + 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()); + }); } - private static Handler createHandler(Class interfaceType, Method method, Map, Object> interfaceDispatch, - BinaryOperator conflictResolver, InvokeTunnel invokeTunnel) { + private static Stream getImplementerMethods(Object slice) { + var sliceType = slice.getClass(); - final var methodDeclaringClass = method.getDeclaringClass(); + 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(); - if (!methodDeclaringClass.equals(interfaceType)) { - // The method is declared in one of the superinterfaces. - final var slice = interfaceDispatch.get(methodDeclaringClass); + var proxyableMethodSignatures = proxyableMethods.stream() + .map(FullMethodSignature::new) + .collect(toSet()); - 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; - } - } + var methods = getUnfilteredImplementerMethods(slice).filter(method -> { + return !proxyableMethodSignatures.contains(new FullMethodSignature(method)); + }); - private static Stream getProxyableMethods(Class interfaceType) { - return Stream.of(interfaceType.getMethods()).filter(method -> !Modifier.isStatic(method.getModifiers())); + return removeRedundancy(Stream.concat(methods, proxyableMethods.stream())); } - private static boolean isInvokeDefault(Method method, Object slice) { - if (!method.isDefault()) { - return false; - } - - // 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. - - final var sliceClass = 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)); - - return !methodOverriden; + 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 @@ private static String objectToString(Object obj) { 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); - } - } - - static class ObjectMethodHandler extends HandlerOfMethod { + private record ObjectMethodHandler(Method method) implements Handler { - ObjectMethodHandler(Method method) { - super(method); + ObjectMethodHandler { + Objects.requireNonNull(method); } @Override @@ -546,43 +631,47 @@ public Object invoke(Object proxy, Object[] args) throws Throwable { } } - 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 @@ private interface Handler { 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()); } } - 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; + /** + * 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); + } + }); + } + + 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 1ece83be0a62..b8b1325529de 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 @@ static String saySomething() { } @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 String sayHello() { 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 String sayThings() { } @Test - public void testInherited() { + void testInherited() { interface Base { String doSome(); } @@ -193,7 +224,7 @@ public String doSome() { } @Test - public void testNestedProxy() { + void testNestedProxy() { interface AddM { String m(); } @@ -231,7 +262,7 @@ public String n() { } @Test - public void testComposite() { + void testComposite() { interface A { String sayHello(); String sayBye(); @@ -262,65 +293,942 @@ public String sayBye() { assertEquals("ciao,bye", proxy.talk()); } + @Test + void testBasicObjectMethods() { + interface Foo { + } + + var proxy = CompositeProxy.create(Foo.class); + var proxy2 = CompositeProxy.create(Foo.class); + + assertNotEquals(proxy.toString(), proxy2.toString()); + assertNotEquals(proxy.hashCode(), proxy2.hashCode()); + assertFalse(proxy.equals(proxy2)); + assertFalse(proxy2.equals(proxy)); + assertTrue(proxy.equals(proxy)); + assertTrue(proxy2.equals(proxy2)); + } + + @Test + 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}) - public void testBasicObjectMethods(boolean withOverrides) { + void testAutoMethodConflictResolver8(boolean override) { + interface A { - default void foo() {} + String getString(); } - interface B { - default void bar() {} + interface B extends A { + default String getString() { + return "B"; + } } - interface C extends A, 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"; + } } - final A aImpl; - final B bImpl; + interface AB extends A, B { + String getString(); + } - if (withOverrides) { - aImpl = new A() { + if (override) { + var foo = new B() { @Override - public String toString() { - return "theA"; + 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 boolean equals(Object other) { - return true; + 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 int hashCode() { - return 7; + 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(); } }; + }; - bImpl = new B() { - @Override - public String toString() { - return "theB"; + 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 { - aImpl = new A() {}; - bImpl = new B() {}; + 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()); } + } - var proxy = CompositeProxy.create(C.class, aImpl, bImpl); - var proxy2 = CompositeProxy.create(C.class, aImpl, bImpl); + @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 { - assertNotEquals(proxy.toString(), proxy2.toString()); - assertNotEquals(proxy.hashCode(), proxy2.hashCode()); - assertFalse(proxy.equals(proxy2)); - assertFalse(proxy2.equals(proxy)); - assertTrue(proxy.equals(proxy)); - assertTrue(proxy2.equals(proxy2)); + 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 - public void testJavadocExample() { + void testJavadocExample() { interface Sailboat { default void trimSails() {} } @@ -364,9 +1272,9 @@ public void trimJib() { } }; - 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 530a0d5cb1f2..97041ea1a0e4 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 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 ExceptionPattern hasCause() { } + 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 30/90] 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 5137adc1c080..5e4fa4ed2eff 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 @@ private Constructor getConstructor(Class clazz) { 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 @@ private Class nextProviderClass() { 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 000000000000..209dce752673 --- /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 68e4aea0ab29..85095cc55373 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 void testBadAnnotationProcessor(Path base) throws Exception { .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 void testWrongClassFileVersion(Path base) throws Exception { .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 31/90] 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 7af81fabe139..2af784fd034b 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 @@ 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 static void main(String[] args) throws Exception { } testOld("-Xlog:gc", + "-XX:ConcGCThreads=1", + "-XX:ParallelGCThreads=1", "-Xms96m", "-Xmx96m", "-XX:+UnlockDiagnosticVMOptions", @@ -108,6 +114,8 @@ public static void main(String[] args) throws Exception { ); 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 32/90] 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 6f61d431707e..5a48ff473842 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 static void main(String[] args) throws Exception { 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 33/90] 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 f3569941321d..78ae70629b60 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 @@ * 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 @@ private void finishInit() { 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 5bff127f143e..851201fe347a 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 static void done(GlyphLayout gl) { } 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 34/90] 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 88f1ed22e35d..f436bd32e1b9 100644 --- a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java +++ b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java @@ -148,8 +148,17 @@ private void releaseStarted(Set ids) { } 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 @@ private void releaseTerminated(Integer id) { } } - 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 35/90] 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 | 591 +- .../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, 741 insertions(+), 14326 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 66fcd90e2e84..17d56ff11ba7 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 @@ protected void generateOtherFiles(ClassTree classTree) 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 @@ private void copyLegalFiles(boolean includeJQuery, boolean includeHighlightJs) t 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 a3fba7eca142..50e6207b833b 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 30318bbaeeab..cde5b287e25c 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.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 @@ private void addSearch(Content target) { .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 433a641530df..5fa0daacf987 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 @@ protected void addSearchFileContents(Content contentTree) { .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 @@ private Content createModuleSelector() { .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 cda4bc9a5be4..bff32cbd7bf9 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 @@ private Comment getGeneratedBy(boolean timestamp, ZonedDateTime buildDate) { } 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 @@ private void addScripts(HtmlTree head) { .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 9b59cb0cb475..2b154db7de76 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 1a86433c2230..000000000000 --- 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 @@ void checkSearchOutput(String fileName, boolean expectedOutput) { 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 @@ void checkInvalidUsageIndexTag() { "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 @@ void checkSearchJS() { "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 @@ void checkCssClasses(String jsFile, String cssFile) { // 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 012e9ce00ded..a2c2a6032126 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 void test(Path base) { 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 71908f34e996..bd8d0cf79531 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 @@ protected void error(String msg) { "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 @@ protected void error(String msg) { "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 @@ protected void error(String msg) { !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 36/90] 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 80b17efb998e..60a61b6bb4e8 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 000000000000..7138f22beec7 --- /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 37/90] 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 ff011dca8892..5c84b929ef13 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 38/90] 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 ab9cd8be19bc..423654cd50ad 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 7782735be25c..ff10828731ec 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 39/90] 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 7fa2e8086ad4..7bec0a3c0caf 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 994fbe3c80fe..dfba2dcff461 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -499,29 +499,20 @@ class MacroAssembler: public Assembler { 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 40/90] 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 e50e1ff537bc..0e5ff69fe6c9 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 41/90] 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 a2b7970f9f69..0e32c602d953 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 a51a6aea468e..4cc55e7ae23b 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 @@ class MacroAssembler: public Assembler { } 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 42/90] 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 444530c72664..89ae68e85bad 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 void visitModifiers(JCModifiers tree) { 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 d35351b6f408..5031a74bc5ae 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 b91d65828b97..6e2b9cb93b0e 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 4bdd791909c2..427c1fef3a86 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 ade5333a446f..2ae736ad315d 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 43/90] 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 | 66 +++++++------ .../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, 263 insertions(+), 268 deletions(-) diff --git a/test/jdk/java/net/DatagramSocket/ConnectPortZero.java b/test/jdk/java/net/DatagramSocket/ConnectPortZero.java index 7f61d146bc04..342dae4c02b2 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.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 } - }; - } - - @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))); + 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) + ); } - @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 6fecf8dc7323..6e5cd9442973 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 4d979f9dc8de..a8d35a64dc87 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(); - } - - @DataProvider(name = "data") - public Object[][] variants() { - return new Object[][]{ - { datagramSocket }, - { datagramSocketAdaptor }, - { multicastSocket }, - }; - } - - @Test(dataProvider = "data") - public void testSetNegTimeout(DatagramSocket ds) { - assertThrows(IAE, () -> ds.setSoTimeout(-1)); + 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()); } - @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)); + @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 testGetTimeout(DatagramSocket ds) throws Exception { - ds.setSoTimeout(10); - assertEquals(10, ds.getSoTimeout()); + @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)); + } } - @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 7f8eea874ecf..1d3c39ffd711 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.net.*; -import java.io.*; - -import static org.testng.Assert.assertEquals; +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 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 void testOldImplConnectTwoArgs() { 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 482eadb3cf9d..5cefb0fd0e69 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.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 @@ * 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 static Packet of(DatagramPacket packet) { 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 static Packet of(DatagramPacket packet) { } } - @DataProvider(name = "packets") - Object[][] providerIO() throws IOException { + static List providerIO() throws IOException { loopbackAddr = InetAddress.getLoopbackAddress(); wildcardAddr = new InetSocketAddress(0).getAddress(); @@ -124,44 +121,46 @@ Object[][] providerIO() throws IOException { 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 03c78c3e54d7..149424232eef 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 void setUp() throws IOException { 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 Object[][] variants() { }; } - @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 36eae0b5c321..d85817337f43 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.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 interface DatagramSocketSupplier { } 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 Object[][] invariants() { }; } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("testCases") public void testSendReceiveMaxSize(String name, int capacity, DatagramSocketSupplier supplier, Class exception) throws IOException { @@ -177,7 +176,7 @@ public void testSendReceiveMaxSize(String name, int capacity, 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 void testSendReceiveMaxSize(String name, int capacity, 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 67c890cd2e24..96fa4d68d2e9 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 interface DatagramSocketSupplier { } 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 Object[][] invariants() { }; } - @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 0f6f9af4c60b..07ae4bfad595 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.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 interface DatagramSocketSupplier { } 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 Object[][] invariants() { }; } - @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 9ad381be73c3..0186e3e4d46f 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 44/90] 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 fe286793ae74..2709e6b30087 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 b5cb9167d928..3a47453819e6 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -1275,7 +1275,7 @@ class G1CollectedHeap : public CollectedHeap { 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 cb857dc6eabd..2b0e6ce9cf4f 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 45/90] 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 7f535fa0c23c..c3cc3eddc687 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 5c4f8f66b3da..6704a2908364 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 @@ static long zdtToMillis(ZonedDateTime zdt) { 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 Object[][] testData() { {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 void test1(long creationInstant, // if -1, then current time is used 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 void test1(long creationInstant, // if -1, then current time is used 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 void test1(long creationInstant, // if -1, then current time is used : 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 void test1(long creationInstant, // if -1, then current time is used 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 a44eef9c3f55..9a490ce18e7d 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 void beforeTest() throws Exception { .toURL(); } - @AfterTest - public void afterTest() { + @AfterAll + public static void afterTest() { if (server != null) server.stop(0); } @@ -77,9 +83,9 @@ public void afterTest() { * - 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 void testRequestPropertiesOrder() throws Exception { 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 void testRequestPropertiesOrder() throws Exception { * * @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 void testServerSideRequestHeadersOrder() throws Exception { 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 @@ private int testRequestHeadersOrder(HttpExchange exchange) { } 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 a6f2fbc1ae68..be922608c80e 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.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.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 void afterTest() { * - 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 void test() throws Exception { .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 2be9772ed29c..bdda7821bf84 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.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 void setup() throws Exception { .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 void run() { 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 void test1xx() throws Exception { 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 void test101CausesRequestFailure() throws Exception { 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 69b6c588af8e..6a0173ac692b 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.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 void noEntry() throws Exception { 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 void withEntry() throws Exception { 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 void manifestNoEntry() throws Exception { 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 void manifestWithEntry() throws Exception { 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 void manifestNoEntryAttr() throws Exception { 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 void manifestWithEntryAttr() throws Exception { 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 e8698dddf6b0..47e32b39a4b3 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.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 void test() throws Exception { Package pForFoo = loader1.getDefinedPackage("p"); Package pForBar = loader2.getDefinedPackage("p"); - assertEquals(pForFoo.getName(), pForBar.getName()); - assertTrue(pForFoo != pForBar); - - try { - loader2.defineSplitPackage("p"); - } catch (IllegalArgumentException e) { + assertEquals(pForBar.getName(), pForFoo.getName()); + assertNotSame(pForBar, pForFoo); - } + 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 d052f1aeaf21..84206d89868b 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.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 @@ private Object[][] urls() { 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 @@ private Object[][] urls() { * 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 void testSetRequestPropertyNullPointerException(final String url) throws * 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 void testAddRequestPropertyNullPointerException(final String url) throws * 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 void testGetRequestPropertyReturnsNull(final String url) throws Exception 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 void testSetRequestPropertyIllegalStateException() throws Exception { 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 void testAddRequestPropertyIllegalStateException() throws Exception { 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 void testGetRequestPropertyIllegalStateException() throws Exception { 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 73c822ac2c98..224e5217d33e 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 @@ void checkFile() throws IOException { 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 6f16c79f5204..5f680a04283a 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.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 void testRequestPropertiesOrder() throws Exception { 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 b01be15a4469..c49720545ed8 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 static enum ParameterType { 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 Object[][] getDecodeParameters() { * @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 void testIllegalArgument(ParameterType type) throws Exception { * * @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 f1b4f3ce3e9d..f992fb4e8eed 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 static enum ParameterType { 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 Object[][] getDecodeParameters() { * @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 06dd21b71ea0..9dce36dbb279 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 Object[][] badUrls() { }; } - @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 Object[][] goodUrls() { }; } - @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 37179f5dfe2a..ae49353df0f9 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 void testIllegalArgException() throws Exception { // 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 9fe4eff4150c..ed01791acdd2 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.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 46/90] 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 9aebb27238c5..9c8187c7a46c 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 @@ 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 47/90] 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 426ba4e76509..969c9ca60c1d 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 5d72a9f85dc7..d8b740e1a66e 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 ca7b6dfc0f11..6e168153947e 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 @@ * @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 @@ private static void testJavaDynamic() throws Throwable { 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 48/90] 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 1c6904e74462..d372e72fc23d 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 49/90] 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 e84acd622843..3f85fd16b614 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 7d3d4ec16f4f..a93e2e43a29a 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 6974d50741e5..dacc8ce9c261 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 ead1b78cdea9..5d170f919c8c 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 1465da02ac80..49897ca3c176 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 b2b01079379e..eb4f506d14f1 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 5241ae6cd2b3..e4c548fc744e 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -503,6 +503,66 @@ class SafePointNode : public MultiNode { 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 @@ class CallNode : public SafePointNode { // 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 @@ class CallNode : public SafePointNode { // 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 b760a179b57b..1cd6c52393b0 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 d92904923374..3c1a68d62245 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 7b5f78a8ad33..db3cbd4109cb 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 eb6be669f241..ff0085d79dea 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 @@ class Compile : public Phase { 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 @@ class Compile : public Phase { _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 @@ class Compile : public Phase { // 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 64ee60037d65..a05ad0ef99a3 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 4a1553b1e009..e3d3108a22e7 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 8d32694e9a51..bbd00d111f73 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 273009ca7ce7..f53f73d09784 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 e0f95377cde6..26417436ed99 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 9b87df645e19..9aae48302cf0 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 60a61b6bb4e8..b65f90093ab7 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 6963a67118fd..35a9108892cc 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 6667c71511c6..26b822593279 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 @@ class IdealLoopTree : public ResourceObj { 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 @@ class IdealLoopTree : public ResourceObj { // 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 @@ class IdealLoopTree : public ResourceObj { 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 @@ class PhaseIdealLoop : public PhaseTransform { 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 @@ class PhaseIdealLoop : public PhaseTransform { // 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 01c671878834..8c5dbe7fb481 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 9ec3402c7016..c7fe45084730 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 cb5795a12509..3eafd97d7c18 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 46b89aa2c5fd..36855d659bac 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 @@ class Node { // 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 @@ class Node { 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 @@ class Node { 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 42f44f0f7ea8..5118019fc313 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 683633f6355b..6a400631bffb 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 5603033ce69d..3f1866990e2c 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 6700df6ec177..5bd3c34f15f1 100644 --- a/src/hotspot/share/opto/phase.hpp +++ b/src/hotspot/share/opto/phase.hpp @@ -85,6 +85,9 @@ class Phase : public StackObj { 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 ce432fbfc01d..2b599ace03ae 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 000000000000..b45b340ab85a --- /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 000000000000..ba435c8484f2 --- /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 88bdb99dfd60..df46ffe6ca6a 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 @@ protected Object clone() throws CloneNotSupportedException { * {@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 000000000000..4289794b2781 --- /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 000000000000..db8590865fb5 --- /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 000000000000..d0bce0246966 --- /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 000000000000..7f4142c18d3b --- /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 1e3ba7c314e1..43178f411852 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 0e1accf8a502..3f742a0ce627 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 50/90] 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 2aaf0a2fac6f..0bb15ef3efe6 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 @@ public Object clone() throws CloneNotSupportedException { 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 c1cb5ed6a308..50afba7cab88 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 @@ int keyArrayLength() { 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 @@ void getY(int i, byte[] arr, int pos) { 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 @@ void getPath(int i, byte[] arr, int pos) { 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 @@ static class LMOTSParams { // 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 @@ static class LMOTSParams { 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 @@ private LMOTSParams( 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 @@ private void addCksm(byte[] S) { 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 @@ byte[] lmotsPubKeyCandidate( 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 @@ byte[] lmotsPubKeyCandidate( 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 e966e6b77f8d..7d8c2840de95 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 @@ void implDigest(byte[] out, int ofs) { } + @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 a096cac5f504..0578645c1cd5 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 @@ private SHA3(String name, int digestLength, byte suffix, int c) { 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 @@ void finishAbsorb() { * 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 @@ void implDigest(byte[] out, int ofs) { 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 @@ void implDigest(byte[] out, int ofs) { 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 942a91d61b84..e9dabdc5b06f 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 static ObjectIdentifier hashAlgFromHSS(PublicKey publicKey) // 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 8056855cc1ac..48019d4e4655 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 @@ record TestCase( 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 @@ record TestCase( // 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 @@ record TestCase( ), // 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 @@ record TestCase( ), // 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 @@ record TestCase( ), // 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 @@ record TestCase( ), // 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 @@ record TestCase( """) ), - // Test Case #7 + // Test Case #8 // LMSigParameters.lms_sha256_m32_h20, LMOtsParameters.sha256_n32_w8 new TestCase( null, // exception @@ -821,7 +902,7 @@ record TestCase( """) ), - // Test Case #8 + // Test Case #9 // LMSigParameters.lms_sha256_m32_h15, LMOtsParameters.sha256_n32_w4 new TestCase( null, // exception @@ -957,7 +1038,7 @@ record TestCase( """) ), - // Test Case #9 + // Test Case #10 // LMSigParameters.lms_sha256_m32_h20, LMOtsParameters.sha256_n32_w4 new TestCase( null, // exception @@ -1098,7 +1179,7 @@ record TestCase( """) ), - // 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 @@ record TestCase( """) ), - // 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 @@ record TestCase( """) ), - // 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 @@ record TestCase( """) ), - // 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 @@ record TestCase( """) ), - // Test Case #14 + // Test Case #15 // LMS signature length is incorrect new TestCase( new SignatureException(), @@ -2119,7 +2200,7 @@ record TestCase( """) ), - // Test Case #15 + // Test Case #16 // HSS signature and public key have different tree heights new TestCase( new SignatureException(), @@ -2232,7 +2313,7 @@ record TestCase( """) ), - // Test Case #16 + // Test Case #17 // bad signature new TestCase( null, // exception @@ -2345,7 +2426,7 @@ record TestCase( """) ), - // Test Case #17 + // Test Case #18 // Invalid key in HSS signature new TestCase( new SignatureException(), @@ -2458,7 +2539,7 @@ record TestCase( """) ), - // Test Case #18 + // Test Case #19 // LMS signature is too short new TestCase( new SignatureException(), @@ -2485,7 +2566,7 @@ record TestCase( 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 51/90] 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 | 164 +++++++++--------- .../protocol/http/TestTransparentNTLM.java | 40 ++--- .../jar/MultiReleaseJarURLConnection.java | 96 +++++----- test/jdk/sun/net/www/protocol/jrt/Basic.java | 34 ++-- 11 files changed, 233 insertions(+), 235 deletions(-) diff --git a/test/jdk/sun/net/ext/ExtendedSocketOptionsTest.java b/test/jdk/sun/net/ext/ExtendedSocketOptionsTest.java index d42d780db9d8..af9345953b8a 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.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 @@ * 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 void testConcurrentClassLoad() throws Exception { // 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 5fdff96f5f21..d070d843fee8 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 void testIllegalArgForNull() { @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 void testIllegalArgForNoHost() throws Exception { @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 903e805f5f4f..6928173df672 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 void reverseMessageHeadersTest() throws Exception { 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 void ntlmNegotiateTest () throws Exception { 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 5f66aff365e6..bf7553acf621 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 b4bc638099db..d927e0a8029c 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 290248989d85..364bafd07498 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.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 void testHttpClient() throws Exception { // 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 0e3f9e86c4eb..b6d8790bb5b5 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 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 void doTest() throws MalformedURLException { } } - @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 void setup() throws Throwable { .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 245cd49d518f..ad3b3fa3722d 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 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 Object[][] responses() { "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 Object[][] responses() { 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 Object[][] responses() { "HTTP/1.0 404 Not Found\r\n" + "header-without-colon\r\n\r\n" + - "SOMEBODY", - - }; - Arrays.stream(bad).forEach(responses::add); + "SOMEBODY" - 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 @@ static final String mixedCRLF(String headers) { 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 void verifyHeaders(String respString) throws Exception { 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 void verifyHeaders(String respString) throws Exception { 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" + + "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" + - "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", + "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" + - "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" + + "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" + - "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" + + "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" + - " : 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" + + "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" + - " \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" + + " : no header\r\n" + // all blank header-name (not fold) + "Content-Length: 65\r\n\r\n" + + "XXXXX", - }; - Arrays.stream(bad).forEach(responses::add); + "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"); - 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 @@ void assertHeadersEqual(Map> expected, 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 0df834765c8e..1c2262ba8e2e 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.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 void testNTLM() throws IOException { 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 @@ static void readRequestHeaders(InputStream is) throws IOException { } } - @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 void setup() throws Exception { .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 f113e7d3fcd9..3be7dd5bd98e 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 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 void initialize() throws Exception { 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 void close() throws IOException { 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 Object[][] createData() { }; } - @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 void testRuntimeVersioning(String style, String file) throws Exception { // 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 void testCachedJars(String style, String file) throws Exception { 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 Object[][] createResourceData() throws Exception { }; } - @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 void testResources(String style, URL url) throws Throwable { // 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 void testResources(String style, URL url) throws Throwable { 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 785920b4a4da..272d82bd4d68 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 Object[][] urls() { 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 void testConnect(String urlString, boolean exists) throws Exception { } } - @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 52/90] 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 ebcb9e3204ce..72fb8036f08e 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 GZIPInputStream(InputStream in, int size) throws IOException { 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 void close() throws IOException { /* * 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 void close() throws IOException {} (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 @@ private int readUByte(InputStream in) throws IOException { 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 f63015e0930d..000000000000 --- 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 53/90] 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 6a288e0dad06..854cf73049bf 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 54/90] 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 2ae42bebcfdb..33d00b93365f 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 0846f339227a..f2fa114133e7 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 c41e7bf2e2e3..97ceb19d0ad2 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -94,6 +94,15 @@ class PrintSystemPropertiesDCmd : public DCmd { 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 30a22b05742d..9faa172c8e7a 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 @@ private static void debugLoad(boolean start, Object source) { 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 a4875f357e37..2d9dbea052af 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 @@ 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 197da0d456c4..32c358340af3 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 static byte[] serializePropertiesToByteArray() throws IOException { 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 000000000000..b5a6ead34c14 --- /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 55/90] 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 9a1da726f00c..d6e75f17f501 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 000000000000..1a3fdf6e9d64 --- /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 56/90] 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 31449eefb332..ff8358c3cd82 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 57/90] 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 60602ef942bb..0da2f90da3f3 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 58/90] 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 13a005591fb8..4a2d75ecdf3b 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 59/90] 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 7d80ed327fd6..5c6010acdf19 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 2f2d33ab130f..cc5a7ccbdefd 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 @@ static boolean opKind(Operator op, int bit) { /** 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 000000000000..ea1878bcb538 --- /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 60/90] 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 a72d5fc5cf9d..dbb5ba509a2c 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 2b0b78ac1ce6..5af1eae92c5d 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 2b0e6ce9cf4f..52c8d4d43895 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 0108f1a97629..048355bfad3f 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 39fcc5556c62..ac22430aa4c0 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 d18338726837..04884d5e666c 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 87cc137e7977..340f370d1d5d 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 @@ class PartialArraySplitter { // // 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 @@ class PartialArraySplitter { 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 abb0cf131016..7679358e2188 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 aadbc46b7c1f..d3b21c2fdaa0 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 3dafeb0f14ce..75e297526aef 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 @@ class PartialArrayState { // 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 @@ class PartialArrayStateAllocator : public CHeapObj { // 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 d91ba347d6c8..f7d53c9348ab 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 11499ca2ffeb..594cc7b245a9 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 @@ class PartialArrayTaskStepper { // 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 6946f7c69ff3..538815698f29 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 977e7a9d9497..3f5b6c0706c9 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 61/90] 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 5af1eae92c5d..3be4ab8d839e 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 66ca10f1fb6b..c91029441974 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 ea3d644d105a..4d7ffce3a5dd 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 a89f42959e1b..1d2f45397aa7 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 62/90] 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 de496b3f606b..9f42326ef095 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 @@ private static Map extractZoneNames(Map map, Str 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 @@ private static Map extractZoneNames(Map map, Str } 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 @@ private static Map extractZoneNames(Map map, Str 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 @@ private static String flipIfNeeded(boolean inVanguard, String format) { * 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 @@ private static void fillTZDBShortNames(String tzid, String[] names) { } } + 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 4d9b7500d870..b02f988e7c01 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 @@ private static Object[][] sampleTZs() { // 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 63/90] 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 15af2d5c4e21..441bd4859fe8 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 0b69ef7d25a3..3e3b1103c864 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 36f0864da0bb..3a6415d52bd3 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 7f5b4870aab4..7e9000991cae 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 39a9c618350e..a688d834e9b5 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 ddcfc7c5f7be..65f3e9b91413 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 @@ protected void verifyWarnings() throws Throwable { @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 @@ protected void verifyOptionValues() throws Throwable { 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 64/90] 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 a688d834e9b5..cf9de40a2370 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 65/90] 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 | 24 +++- .../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, 212 insertions(+), 143 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 a12f48c08774..594367e29729 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 1a47cb756f42..8ea5cdb36c8b 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 @@ class ShenandoahGenerationalHeuristics : public ShenandoahAdaptiveHeuristics { 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 ed25cd2e1a98..9452e8b28cbb 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 8102fa24d145..1e96a665704b 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 895088381ee6..3091b19b6003 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 6ed05abf0b16..765061a43ed7 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 @@ class ShenandoahSpaceInfo { // 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 68ffb6592db1..27aa9a475101 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 806cef673d5b..8fabc40693ca 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp @@ -38,9 +38,9 @@ class ShenandoahYoungHeuristics : public ShenandoahGenerationalHeuristics { 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 5ef21719ed47..1c2c15c40dc4 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 3d592e9f9be3..7d082e4a8b00 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 6f32d1011527..9f8944127c00 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -143,7 +143,7 @@ class ShenandoahGeneration : public CHeapObj, public ShenandoahSpaceInfo { 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 630736190f0c..0069d38a84ee 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp @@ -213,7 +213,12 @@ class ShenandoahOldGeneration : public ShenandoahGeneration { 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 bbb44348355b..c28e572dd6bd 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,16 +35,30 @@ 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_freeRegions(free_regions); + e.set_regionsImmediate(regions_immediate); + e.set_immediateBytes(immediate_size); + + 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.set_freeRegions(free_regions); - e.set_regionsImmediate(regions_immediate); - e.set_immediateBytes(immediate_size); e.commit(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTrace.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTrace.hpp index 116968103dea..e5c80e0705fe 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 2b0821650057..09d9e0ccabfc 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 554e09261d69..d077157d2a1d 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 108886fb18d6..126615af14b6 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 5730f4d9ff4b..888ff9eb17ae 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 static void main(String[] args) throws Exception { 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 000000000000..08a360e14fd2 --- /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 8b0113f75f42..06ee62a2f7c7 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 66/90] 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 ebd8f3a9e03c..4c1c8d9bbc80 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -1000,30 +1000,6 @@ class Assembler : public AbstractAssembler { 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 dfba2dcff461..a6cc862d05ca 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -890,10 +890,6 @@ class MacroAssembler: public Assembler { // 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 67/90] 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 8f969600ba8c..d691a3c80285 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -1286,7 +1286,7 @@ class FrameValuesOopClosure: public OopClosure, public DerivedOopClosure { } 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 68/90] 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 034de22bf25f..7783fc7ff032 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 673d4d50420f..ba81df0c0e61 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 d0b085f79334..179b8dc8cb4d 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 fd095b515b91..e4e13b0a6840 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 56ec204cd1a4..349e7d073831 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 5772e6ebb1c8..1a5bb7b60f8a 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 4a7e51d112dc..de63c9989279 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 f0972ba9bef9..838c8460f910 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 05d18cd06b74..29082a6be089 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 69/90] 8372797: [VectorAPI] Missing Min/Max identity
 transforms

Reviewed-by: xgong, vlivanov
---
 src/hotspot/share/opto/vectornode.cpp         |   82 +-
 src/hotspot/share/opto/vectornode.hpp         |   38 +-
 .../compiler/lib/ir_framework/IRNode.java     |   20 +
 .../VectorCommutativeOperSharingTest.java     |    4 +-
 .../vectorapi/VectorMinMaxTransforms.java     | 2036 +++++++++++++++++
 .../VectorUnsignedMinMaxOperationsTest.java   | 1353 ++++++++++-
 6 files changed, 3476 insertions(+), 57 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 6012bdef86ee..b07f02344922 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 dce43f929056..c4fff06e771c 100644
--- a/src/hotspot/share/opto/vectornode.hpp
+++ b/src/hotspot/share/opto/vectornode.hpp
@@ -662,10 +662,22 @@ class AbsVSNode : public VectorNode {
   virtual int Opcode() const;
 };
 
+// Common superclass for Min/Max vector nodes
+class MinMaxVNode : public VectorNode {
+public:
+  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 VectorNode {
+class MinVNode : public MinMaxVNode {
 public:
-  MinVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
+  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 @@ class MaxVHFNode : public VectorNode {
 };
 
 // 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 3f742a0ce627..f3fc4afb1704 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 a51946dd6985..2b43cf264210 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java
@@ -74,8 +74,8 @@ public static void main(String[] args) {
     @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 000000000000..acffe4d32577
--- /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 464e887cbace..b1b983063125 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 @@
 
 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 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 void umin_max_ir_transform5_verify() {
             }
         }
     }
-}
 
+
+    // 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 70/90] 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 000000000000..3d51031840cd
--- /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 71/90] 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 acffe4d32577..be3ec3228925 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 72/90] 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 | 100 +++---
 .../vectorapi/VectorMaskCastTest.java         | 188 +++++++----
 .../vectorapi/VectorMaskToLongTest.java       |  33 +-
 .../VectorStoreMaskIdentityTest.java          | 317 ++++++++++++++++++
 .../vector/VectorStoreMaskBenchmark.java      |  84 +++++
 9 files changed, 652 insertions(+), 119 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 0fecc14f31a7..a4d6a6c33d08 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 b07f02344922..dbadc18da014 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 c4fff06e771c..de8668983024 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 706e21554bb5..f9e50fbd23bd 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorLongToMaskNodeIdealization.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLongToMaskNodeIdealization.java
@@ -46,7 +46,7 @@
 
 /*
  * @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 static void main(String[] args) {
                   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 static void check_test1(Object out) {
                   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 static void check_test1b(Object out) {
                   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 e4f166f510a6..e1c20da76ec9 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();
-    }
-
-    @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());
-    }
-
-    @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.
+    @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);
-        VectorMask mDouble256 = mInt128.cast(DoubleVector.SPECIES_256);
-        VectorMask  mShort64 = mDouble256.cast(ShortVector.SPECIES_64);
-        return mShort64.trueCount();
+        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 = "testTwoCastToDifferentType2")
-    public static void testTwoCastToDifferentType2_runner() {
-        int count = testTwoCastToDifferentType2();
+    @Run(test = "testOneCastToSameType")
+    public static void testOneCastToSameType_runner() {
+        int count = testOneCastToSameType();
         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, "= 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 1f346cffd2fa..c75ea6c7a66f 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 static void testByte64ToShort128_runner() {
     @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 static void testByte64ToInt256_runner() {
     @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 static void testByte64ToFloat256_runner() {
     @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 static void testByte64ToLong512_runner() {
     @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 static void testByte64ToDouble512_runner() {
     @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 static void testByte128ToShort256_runner() {
     @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 static void testByte128ToInt512_runner() {
     @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 static void testByte128ToFloat512_runner() {
     @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 static void testByte256ToShort512_runner() {
     @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 static void testShort64ToInt128_runner() {
     @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 static void testShort64ToFloat128_runner() {
     @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 static void testShort64ToLong256_runner() {
     @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 static void testShort64ToDouble256_runner() {
     @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 static void testShort128ToByte64_runner() {
     @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 static void testShort128ToInt256_runner() {
     @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 static void testShort128ToFloat256_runner() {
     @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 static void testShort128ToLong512_runner() {
     @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 static void testShort128ToDouble512_runner() {
     @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 static void testShort256ToByte128_runner() {
     @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 static void testShort256ToInt512_runner() {
     @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 static void testShort256ToFloat512_runner() {
     @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 static void testShort512ToByte256_runner() {
     @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 static void testInt64ToLong128_runner() {
     @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 static void testInt64ToDouble128_runner() {
     @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 static void testInt128ToShort64_runner() {
     @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 static void testInt128ToLong256_runner() {
     @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 static void testInt128ToDouble256_runner() {
     @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 static void testInt256ToShort128_runner() {
     @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 static void testInt256ToByte64_runner() {
     @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 static void testInt256ToLong512_runner() {
     @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 static void testInt256ToDouble512_runner() {
     @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 static void testInt512ToShort256_runner() {
     @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 static void testInt512ToByte128_runner() {
     @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 static void testFloat64ToLong128_runner() {
     @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 static void testFloat64ToDouble128_runner() {
     @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 static void testFloat128ToShort64_runner() {
     @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 static void testFloat128ToLong256_runner() {
     @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 static void testFloat128ToDouble256_runner() {
     @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 static void testFloat256ToShort128_runner() {
     @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 static void testFloat256ToByte64_runner() {
     @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 static void testFloat256ToLong512_runner() {
     @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 static void testFloat256ToDouble512_runner() {
     @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 static void testFloat512ToShort256_runner() {
     @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 static void testFloat512ToByte128_runner() {
     @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 static void testLong128ToInt64_runner() {
     @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 static void testLong128ToFloat64_runner() {
     @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 static void testLong256ToInt128_runner() {
     @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 static void testLong256ToFloat128_runner() {
     @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 static void testLong256ToShort64_runner() {
     @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 static void testLong512ToInt256_runner() {
     @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 static void testLong512ToFloat256_runner() {
     @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 static void testLong512ToShort128_runner() {
     @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 static void testLong512ToByte64_runner() {
     @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 static void testDouble128ToInt64_runner() {
     @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 static void testDouble128ToFloat64_runner() {
     @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 static void testDouble256ToInt128_runner() {
     @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 static void testDouble256ToFloat128_runner() {
     @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 static void testDouble256ToShort64_runner() {
     @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 static void testDouble512ToInt256_runner() {
     @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 static void testDouble512ToFloat256_runner() {
     @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 static void testDouble512ToShort128_runner() {
     @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 35a5aca966ac..434154960720 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 static void testFromLongToLongLong() {
         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 static void testFromLongToLongFloat() {
         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 000000000000..c019f1163738
--- /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 000000000000..d4dc321ccba7
--- /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 73/90] 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      | 15 +++-
 src/hotspot/cpu/arm/stubDeclarations_arm.hpp  | 15 ++--
 src/hotspot/cpu/arm/stubRoutines_arm.cpp      |  2 +-
 src/hotspot/cpu/arm/stubRoutines_arm.hpp      | 12 ++-
 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  | 12 ++-
 .../cpu/s390/stubDeclarations_s390.hpp        | 15 ++--
 src/hotspot/cpu/s390/stubRoutines_s390.cpp    |  6 +-
 src/hotspot/cpu/s390/stubRoutines_s390.hpp    | 12 ++-
 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      | 12 ++-
 .../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, 349 insertions(+), 123 deletions(-)

diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad
index 19f03d97a72e..30b0c9c799ba 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 7aab7d389e1b..bba37a7a3901 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 5c05832afbeb..5964bb60d4f8 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 9dac6a39b82b..d1f59e479dbd 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 32fd8afb2685..5d9b2f1d8265 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 35ec22b08973..aaf31d4f9111 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 f77192a37418..6067408ef138 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) +#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) + 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 @@ class aarch64 { #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 5f768a205a54..5fb0d4e901fe 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 3ed747ea11a2..38a9b298562f 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 45ab10d14f99..29d96d0e6535 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) +#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) + 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 @@ class Arm { #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 be51afe42a44..41b8b71486df 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 f977d759d204..890e354fd278 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 51e31aa3672d..b7f69eff9fa3 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 2c4e7210413f..ec67a3380521 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) +#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) + 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 @@ class riscv { #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 c3ad3cefeb97..d0e26beedab9 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 3db4995338de..eda0ebfdecc9 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 0a07efae46c0..e575115b7319 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) +#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) + 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 @@ class zarch { #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 f36c816dd5e4..b4d8aa10de28 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 4e77f8a5f6f6..9b229ad72219 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -596,4 +596,5 @@ 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 07a1ab622edb..24886deb3c5f 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 40be816fbf0f..993d19640340 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 05e8384d6364..d3823cb559fa 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 8696180c512a..aaee01437af6 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 3c6d75c1d4ed..7283798888be 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) +#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) + 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 @@ class x86 { #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) +#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) + 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 2357bbb51699..9abe313b3a72 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 d1ce378ee20e..ed1b3ea2e78f 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 c07c0298f2bb..4d4d865cf95b 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 447f7d3a5825..2fe503a8d0eb 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 74/90] 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 a184884b61a2..d9a18956e3b5 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 75/90] 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 ff77d51b798b..9f108a263e90 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 void testNegativePortValue() throws Exception { /* 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 void testSimpleConstructor() { 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 void testFullConstructor() { 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 f2e1c40603c6..c66f79662676 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 void testDefaultGetSocketAddress() { 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 0e950c4f7f2b..74424339a188 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 void testSetAddress() throws Exception { // 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 @@ Object[][] data() { // add checks for setAddress with null - add getAddress to v }; } - @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 @@ Object[][] lengths() { }; } - @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 @@ Object[][] ports() { }; } - @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 304180b6c489..56b52b2a264a 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 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 @@ * @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 void testOrdering() throws Exception { } 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 12eb599b872c..a86e6c714f03 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 Object[][] createArgs1() { }; } - @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 Object[][] createArgs3() { }; } - @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 8161670860eb..8edb447e44ed 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 void testNetworkInterfaces() throws SocketException { 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 825f344c6622..e8cedab7dadb 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.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 @@ static Map,List> optionValueMap() { // -- 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 Object[][] socketOptionValues() throws Exception { } } - @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 Object[][] serverSocketOptionValues() throws Exception { } } - @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 void closedServerSocketAdapter(SocketOption option, List values 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 Object[][] datagramSocketOptionValues() throws Exception { } } - @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 Object[][] multicastSocketOptionValues() throws Exception { } } - @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 955414559c20..a5e3ec8f67ca 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.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 void testDatagramSocket() throws IOException { 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 void testMulticastSocket() throws IOException { 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 void testSocket() throws IOException { 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 void testServerSocket() throws IOException { 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 372a0322a355..14b50afa8d35 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 842fd4bc229d..d6dab5fa3271 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.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 void nulls() throws Exception { @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 @@ static Map,List> badOptionValues() { // -- 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 Object[][] socketBadOptionValues() throws Exception { } } - @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 Object[][] serverSocketBadOptionValues() throws Exception { } } - @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 void serverSocketAdapter(SocketOption option, T value) 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 Object[][] datagramSocketBadOptionValues() throws Exception { } } - @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 Object[][] multicastSocketBadOptionValues() throws Exception { } } - @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 3074d8fd2743..2a1c689cae71 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.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 @@ static Set> concat(Set> ...options) { 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 @@ static Object[][] provider() throws IOException { }; } - @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 dde7596c0524..20c194be8473 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 void positive() { @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 1b277bb24fce..a8794724c546 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.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 @@ protected java.net.PasswordAuthentication getPasswordAuthentication() { }); } - private boolean ensureIPv6OnLoopback() throws Exception { + private static boolean ensureIPv6OnLoopback() throws Exception { boolean ipv6 = false; List nics = Collections.list(NetworkInterface.getNetworkInterfaces()); @@ -114,7 +115,7 @@ private boolean ensureIPv6OnLoopback() throws Exception { 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 @@ private boolean ensureInet6AddressFamily() throws IOException { 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 void testSocksOverIPv6() throws Exception { 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 void testSocksOverIPv6Hostname() throws Exception { 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 void testSocksOverIPv6Hostname() throws Exception { 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 57d54defda33..05792aad784a 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.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 void afterTest() { * 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 @@ private static final class SchemeStrippedProxySelector extends DefaultProxySelec @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 List select(final URI uri) { } 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 ba55eac46df2..d5d1f295fd16 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 c34c8e001b77..d75658011c90 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; -public class LengthTest { - final int namelen = 100; // length close to max +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; - @DataProvider(name = "strings") - public Object[][] strings() { - if (namelen == -1) - return new Object[][] {new String[]{""}}; +public class LengthTest { + private static final int namelen = 100; // length close to max - 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 305b4bee95e3..b48805f61b32 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.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 76/90] 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 | 141 ++++++++--- .../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 | 236 +++++++++++++++++- .../vector/Float16OperationsBenchmark.java | 19 ++ .../bench/vm/compiler/VectorReduction2.java | 93 ++++++- 14 files changed, 819 insertions(+), 68 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index 30b0c9c799ba..4c854913e638 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 48bffb3cf358..58ed234194ab 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" %} - 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, + `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 %{ + 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 bba37a7a3901..3c179f21c149 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 5964bb60d4f8..f96d3ffb8635 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 4dd2bff7c897..5802217c1c1c 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 3c1a68d62245..0f67cf90183b 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 db3cbd4109cb..e05df8ea716b 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 dbadc18da014..d19aa476196a 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 de8668983024..91cff9fcae89 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 @@ class AddReductionVLNode : public ReductionNode { 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 @@ class AddReductionVFNode : 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 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 @@ class AddReductionVDNode : 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 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 @@ class MulReductionVLNode : public ReductionNode { 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 f3fc4afb1704..55d591acdb3a 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 5c085e6a3a34..97a55ae20749 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 @@ 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 @@ interface TestFunction { 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 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 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 @@ static double[] fillRandom(double[] a) { 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 @@ private static double doubleMaxBig() { 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 f3c27c4d278a..929a70f304aa 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.generators.Generator; import compiler.lib.ir_framework.*; -import jdk.incubator.vector.Float16; -import static jdk.incubator.vector.Float16.*; -import static java.lang.Float.*; +import compiler.lib.verify.Verify; import java.util.Arrays; +import jdk.incubator.vector.Float16; import jdk.test.lib.*; -import compiler.lib.generators.Generator; 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 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 TestFloat16VectorOperations() { input1[i] = gen.next(); input2[i] = gen.next(); input3[i] = gen.next(); + input4[i] = shortBitsToFloat16(gen.next()); } } @@ -349,7 +353,9 @@ public void checkResultAddConstantInputFloat16() { @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 void checkResultSubConstantInputFloat16() { @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 void checkResultMulConstantInputFloat16() { @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 void checkResultDivConstantInputFloat16() { @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 void checkResultMaxConstantInputFloat16() { @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 void checkResultMinConstantInputFloat16() { 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 92c0b58005f1..daf18af528eb 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 short dotProductFP16() { } 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 9241aca1dadf..0d11705c8ec6 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 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 void init() { 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 void init() { 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 void doubleMaxBig(Blackhole bh) { 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 77/90] 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 32728efde6c3..b28723f94a62 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.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.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.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 void print(PrintRequestAttributeSet attributes) } 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 4c2ff370cb88..322c19ed7c2c 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.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 @@ private enum TestExceptionType {PE, RE} 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 static void main(String[] args) { TestExceptionType.valueOf(args[1])); } - public ExceptionFromPrintableIsIgnoredTest( + private ExceptionFromPrintableIsIgnoredTest( final TestThreadType threadType, final TestExceptionType exceptionType) { System.out.println(String.format( @@ -87,15 +99,28 @@ public void run() { } 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 int print(Graphics graphics, PageFormat pageFormat, 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 int print(Graphics graphics, PageFormat pageFormat, }); 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 78/90] 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 a3dd3d2bfd05..c2838917516d 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 79/90] 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 cb44b833c489..832c8a33c888 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 1e84a39c30b5..d8779a873cd8 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 984454dfbaff..b52e3412f4e0 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"); - - 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."); - } +ClassLoad(jvmtiEnv *jvmti_env, + JNIEnv* jni_env, + jthread thread, + jclass klass) { - 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 8a7b7cf106ae..9d25a7bc0904 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 80/90] 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 54269a56c19c..7bb6b1dcb77d 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 38545fd6f41d..dce54eb73c0c 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -303,14 +303,18 @@ class CastVVNode: public ConstraintCastNode { //------------------------------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 26417436ed99..ff7bc2c10d3b 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 36855d659bac..8c6622e643ec 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1186,6 +1186,7 @@ class Node { 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 f44df7e6da22..d35717c59222 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 81/90] 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 6e9421e5c092..6623676d2ba3 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 e9e610330ad3..aa7becdb6f85 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 String classpath(RunMode runMode) { } @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 3b9458c14da3..0fe112357491 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 String[] vmArgs(RunMode runMode) { @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 d3c6a23efa0b..01b64a7fff08 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 String classpath(RunMode runMode) { @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 000000000000..2afcd802fc5a --- /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 000000000000..e243dfb4e8e7 --- /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 82/90] 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 fc7274714ad7..ab9896fa4266 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -97,7 +97,7 @@ class NativeInstruction { #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 @@ class NativeCall: public NativeInstruction { 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 83/90] 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 ae20418942d8..d732e6f04e12 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 000000000000..f2828257a2e2 --- /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 84/90] 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 c1fa4b964b77..e9d6a6866943 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 000000000000..822c38063479 --- /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 85/90] 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 5d9b2f1d8265..fddb37b7b8d8 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 aaf31d4f9111..f02b681ca109 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 29925e71aafc..5c05b3702bb3 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 45c13b7b3972..19e1ca680b37 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 2ed9858bf0c7..3c8babcbecfc 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 f73c8ed459e1..f53985a13b7b 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 557fe6233510..9ebab07589eb 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 8849597c94b1..07683a51e3d1 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 1d0e961c82d9..ea7e6d642540 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 4648fe03aa04..308a80429938 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 5ff09e2b3775..a9a6dc10da47 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 075d25dcac89..58f81652a0c9 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 eaeaea2c5662..00c759a369ba 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 f6e1d241948f..9969866cfc70 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 3bfa5a7277fc..9f91b9e8f841 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 dcf5f3eb824d..4f2fe8a460bb 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 aaee01437af6..ce11925dde2b 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 86/90] 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 50aabad7d42e..0096aad2570d 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 000000000000..743e59bca617 --- /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 000000000000..cb7e4b5d1eea --- /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 87/90] 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 8fe41faa8861..78cbe664da33 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 @@ private static void execTest() { } } } 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 88/90] 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 3a936f288cce..f5289e6b0115 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 @@ public static void main(String[] args) { 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 @@ protected void runTests() throws Exception { 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 @@ public void dontinline_waitWhenWarmupDone(ForLocking l2) throws Exception { } -///////////////////////////////////////////////////////////////////////////// - -/** - * 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 89/90] 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 f0125c38caea..ba0aa1a13045 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 54d43416fdb3..ba228901d722 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp @@ -59,8 +59,6 @@ class ShenandoahConcurrentGC : public ShenandoahGC { 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 @@ class ShenandoahConcurrentGC : public ShenandoahGC { 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 1873d8180939..84b22f13d470 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 a579d6d36942..592c5bffa5a7 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 6912750378e5..ca15c6db443e 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 d5cfa4b7fb92..a51449e91f49 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 5bf765055065..75d3ade4e491 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 d4604be0aece..ab7dd00b7743 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -298,6 +298,7 @@ class ShenandoahHeap : public CollectedHeap { 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 afc6b24e168c..3db11000af52 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 3a0ac042f574..569b64f756b9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -246,6 +246,7 @@ class ShenandoahHeapRegion { double _empty_time; HeapWord* _top_before_promoted; + HeapWord* _top_at_evac_start; // Seldom updated fields Atomic _state; @@ -365,12 +366,15 @@ class ShenandoahHeapRegion { } // 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 3c6fe1a3df12..7554a9c9a2ce 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 10d61221e87e..153193fa3a33 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 4ad7d2a1ae55..37de5966554e 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 0069d38a84ee..942f93c5c68d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp @@ -172,8 +172,8 @@ class ShenandoahOldGeneration : public ShenandoahGeneration { 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 @@ class ShenandoahOldGeneration : public ShenandoahGeneration { // Mark card for this location as dirty void mark_card_as_dirty(void* location); - void parallel_heap_region_iterate(ShenandoahHeapRegionClosure* cl) override; + template + class ShenandoahHeapRegionLambda : public ShenandoahHeapRegionClosure { + T _region_lambda; + public: + explicit ShenandoahHeapRegionLambda(T region_lambda) : _region_lambda(region_lambda) {} - void parallel_heap_region_iterate_free(ShenandoahHeapRegionClosure* cl) override; + 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 @@ class ShenandoahOldGeneration : public ShenandoahGeneration { 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 412cfa9447e7..5049113b6658 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 e890008b9160..a454de68f006 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 @@ class ShenandoahPhaseTimings : public CHeapObj { 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 9e160d5b2945..8d7ba2dc46ff 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 c2c117e86e6a..53f00e64a037 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -603,6 +603,9 @@ class ShenandoahCardCluster: public CHeapObj { // 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 @@ class ShenandoahScanRemembered: public CHeapObj { } } + 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 90/90] 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 81f2951289de..1711c5f8cd33 100644 --- a/src/hotspot/share/classfile/compactHashtable.hpp +++ b/src/hotspot/share/classfile/compactHashtable.hpp @@ -307,14 +307,9 @@ class CompactHashtable : public SimpleCompactHashtable { 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 bd696f52a8b4..a6decdce7f0d 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 @@ class TrainingData : public Metadata { 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 @@ class TrainingData : public Metadata { } 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);