Version in base suite: 25.0.3+9-2~deb13u1 Version in overlay suite: 25.0.4.1+1-1~deb13u1 Base version: openjdk-25_25.0.4.1+1-1~deb13u1 Target version: openjdk-25_25.0.5+8-1~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/o/openjdk-25/openjdk-25_25.0.4.1+1-1~deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/o/openjdk-25/openjdk-25_25.0.5+8-1~deb13u1.dsc /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/cert8.db |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/cert9.db |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/key3.db |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/key4.db |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/keystore |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/secmod.db |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/cert8.db |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/cert9.db |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/key3.db |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/key4.db |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/keystore |binary /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/secmod.db |binary openjdk-25-25.0.5+8/.jcheck/conf | 2 openjdk-25-25.0.5+8/debian/JB-jre-headless.overrides.in | 5 openjdk-25-25.0.5+8/debian/JB-jre-zero.overrides.in | 1 openjdk-25-25.0.5+8/debian/JB-testsupport.overrides.in | 6 openjdk-25-25.0.5+8/debian/changelog | 103 openjdk-25-25.0.5+8/debian/control | 4 openjdk-25-25.0.5+8/debian/man/jar.1 | 4 openjdk-25-25.0.5+8/debian/man/jarsigner.1 | 4 openjdk-25-25.0.5+8/debian/man/java.1 | 4 openjdk-25-25.0.5+8/debian/man/javac.1 | 4 openjdk-25-25.0.5+8/debian/man/javadoc.1 | 4 openjdk-25-25.0.5+8/debian/man/javap.1 | 4 openjdk-25-25.0.5+8/debian/man/jcmd.1 | 4 openjdk-25-25.0.5+8/debian/man/jconsole.1 | 4 openjdk-25-25.0.5+8/debian/man/jdb.1 | 4 openjdk-25-25.0.5+8/debian/man/jdeprscan.1 | 4 openjdk-25-25.0.5+8/debian/man/jdeps.1 | 4 openjdk-25-25.0.5+8/debian/man/jfr.1 | 4 openjdk-25-25.0.5+8/debian/man/jhsdb.1 | 4 openjdk-25-25.0.5+8/debian/man/jinfo.1 | 4 openjdk-25-25.0.5+8/debian/man/jlink.1 | 4 openjdk-25-25.0.5+8/debian/man/jmap.1 | 4 openjdk-25-25.0.5+8/debian/man/jmod.1 | 4 openjdk-25-25.0.5+8/debian/man/jnativescan.1 | 4 openjdk-25-25.0.5+8/debian/man/jpackage.1 | 4 openjdk-25-25.0.5+8/debian/man/jps.1 | 4 openjdk-25-25.0.5+8/debian/man/jrunscript.1 | 4 openjdk-25-25.0.5+8/debian/man/jshell.1 | 4 openjdk-25-25.0.5+8/debian/man/jstack.1 | 4 openjdk-25-25.0.5+8/debian/man/jstat.1 | 4 openjdk-25-25.0.5+8/debian/man/jstatd.1 | 4 openjdk-25-25.0.5+8/debian/man/jwebserver.1 | 4 openjdk-25-25.0.5+8/debian/man/keytool.1 | 4 openjdk-25-25.0.5+8/debian/man/rmiregistry.1 | 4 openjdk-25-25.0.5+8/debian/man/serialver.1 | 4 openjdk-25-25.0.5+8/debian/patches/jdk-8337853.diff | 427 ++ openjdk-25-25.0.5+8/debian/patches/jdk-8371066.diff | 920 ++++++ openjdk-25-25.0.5+8/debian/patches/jdk-8378603.diff | 91 openjdk-25-25.0.5+8/debian/patches/jdk-8378607.diff | 89 openjdk-25-25.0.5+8/debian/patches/jdk-8378615.diff | 127 openjdk-25-25.0.5+8/debian/patches/jdk-8384505.diff | 39 openjdk-25-25.0.5+8/debian/patches/jdk-8388170-proposed.diff | 304 -- openjdk-25-25.0.5+8/debian/patches/jdk-8388170.diff | 300 ++ openjdk-25-25.0.5+8/debian/patches/series | 10 openjdk-25-25.0.5+8/debian/rules | 39 openjdk-25-25.0.5+8/debian/tests/control | 4 openjdk-25-25.0.5+8/debian/tests/problems-loong-hotspot.txt | 554 +++ openjdk-25-25.0.5+8/debian/tests/problems-loong-jdk.txt | 771 +++++ openjdk-25-25.0.5+8/debian/tests/problems-loong-other.txt | 134 openjdk-25-25.0.5+8/debian/tests/problems.csv | 14 openjdk-25-25.0.5+8/debian/tests/write-problems.in | 6 openjdk-25-25.0.5+8/debian/tests/write-problems.sh | 6 openjdk-25-25.0.5+8/doc/testing.html | 2 openjdk-25-25.0.5+8/doc/testing.md | 4 openjdk-25-25.0.5+8/make/Bundles.gmk | 79 openjdk-25-25.0.5+8/make/CreateJmods.gmk | 8 openjdk-25-25.0.5+8/make/Images.gmk | 22 openjdk-25-25.0.5+8/make/RunTests.gmk | 11 openjdk-25-25.0.5+8/make/autoconf/flags-cflags.m4 | 5 openjdk-25-25.0.5+8/make/autoconf/flags-ldflags.m4 | 15 openjdk-25-25.0.5+8/make/autoconf/flags-other.m4 | 8 openjdk-25-25.0.5+8/make/autoconf/jdk-options.m4 | 27 openjdk-25-25.0.5+8/make/autoconf/lib-tests.m4 | 4 openjdk-25-25.0.5+8/make/autoconf/platform.m4 | 12 openjdk-25-25.0.5+8/make/autoconf/toolchain.m4 | 7 openjdk-25-25.0.5+8/make/common/native/CompileFile.gmk | 8 openjdk-25-25.0.5+8/make/conf/github-actions.conf | 4 openjdk-25-25.0.5+8/make/conf/jib-profiles.js | 8 openjdk-25-25.0.5+8/make/conf/version-numbers.conf | 6 openjdk-25-25.0.5+8/make/data/cldr/common/bcp47/timezone.xml | 16 openjdk-25-25.0.5+8/make/data/cldr/common/dtd/ldmlSupplemental.dtd | 6 openjdk-25-25.0.5+8/make/data/cldr/common/dtd/ldmlSupplemental.xsd | 2 openjdk-25-25.0.5+8/make/data/cldr/common/supplemental/metaZones.xml | 16 openjdk-25-25.0.5+8/make/hotspot/lib/CompileJvm.gmk | 13 openjdk-25-25.0.5+8/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java | 12 openjdk-25-25.0.5+8/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java | 10 openjdk-25-25.0.5+8/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java | 5 openjdk-25-25.0.5+8/make/modules/java.desktop/lib/ClientLibraries.gmk | 2 openjdk-25-25.0.5+8/make/modules/java.sql.rowset/Java.gmk | 1 openjdk-25-25.0.5+8/make/modules/jdk.crypto.cryptoki/Lib.gmk | 4 openjdk-25-25.0.5+8/make/modules/jdk.jconsole/Launcher.gmk | 24 openjdk-25-25.0.5+8/make/modules/jdk.jpackage/Lib.gmk | 3 openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/aarch64.ad | 30 openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/aarch64_vector.ad | 8 openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp | 170 - openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp | 23 openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/matcher_aarch64.hpp | 5 openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp | 83 openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp | 10 openjdk-25-25.0.5+8/src/hotspot/cpu/arm/matcher_arm.hpp | 5 openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp | 20 openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 60 openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp | 10 openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp | 71 openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp | 26 openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 131 openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 15 openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/matcher_ppc.hpp | 5 openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/ppc.ad | 379 -- openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 57 openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp | 159 - openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp | 23 openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 6 openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/matcher_riscv.hpp | 5 openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/riscv.ad | 21 openjdk-25-25.0.5+8/src/hotspot/cpu/s390/matcher_s390.hpp | 5 openjdk-25-25.0.5+8/src/hotspot/cpu/x86/assembler_x86.cpp | 260 + openjdk-25-25.0.5+8/src/hotspot/cpu/x86/assembler_x86.hpp | 38 openjdk-25-25.0.5+8/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 255 - openjdk-25-25.0.5+8/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 20 openjdk-25-25.0.5+8/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp | 333 -- openjdk-25-25.0.5+8/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp | 19 openjdk-25-25.0.5+8/src/hotspot/cpu/x86/macroAssembler_x86.cpp | 16 openjdk-25-25.0.5+8/src/hotspot/cpu/x86/matcher_x86.hpp | 13 openjdk-25-25.0.5+8/src/hotspot/cpu/x86/methodHandles_x86.hpp | 2 openjdk-25-25.0.5+8/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp | 108 openjdk-25-25.0.5+8/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp | 2 openjdk-25-25.0.5+8/src/hotspot/cpu/x86/vm_version_x86.cpp | 2 openjdk-25-25.0.5+8/src/hotspot/cpu/x86/x86.ad | 578 ++- openjdk-25-25.0.5+8/src/hotspot/cpu/x86/x86_64.ad | 172 + openjdk-25-25.0.5+8/src/hotspot/cpu/zero/bytecodeInterpreter_zero.inline.hpp | 33 openjdk-25-25.0.5+8/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 7 openjdk-25-25.0.5+8/src/hotspot/os/linux/os_linux.cpp | 253 - openjdk-25-25.0.5+8/src/hotspot/os/linux/os_linux.hpp | 17 openjdk-25-25.0.5+8/src/hotspot/os/windows/os_perf_windows.cpp | 155 - openjdk-25-25.0.5+8/src/hotspot/os/windows/os_windows.cpp | 52 openjdk-25-25.0.5+8/src/hotspot/os/windows/os_windows.hpp | 2 openjdk-25-25.0.5+8/src/hotspot/os/windows/safefetch_static_windows.cpp | 64 openjdk-25-25.0.5+8/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp | 11 openjdk-25-25.0.5+8/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp | 4 openjdk-25-25.0.5+8/src/hotspot/os_cpu/windows_aarch64/safefetch_windows_aarch64.S | 65 openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_Compiler.cpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_GraphBuilder.cpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_LIRGenerator.cpp | 6 openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_LIRGenerator.hpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/cds/aotConstantPoolResolver.cpp | 6 openjdk-25-25.0.5+8/src/hotspot/share/cds/filemap.cpp | 7 openjdk-25-25.0.5+8/src/hotspot/share/classfile/classFileParser.cpp | 74 openjdk-25-25.0.5+8/src/hotspot/share/classfile/stringTable.cpp | 7 openjdk-25-25.0.5+8/src/hotspot/share/classfile/symbolTable.cpp | 7 openjdk-25-25.0.5+8/src/hotspot/share/classfile/vmIntrinsics.cpp | 4 openjdk-25-25.0.5+8/src/hotspot/share/classfile/vmIntrinsics.hpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/classfile/vmSymbols.hpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/code/aotCodeCache.cpp | 14 openjdk-25-25.0.5+8/src/hotspot/share/compiler/compilationPolicy.cpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp | 6 openjdk-25-25.0.5+8/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp | 4 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp | 6 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp | 1 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp | 18 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp | 10 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp | 7 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp | 18 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp | 3 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp | 6 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp | 37 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp | 5 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 17 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp | 27 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp | 4 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp | 5 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp | 12 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp | 17 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp | 21 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp | 1 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp | 17 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp | 1 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp | 4 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp | 21 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp | 7 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp | 10 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp | 5 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp | 6 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp | 8 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp | 1 openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/include/jvm.h | 3 openjdk-25-25.0.5+8/src/hotspot/share/interpreter/abstractInterpreter.cpp | 6 openjdk-25-25.0.5+8/src/hotspot/share/interpreter/abstractInterpreter.hpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp | 5 openjdk-25-25.0.5+8/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp | 4 openjdk-25-25.0.5+8/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp | 78 openjdk-25-25.0.5+8/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp | 13 openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp | 5 openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp | 4 openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp | 13 openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp | 53 openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp | 74 openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp | 7 openjdk-25-25.0.5+8/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp | 15 openjdk-25-25.0.5+8/src/hotspot/share/jfr/utilities/jfrSet.hpp | 189 - openjdk-25-25.0.5+8/src/hotspot/share/oops/bsmAttribute.hpp | 170 + openjdk-25-25.0.5+8/src/hotspot/share/oops/bsmAttribute.inline.hpp | 55 openjdk-25-25.0.5+8/src/hotspot/share/oops/constantPool.cpp | 300 -- openjdk-25-25.0.5+8/src/hotspot/share/oops/constantPool.hpp | 142 openjdk-25-25.0.5+8/src/hotspot/share/oops/oop.hpp | 4 openjdk-25-25.0.5+8/src/hotspot/share/oops/oop.inline.hpp | 9 openjdk-25-25.0.5+8/src/hotspot/share/opto/arraycopynode.cpp | 6 openjdk-25-25.0.5+8/src/hotspot/share/opto/c2compiler.cpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/opto/callnode.cpp | 228 + openjdk-25-25.0.5+8/src/hotspot/share/opto/callnode.hpp | 61 openjdk-25-25.0.5+8/src/hotspot/share/opto/cfgnode.hpp | 1 openjdk-25-25.0.5+8/src/hotspot/share/opto/classes.hpp | 3 openjdk-25-25.0.5+8/src/hotspot/share/opto/compile.cpp | 35 openjdk-25-25.0.5+8/src/hotspot/share/opto/divnode.cpp | 158 - openjdk-25-25.0.5+8/src/hotspot/share/opto/divnode.hpp | 35 openjdk-25-25.0.5+8/src/hotspot/share/opto/graphKit.cpp | 29 openjdk-25-25.0.5+8/src/hotspot/share/opto/graphKit.hpp | 1 openjdk-25-25.0.5+8/src/hotspot/share/opto/ifnode.cpp | 55 openjdk-25-25.0.5+8/src/hotspot/share/opto/library_call.cpp | 78 openjdk-25-25.0.5+8/src/hotspot/share/opto/library_call.hpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/opto/loopPredicate.cpp | 19 openjdk-25-25.0.5+8/src/hotspot/share/opto/loopTransform.cpp | 475 ++- openjdk-25-25.0.5+8/src/hotspot/share/opto/loopnode.cpp | 1451 ++++++++-- openjdk-25-25.0.5+8/src/hotspot/share/opto/loopnode.hpp | 12 openjdk-25-25.0.5+8/src/hotspot/share/opto/macro.cpp | 22 openjdk-25-25.0.5+8/src/hotspot/share/opto/matcher.cpp | 15 openjdk-25-25.0.5+8/src/hotspot/share/opto/memnode.cpp | 6 openjdk-25-25.0.5+8/src/hotspot/share/opto/multnode.cpp | 13 openjdk-25-25.0.5+8/src/hotspot/share/opto/multnode.hpp | 46 openjdk-25-25.0.5+8/src/hotspot/share/opto/node.cpp | 25 openjdk-25-25.0.5+8/src/hotspot/share/opto/node.hpp | 5 openjdk-25-25.0.5+8/src/hotspot/share/opto/parse2.cpp | 8 openjdk-25-25.0.5+8/src/hotspot/share/opto/split_if.cpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/opto/subnode.hpp | 4 openjdk-25-25.0.5+8/src/hotspot/share/opto/vectorIntrinsics.cpp | 38 openjdk-25-25.0.5+8/src/hotspot/share/opto/vectornode.cpp | 98 openjdk-25-25.0.5+8/src/hotspot/share/opto/vectornode.hpp | 31 openjdk-25-25.0.5+8/src/hotspot/share/prims/jvm.cpp | 10 openjdk-25-25.0.5+8/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp | 28 openjdk-25-25.0.5+8/src/hotspot/share/prims/jvmtiRedefineClasses.cpp | 149 - openjdk-25-25.0.5+8/src/hotspot/share/prims/jvmtiRedefineClasses.hpp | 26 openjdk-25-25.0.5+8/src/hotspot/share/prims/upcallLinker.cpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/prims/upcallLinker.hpp | 2 openjdk-25-25.0.5+8/src/hotspot/share/prims/whitebox.cpp | 15 openjdk-25-25.0.5+8/src/hotspot/share/runtime/cpuTimeCounters.cpp | 3 openjdk-25-25.0.5+8/src/hotspot/share/runtime/os.hpp | 5 openjdk-25-25.0.5+8/src/hotspot/share/runtime/safefetch.hpp | 4 openjdk-25-25.0.5+8/src/hotspot/share/runtime/threads.cpp | 16 openjdk-25-25.0.5+8/src/hotspot/share/runtime/vmStructs.cpp | 21 openjdk-25-25.0.5+8/src/hotspot/share/sanitizers/ub.hpp | 5 openjdk-25-25.0.5+8/src/hotspot/share/utilities/debug.cpp | 107 openjdk-25-25.0.5+8/src/hotspot/share/utilities/ostream.hpp | 2 openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java | 7 openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java | 121 openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java | 103 openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java | 2 openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java | 38 openjdk-25-25.0.5+8/src/java.base/share/classes/java/lang/ref/Reference.java | 11 openjdk-25-25.0.5+8/src/java.base/share/classes/java/net/SocksSocketImpl.java | 41 openjdk-25-25.0.5+8/src/java.base/share/classes/java/security/Security.java | 37 openjdk-25-25.0.5+8/src/java.base/share/classes/java/text/SimpleDateFormat.java | 27 openjdk-25-25.0.5+8/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java | 8 openjdk-25-25.0.5+8/src/java.base/share/classes/java/util/zip/ZipFile.java | 16 openjdk-25-25.0.5+8/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java | 53 openjdk-25-25.0.5+8/src/java.base/share/classes/module-info.java | 1 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java | 4 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/smtp/SmtpClient.java | 6 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java | 8 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java | 6 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java | 58 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java | 60 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java | 29 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/pkcs12/MacData.java | 349 +- openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java | 140 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java | 138 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/provider/SHA3.java | 6 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/DHasKEM.java | 287 + openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/Hybrid.java | 474 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/HybridProvider.java | 130 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java | 162 - openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/KEMKeyExchange.java | 223 + openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java | 117 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/NamedGroup.java | 131 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java | 2 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmDecomposer.java | 10 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLExtension.java | 8 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java | 11 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java | 6 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java | 22 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/ServerHello.java | 51 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java | 6 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java | 4 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/HostnameChecker.java | 20 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/KeyUtil.java | 3 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/KnownOIDs.java | 3 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java | 212 + openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java | 30 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java | 33 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java | 15 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java | 32 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/SymantecTLSPolicy.java | 65 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/AlgorithmId.java | 143 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/DNSName.java | 108 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/IPAddressName.java | 145 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java | 19 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/URIName.java | 24 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/X509Key.java | 4 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java | 9 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java | 16 openjdk-25-25.0.5+8/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java | 4 openjdk-25-25.0.5+8/src/java.base/share/conf/security/java.security | 22 openjdk-25-25.0.5+8/src/java.base/share/data/cacerts/luxtrustglobalrootca | 28 openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/VERSION | 2 openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/africa | 191 - openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/asia | 24 openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/australasia | 2 openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/backward | 54 openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/europe | 51 openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/leapseconds | 8 openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/northamerica | 297 +- openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/southamerica | 29 openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/tzmappings.override | 16 openjdk-25-25.0.5+8/src/java.base/share/native/libjava/Reference.c | 8 openjdk-25-25.0.5+8/src/java.base/share/native/libjli/java.c | 2 openjdk-25-25.0.5+8/src/java.base/share/native/libjli/jli_util.c | 4 openjdk-25-25.0.5+8/src/java.base/share/native/libverify/check_code.c | 2 openjdk-25-25.0.5+8/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java | 15 openjdk-25-25.0.5+8/src/java.base/unix/native/libjava/TimeZone_md.c | 76 openjdk-25-25.0.5+8/src/java.base/unix/native/libnet/NetworkInterface.c | 21 openjdk-25-25.0.5+8/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java | 3 openjdk-25-25.0.5+8/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java | 11 openjdk-25-25.0.5+8/src/java.base/windows/native/libnet/NTLMAuthSequence.c | 4 openjdk-25-25.0.5+8/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java | 17 openjdk-25-25.0.5+8/src/java.desktop/macosx/classes/sun/lwawt/macosx/CImage.java | 29 openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/awt/CImage.m | 5 openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m | 5 openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m | 54 openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/shaders.metal | 10 openjdk-25-25.0.5+8/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java | 17 openjdk-25-25.0.5+8/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java | 8 openjdk-25-25.0.5+8/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java | 57 openjdk-25-25.0.5+8/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java | 11 openjdk-25-25.0.5+8/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c | 4 openjdk-25-25.0.5+8/src/java.desktop/share/native/libfontmanager/freetypeScaler.c | 8 openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/Devices.cpp | 140 openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/Devices.h | 7 openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp | 104 openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp | 70 openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h | 4 openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp | 12 openjdk-25-25.0.5+8/src/java.instrument/share/native/libinstrument/JPLISAgent.c | 4 openjdk-25-25.0.5+8/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c | 4 openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java | 4 openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java | 14 openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java | 4 openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java | 4 openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java | 10 openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/naming/internal/NamingManagerHelper.java | 29 openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java | 136 openjdk-25-25.0.5+8/src/java.naming/share/classes/module-info.java | 24 openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java | 104 openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/CheckFilename.java | 76 openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java | 4 openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/RedirectFilter.java | 47 openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java | 2 openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/ResponseContent.java | 69 openjdk-25-25.0.5+8/src/java.prefs/unix/native/libprefs/FileSystemPreferences.c | 9 openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java | 246 - openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java | 132 openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/MessageToken_v2.java | 34 openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/WrapToken_v2.java | 4 openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java | 2 openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java | 7 openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java | 6 openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/ETypeInfo2.java | 5 openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java | 2 openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java | 31 openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java | 6 openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java | 6 openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java | 6 openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java | 5 openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java | 11 openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java | 11 openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/RowSetResourceBundle.properties | 4 openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java | 34 openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java | 168 - openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java | 40 openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlErrorHandler.java | 36 openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java | 186 - openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlResolver.java | 44 openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java | 7 openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java | 3 openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java | 13 openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/SchemaNamespaceSupport.java | 7 openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java | 185 - openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/MultipleScopeNamespaceSupport.java | 52 openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathContext.java | 32 openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java | 27 openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java | 6 openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java | 5 openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java | 9 openjdk-25-25.0.5+8/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java | 14 openjdk-25-25.0.5+8/src/java.xml/share/classes/jdk/xml/internal/JdkXmlFeatures.java | 35 openjdk-25-25.0.5+8/src/java.xml/share/classes/module-info.java | 56 openjdk-25-25.0.5+8/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c | 17 openjdk-25-25.0.5+8/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c | 15 openjdk-25-25.0.5+8/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c | 15 openjdk-25-25.0.5+8/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java | 2 openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java | 48 openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11HKDF.java | 103 openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java | 51 openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c | 40 openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c | 31 openjdk-25-25.0.5+8/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java | 76 openjdk-25-25.0.5+8/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U4Array.java | 64 openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java | 30 openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java | 125 openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java | 8 openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java | 41 openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java | 4 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java | 6 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java | 6 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java | 6 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java | 6 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java | 6 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java | 82 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java | 6 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java | 6 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java | 6 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java | 6 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java | 6 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java | 82 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template | 85 openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template | 2 openjdk-25-25.0.5+8/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template | 6 openjdk-25-25.0.5+8/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js | 28 openjdk-25-25.0.5+8/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template | 2 openjdk-25-25.0.5+8/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c | 6 openjdk-25-25.0.5+8/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java | 13 openjdk-25-25.0.5+8/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin.java | 15 openjdk-25-25.0.5+8/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java | 11 openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/ExecCommand.c | 313 ++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/ExecCommand.h | 49 openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/LinuxLauncher.c | 36 openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c | 240 - openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.h | 21 openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Executor.cpp | 63 openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Executor.h | 4 openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/LinuxLauncherLib.cpp | 22 openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Package.cpp | 72 openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Package.h | 15 openjdk-25-25.0.5+8/src/jdk.jpackage/share/native/applauncher/JvmLauncher.h | 8 openjdk-25-25.0.5+8/src/jdk.jpackage/share/native/applauncher/JvmLauncherLib.c | 26 openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java | 71 openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java | 3 openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java | 28 openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java | 40 openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java | 55 openjdk-25-25.0.5+8/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java | 7 openjdk-25-25.0.5+8/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java | 19 openjdk-25-25.0.5+8/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json | 2 openjdk-25-25.0.5+8/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java | 157 - openjdk-25-25.0.5+8/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java | 54 openjdk-25-25.0.5+8/test/docs/TEST.ROOT | 4 openjdk-25-25.0.5+8/test/hotspot/jtreg/TEST.ROOT | 4 openjdk-25-25.0.5+8/test/hotspot/jtreg/TEST.groups | 3 openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/arraycopy/TestDeadCloneMem.java | 79 openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java | 36 openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java | 22 openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java | 215 + openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java | 3 openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/TestReferenceGet.java | 175 + openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/TestReferenceRefersTo.java | 146 - openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java | 218 + openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java | 107 openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java | 1 openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/rangechecks/TestFoldedIfsWrongReexec.java | 299 ++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/rangechecks/TestIndexMatching.java | 833 +++++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheckWithZeroScaling.java | 53 openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java | 70 openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java | 1299 ++++++++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java | 76 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/DockerBasicTest.java | 8 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/ShareTmpDir.java | 8 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java | 7 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestCPUSets.java | 10 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestContainerInfo.java | 8 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJFREvents.java | 5 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java | 8 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java | 7 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJcmd.java | 3 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java | 8 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java | 27 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java | 5 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java | 5 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java | 7 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java | 5 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMisc.java | 16 openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestPids.java | 7 openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/TestNativeReferenceGet.java | 181 + openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java | 12 openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java | 19 openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java | 433 ++ openjdk-25-25.0.5+8/test/hotspot/jtreg/gtest/ShenandoahGtests.java | 31 openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java | 2 openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/ErrorHandling/libNativeException.c | 5 openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java | 13 openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheConsistency.java | 82 openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ChangedJarFile.java | 2 openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java | 4 openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java | 107 openjdk-25-25.0.5+8/test/hotspot/jtreg/serviceability/dcmd/thread/PrintTest.java | 5 openjdk-25-25.0.5+8/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java | 5 openjdk-25-25.0.5+8/test/jaxp/TEST.ROOT | 2 openjdk-25-25.0.5+8/test/jdk/ProblemList.txt | 11 openjdk-25-25.0.5+8/test/jdk/TEST.ROOT | 6 openjdk-25-25.0.5+8/test/jdk/TEST.groups | 9 openjdk-25-25.0.5+8/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java | 24 openjdk-25-25.0.5+8/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java | 84 openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java | 159 + openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test10.java | 14 openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test3.java | 10 openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test4.java | 10 openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test5.java | 10 openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/B6361557.java | 12 openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/B6393710.java | 4 openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/B6433018.java | 3 openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java | 6 openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java | 67 openjdk-25-25.0.5+8/test/jdk/java/awt/Graphics2D/ClearPolyLineUsingXORTest.java | 95 openjdk-25-25.0.5+8/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java | 67 openjdk-25-25.0.5+8/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java | 244 - openjdk-25-25.0.5+8/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java | 10 openjdk-25-25.0.5+8/test/jdk/java/foreign/TestUpcallStress.java | 33 openjdk-25-25.0.5+8/test/jdk/java/lang/ProcessBuilder/Basic.java | 25 openjdk-25-25.0.5+8/test/jdk/java/lang/Thread/virtual/JfrEvents.java | 12 openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/AbstractConnectTimeout.java | 258 - openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutNoProxyAsync.java | 47 openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutNoProxySync.java | 48 openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutTest.java | 370 ++ openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutWithProxyAsync.java | 47 openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutWithProxySync.java | 48 openjdk-25-25.0.5+8/test/jdk/java/security/Security/ConfigFileTest.java | 927 ------ openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/ExtraFileAndIncludes.java | 937 ++++++ openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/LinuxAnonymousFiles.java | 83 openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/SecurityPropFile.file | 1 openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/SecurityPropFile.java | 42 openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/WindowsParentDirPermissions.java | 84 openjdk-25-25.0.5+8/test/jdk/java/time/test/java/time/format/TestUnicodeExtension.java | 12 openjdk-25-25.0.5+8/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java | 38 openjdk-25-25.0.5+8/test/jdk/java/time/test/java/time/zone/TestZoneRules.java | 14 openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/AIXTzMappingTest.java | 102 openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/Bug6329116.java | 20 openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/CustomTzIDCheckDST.java | 7 openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/NegativeDSTTest.java | 17 openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/TimeZoneData/VERSION | 2 openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt | 4 openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt | 12 openjdk-25-25.0.5+8/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java | 277 - openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java | 57 openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java | 8 openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java | 15 openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java | 25 openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/ciphersuites/BulkCipherDisabledAlgorithms.java | 197 + openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java | 288 + openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml | 32 openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml | 52 openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml | 32 openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml | 56 openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml | 40 openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml | 36 openjdk-25-25.0.5+8/test/jdk/javax/swing/SwingWorker/TestDoneBeforeDoInBackground.java | 20 openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java | 9 openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java | 7 openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java | 5 openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java | 6 openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java | 8 openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java | 30 openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java | 7 openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java | 5 openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java | 5 openjdk-25-25.0.5+8/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java | 1 openjdk-25-25.0.5+8/test/jdk/jdk/jfr/event/os/TestCPULoad.java | 72 openjdk-25-25.0.5+8/test/jdk/jdk/jfr/event/runtime/TestFlush.java | 2 openjdk-25-25.0.5+8/test/jdk/jdk/modules/etc/JmodExcludedFiles.java | 24 openjdk-25-25.0.5+8/test/jdk/jdk/nio/zipfs/EndOfCenValidation.java | 150 + openjdk-25-25.0.5+8/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java | 9 openjdk-25-25.0.5+8/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java | 2 openjdk-25-25.0.5+8/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java | 36 openjdk-25-25.0.5+8/test/jdk/sun/net/www/protocol/http/NTLMFailTest.java | 167 + openjdk-25-25.0.5+8/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java | 10 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java | 60 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh | 139 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java | 24 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java | 502 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/nss.cfg | 27 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/pkcs11.txt | 9 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java | 486 --- openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/nss.cfg | 19 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/pkcs11.txt | 9 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java | 9 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/PBMAC1Test.java | 223 + openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/ParamsPreferences.java | 8 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/params/README | 2 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/params/os6 | 23 openjdk-25-25.0.5+8/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java | 10 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java | 49 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java | 76 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/RestrictNamedGroup.java | 7 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java | 32 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/TLS13BulkCipherDisabledCipherSuite.java | 79 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/HybridKeyExchange/TestHybrid.java | 67 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/SSLAlgorithmDecomposer/BulkCipherDecomposition.java | 109 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruteForceClose.java | 4 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Camerfirma.java | 6 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java | 9 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java | 6 openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java | 10 openjdk-25-25.0.5+8/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java | 8 openjdk-25-25.0.5+8/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java | 24 openjdk-25-25.0.5+8/test/jdk/sun/security/x509/AlgorithmId/NullParams.java | 10 openjdk-25-25.0.5+8/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java | 184 - openjdk-25-25.0.5+8/test/jdk/sun/security/x509/IPAddressName/ConstrainsTest.java | 98 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcCapacityOutput1.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcMetaCapacityOutput1.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcNewCapacityOutput1.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcNewOutput1.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcOldCapacityOutput1.sh | 5 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcOldOutput1.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcOutput1.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts1.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts2.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts3.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts4.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatTimeStamp1.sh | 3 openjdk-25-25.0.5+8/test/jdk/sun/util/resources/TimeZone/Bug8139107.java | 7 openjdk-25-25.0.5+8/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java | 25 openjdk-25-25.0.5+8/test/jdk/sun/util/resources/cldr/Bug8202764.java | 21 openjdk-25-25.0.5+8/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java | 69 openjdk-25-25.0.5+8/test/jdk/tools/jar/JarExtractTest.java | 64 openjdk-25-25.0.5+8/test/jdk/tools/jlink/plugins/DefaultStripDebugPluginTest.java | 38 openjdk-25-25.0.5+8/test/jdk/tools/jlink/plugins/StripParameterNamesTest.java | 224 + openjdk-25-25.0.5+8/test/langtools/TEST.ROOT | 2 openjdk-25-25.0.5+8/test/langtools/jdk/jshell/LocalExecutionInstrumentationCHRTest.java | 64 openjdk-25-25.0.5+8/test/langtools/jdk/jshell/RemoteAgentHandshakeTest.java | 128 openjdk-25-25.0.5+8/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java | 5 openjdk-25-25.0.5+8/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.java | 5 openjdk-25-25.0.5+8/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.out | 45 openjdk-25-25.0.5+8/test/lib-test/TEST.ROOT | 4 openjdk-25-25.0.5+8/test/lib/jdk/test/lib/Utils.java | 32 openjdk-25-25.0.5+8/test/lib/jdk/test/lib/cds/CDSAppTester.java | 4 openjdk-25-25.0.5+8/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java | 5 openjdk-25-25.0.5+8/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java | 26 openjdk-25-25.0.5+8/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java | 25 openjdk-25-25.0.5+8/test/lib/jdk/test/lib/json/JSONValue.java | 94 openjdk-25-25.0.5+8/test/lib/jdk/test/lib/security/DerUtils.java | 14 openjdk-25-25.0.5+8/test/lib/jdk/test/lib/threaddump/ThreadDump.java | 193 - openjdk-25-25.0.5+8/test/lib/jdk/test/lib/util/ZipUtils.java | 247 + openjdk-25-25.0.5+8/test/lib/jdk/test/whitebox/WhiteBox.java | 9 openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/java/security/SSLHandshake.java | 25 openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java | 110 openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java | 34 openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/jdk/incubator/vector/GatherOperationsBenchmark.java | 357 -- openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskCompareNotBenchmark.java | 220 + openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java | 55 671 files changed, 26474 insertions(+), 11260 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp3neib7fo/openjdk-25_25.0.4.1+1-1~deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp3neib7fo/openjdk-25_25.0.5+8-1~deb13u1.dsc: no acceptable signature found diff -Nru openjdk-25-25.0.4.1+1/.jcheck/conf openjdk-25-25.0.5+8/.jcheck/conf --- openjdk-25-25.0.4.1+1/.jcheck/conf 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/.jcheck/conf 2026-10-19 12:10:20.000000000 +0000 @@ -1,7 +1,7 @@ [general] project=jdk-updates jbs=JDK -version=25.0.4.1 +version=25.0.5 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists,copyright diff -Nru openjdk-25-25.0.4.1+1/debian/JB-jre-headless.overrides.in openjdk-25-25.0.5+8/debian/JB-jre-headless.overrides.in --- openjdk-25-25.0.4.1+1/debian/JB-jre-headless.overrides.in 2026-08-18 21:50:36.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/JB-jre-headless.overrides.in 2026-10-22 00:58:09.000000000 +0000 @@ -9,7 +9,6 @@ @basename@-jre-headless binary: debug-suffix-not-dbg # Upstream implementation -@basename@-jre-headless binary: exit-in-shared-library @basename@-jre-headless binary: spelling-error-in-binary # Override due to upstream copyright @@ -20,3 +19,7 @@ # override warning for the old mailing address in upstream copyright @basename@-jre-headless binary: old-fsf-address-in-copyright-file + +# https://bugs.openjdk.org/browse/JDK-6454213 - i386 openjdk libjvm.so includes +# code compiled with -fno-PIC. +@basename@-jre-headless binary: specific-address-in-shared-library [usr/lib/jvm/java-@RELEASE@-openjdk-i386/lib/zero/libjvm.so] diff -Nru openjdk-25-25.0.4.1+1/debian/JB-jre-zero.overrides.in openjdk-25-25.0.5+8/debian/JB-jre-zero.overrides.in --- openjdk-25-25.0.4.1+1/debian/JB-jre-zero.overrides.in 2026-08-18 21:50:36.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/JB-jre-zero.overrides.in 2026-10-22 00:58:09.000000000 +0000 @@ -3,7 +3,6 @@ @basename@-jre-zero binary: unstripped-binary-or-object # Upstream implementation -@basename@-jre-zero binary: exit-in-shared-library @basename@-jre-zero binary: spelling-error-in-binary # repeated lib due to upstream implementation directory layout diff -Nru openjdk-25-25.0.4.1+1/debian/JB-testsupport.overrides.in openjdk-25-25.0.5+8/debian/JB-testsupport.overrides.in --- openjdk-25-25.0.4.1+1/debian/JB-testsupport.overrides.in 2026-08-18 21:23:33.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/JB-testsupport.overrides.in 2026-10-22 00:58:09.000000000 +0000 @@ -1,2 +1,6 @@ # servicability tests doing symbol lookups -@basename@-testsupport: unstripped-binary-or-object +@basename@-testsupport binary: unstripped-binary-or-object + +# https://bugs.openjdk.org/browse/JDK-6454213 - i386 openjdk libjvm.so includes +# code compiled with -fno-PIC. +@basename@-testsupport binary: specific-address-in-shared-library [usr/lib/jvm/java-@RELEASE@-openjdk-i386/testsuite/hotspot/gtest/zero/libjvm.so] diff -Nru openjdk-25-25.0.4.1+1/debian/changelog openjdk-25-25.0.5+8/debian/changelog --- openjdk-25-25.0.4.1+1/debian/changelog 2026-08-21 21:53:08.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/changelog 2026-10-24 19:36:15.000000000 +0000 @@ -1,8 +1,107 @@ -openjdk-25 (25.0.4.1+1-1~deb13u1) trixie-security; urgency=medium +openjdk-25 (25.0.5+8-1~deb13u1) trixie-security; urgency=medium * Rebuild for trixie - -- Moritz Muehlenhoff Fri, 21 Aug 2026 23:53:08 +0200 + -- Moritz Muehlenhoff Sat, 24 Oct 2026 21:36:15 +0200 + +openjdk-25 (25.0.5+8-1) unstable; urgency=medium + + * OpenJDK 25.0.5 release, build 8. + - CVEs: + + CVE-2026-91415 + + CVE-2026-91398 + + CVE-2026-91382 + + CVE-2026-91411 + + CVE-2026-83395 + + CVE-2026-87294 + + CVE-2026-91394 + + CVE-2026-87290 + + CVE-2026-83387 + + CVE-2026-91462 + + CVE-2026-83374 + + CVE-2026-91410 + + CVE-2026-87291 + + CVE-2026-91332 + + CVE-2026-91451 + + CVE-2026-91373 + + CVE-2026-83380 + + CVE-2026-83400 + + CVE-2026-91463 + + CVE-2026-91464 + + CVE-2026-91453 + + CVE-2026-91452 + + CVE-2026-91418 + + CVE-2026-83378 + + CVE-2026-91487 + + CVE-2026-83381 + + CVE-2026-91374 + + CVE-2026-91375 + + CVE-2026-91379 + + CVE-2026-91380 + + CVE-2026-87255 + + CVE-2026-91333 + + CVE-2026-91334 + + CVE-2026-87367 + + CVE-2026-87292 + + CVE-2026-83376 + + CVE-2026-91461 + + CVE-2026-91397 + + CVE-2026-91400 + + CVE-2026-91335 + * d/{man,watch}: Renegerate. + + -- Vladimir Petko Thu, 22 Oct 2026 13:58:38 +1300 + +openjdk-25 (25.0.5~7ea-2) unstable; urgency=medium + + [ Vladimir Petko ] + * d/changelog: Fix typo in 25.0.5~7ea-1 changelog. + * d/rules: Fix compilation flags for Ubuntu backports: do not override + C and C++ maintainer append flags on jammy and noble S390x with the + workaround. + * d/rules: Link with -latomic for jammy and focal on riscv64 + to resolve ftbfs. + * d/t: Add loong64 specific problemlists. + + [ Reuben Roessler ] + * d/p/jdk-8384505.diff: Account for all jtreg-based frames in stack + walk test (JDK-8384505). + + -- Vladimir Petko Thu, 08 Oct 2026 19:49:32 +1300 + +openjdk-25 (25.0.5~7ea-1) unstable; urgency=medium + + * OpenJDK 25.0.5 snapshot, build 7. + * Cherry-pick upstream patches to resolve FFM font rendering crash + and memory leak (LP: #2155650): + - d/p/jdk-8337853.diff: Temporary directory was filling up + with the temporary font files. + - d/p/jdk-8371066.diff: Remove unused classes so that other font patches + apply cleanly. + - d/p/jdk-8378603.diff: libfontmanager FFM was using mismatched free + and malloc, when overridden with LD_LIBRARY_PRELOAD. + - d/p/jdk-8378607.diff: GlyphLayout cache prevented Fonts from being + garbage collected. + - d/p/jdk-8378615.diff: FFM call stub was holding global JNI reference + to the font. + * d/rules: add --with-external-symbols-in-bundles=full configure + option (JDK-8373246). + * d/B-jre-*.overrides.in: Drop exit-in-shared-library lintian + override. + + -- Vladimir Petko Thu, 24 Sep 2026 19:52:19 +1200 + +openjdk-25 (25.0.5~6ea-1) unstable; urgency=medium + + * OpenJDK 25.0.5 snapshot, build 6. + * d/JB-{jre-headless,testsuport}.overrides.in: suppress specific- + address-in-shared-library for i386 (JDK-6454213). + * d/rules: disable tree-slp-vectorize for Ubuntu S390x builds (LP: + #2095441). Add workaround for Launchpad C2 crash. + * Regenerate man pages and control files. + * d/p/jdk-8388170.diff: Refresh patch. + + -- Vladimir Petko Wed, 16 Sep 2026 08:57:18 +1200 openjdk-25 (25.0.4.1+1-1) unstable; urgency=medium diff -Nru openjdk-25-25.0.4.1+1/debian/control openjdk-25-25.0.5+8/debian/control --- openjdk-25-25.0.4.1+1/debian/control 2026-08-21 21:53:08.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/control 2026-10-24 19:36:02.000000000 +0000 @@ -7,7 +7,7 @@ m4, lsb-release, zip, unzip, sharutils, gawk, cpio, procps, wdiff, pkgconf, fastjar (>= 2:0.96-0ubuntu2), time, strip-nondeterminism, debugedit (>= 4.16), - jtreg8 (>= 8+2~) , libtestng7-java , xvfb , xauth , xfonts-base , libgl1-mesa-dri [!x32] , xfwm4 , x11-xkb-utils , dbus-daemon , libasmtools-java , xvfb , + jtreg8 (>= 8.2.1+1~) , libtestng7-java , xvfb , xauth , xfonts-base , libgl1-mesa-dri [!x32] , xfwm4 , x11-xkb-utils , dbus-daemon , libasmtools-java , xvfb , autoconf, automake, ant, ant-optional, g++-14 , openjdk-25-jdk-headless:native | openjdk-24-jdk-headless:native, @@ -144,7 +144,7 @@ Multi-Arch: same Depends: openjdk-25-jdk (= ${binary:Version}), build-essential, xfwm4, xvfb, dbus-daemon, libatk-wrapper-java, - libatk-wrapper-java-jni, jtreg8 (>= 8+2~), libtestng7-java, + libatk-wrapper-java-jni, jtreg8 (>= 8.2.1+1~), libtestng7-java, ${shlibs:Depends}, ${misc:Depends} Description: Java runtime based on OpenJDK (regression test support) diff -Nru openjdk-25-25.0.4.1+1/debian/man/jar.1 openjdk-25-25.0.5+8/debian/man/jar.1 --- openjdk-25-25.0.4.1+1/debian/man/jar.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jar.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JAR" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JAR" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jar \- create an archive for classes and resources, and manipulate or restore individual classes or resources from an archive diff -Nru openjdk-25-25.0.4.1+1/debian/man/jarsigner.1 openjdk-25-25.0.5+8/debian/man/jarsigner.1 --- openjdk-25-25.0.4.1+1/debian/man/jarsigner.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jarsigner.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,7 +1,7 @@ '\" t -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JARSIGNER" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JARSIGNER" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jarsigner \- sign and verify Java Archive (JAR) files .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/java.1 openjdk-25-25.0.5+8/debian/man/java.1 --- openjdk-25-25.0.4.1+1/debian/man/java.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/java.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,7 +1,7 @@ '\" t -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JAVA" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JAVA" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME java \- launch a Java application .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/javac.1 openjdk-25-25.0.5+8/debian/man/javac.1 --- openjdk-25-25.0.4.1+1/debian/man/javac.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/javac.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JAVAC" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JAVAC" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME javac \- read Java declarations and compile them into class files .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/javadoc.1 openjdk-25-25.0.5+8/debian/man/javadoc.1 --- openjdk-25-25.0.4.1+1/debian/man/javadoc.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/javadoc.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JAVADOC" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JAVADOC" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME javadoc \- generate HTML pages of API documentation from Java source files diff -Nru openjdk-25-25.0.4.1+1/debian/man/javap.1 openjdk-25-25.0.5+8/debian/man/javap.1 --- openjdk-25-25.0.4.1+1/debian/man/javap.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/javap.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JAVAP" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JAVAP" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME javap \- disassemble one or more class files .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/jcmd.1 openjdk-25-25.0.5+8/debian/man/jcmd.1 --- openjdk-25-25.0.4.1+1/debian/man/jcmd.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jcmd.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JCMD" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JCMD" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jcmd \- send diagnostic command requests to a running Java Virtual Machine (JVM) diff -Nru openjdk-25-25.0.4.1+1/debian/man/jconsole.1 openjdk-25-25.0.5+8/debian/man/jconsole.1 --- openjdk-25-25.0.4.1+1/debian/man/jconsole.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jconsole.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JCONSOLE" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JCONSOLE" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jconsole \- start a graphical console to monitor and manage Java applications diff -Nru openjdk-25-25.0.4.1+1/debian/man/jdb.1 openjdk-25-25.0.5+8/debian/man/jdb.1 --- openjdk-25-25.0.4.1+1/debian/man/jdb.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jdb.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JDB" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JDB" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jdb \- find and fix bugs in Java platform programs .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/jdeprscan.1 openjdk-25-25.0.5+8/debian/man/jdeprscan.1 --- openjdk-25-25.0.4.1+1/debian/man/jdeprscan.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jdeprscan.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JDEPRSCAN" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JDEPRSCAN" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jdeprscan \- static analysis tool that scans a jar file (or some other aggregation of class files) for uses of deprecated API elements diff -Nru openjdk-25-25.0.4.1+1/debian/man/jdeps.1 openjdk-25-25.0.5+8/debian/man/jdeps.1 --- openjdk-25-25.0.4.1+1/debian/man/jdeps.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jdeps.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JDEPS" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JDEPS" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jdeps \- launch the Java class dependency analyzer .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/jfr.1 openjdk-25-25.0.5+8/debian/man/jfr.1 --- openjdk-25-25.0.4.1+1/debian/man/jfr.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jfr.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JFR" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JFR" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jfr \- print and manipulate Flight Recorder files .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/jhsdb.1 openjdk-25-25.0.5+8/debian/man/jhsdb.1 --- openjdk-25-25.0.4.1+1/debian/man/jhsdb.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jhsdb.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JHSDB" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JHSDB" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jhsdb \- attach to a Java process or launch a postmortem debugger to analyze the content of a core dump from a crashed Java Virtual Machine diff -Nru openjdk-25-25.0.4.1+1/debian/man/jinfo.1 openjdk-25-25.0.5+8/debian/man/jinfo.1 --- openjdk-25-25.0.4.1+1/debian/man/jinfo.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jinfo.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JINFO" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JINFO" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jinfo \- generate Java configuration information for a specified Java process diff -Nru openjdk-25-25.0.4.1+1/debian/man/jlink.1 openjdk-25-25.0.5+8/debian/man/jlink.1 --- openjdk-25-25.0.4.1+1/debian/man/jlink.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jlink.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JLINK" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JLINK" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jlink \- assemble and optimize a set of modules and their dependencies into a custom runtime image diff -Nru openjdk-25-25.0.4.1+1/debian/man/jmap.1 openjdk-25-25.0.5+8/debian/man/jmap.1 --- openjdk-25-25.0.4.1+1/debian/man/jmap.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jmap.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JMAP" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JMAP" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jmap \- print details of a specified process .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/jmod.1 openjdk-25-25.0.5+8/debian/man/jmod.1 --- openjdk-25-25.0.4.1+1/debian/man/jmod.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jmod.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JMOD" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JMOD" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jmod \- create JMOD files and list the content of existing JMOD files .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/jnativescan.1 openjdk-25-25.0.5+8/debian/man/jnativescan.1 --- openjdk-25-25.0.4.1+1/debian/man/jnativescan.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jnativescan.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JNATIVESCAN" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JNATIVESCAN" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jnativescan \- static analysis tool that scans one or more jar files for uses of native functionalities, such as restricted method calls or diff -Nru openjdk-25-25.0.4.1+1/debian/man/jpackage.1 openjdk-25-25.0.5+8/debian/man/jpackage.1 --- openjdk-25-25.0.4.1+1/debian/man/jpackage.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jpackage.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JPACKAGE" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JPACKAGE" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jpackage \- tool for packaging self\-contained Java applications. .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/jps.1 openjdk-25-25.0.5+8/debian/man/jps.1 --- openjdk-25-25.0.4.1+1/debian/man/jps.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jps.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JPS" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JPS" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jps \- list the instrumented JVMs on the target system .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/jrunscript.1 openjdk-25-25.0.5+8/debian/man/jrunscript.1 --- openjdk-25-25.0.4.1+1/debian/man/jrunscript.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jrunscript.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JRUNSCRIPT" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JRUNSCRIPT" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jrunscript \- run a command\-line script shell that supports interactive and batch modes diff -Nru openjdk-25-25.0.4.1+1/debian/man/jshell.1 openjdk-25-25.0.5+8/debian/man/jshell.1 --- openjdk-25-25.0.4.1+1/debian/man/jshell.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jshell.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,7 +1,7 @@ '\" t -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JSHELL" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JSHELL" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jshell \- interactively evaluate declarations, statements, and expressions of the Java programming language in a read\-eval\-print loop diff -Nru openjdk-25-25.0.4.1+1/debian/man/jstack.1 openjdk-25-25.0.5+8/debian/man/jstack.1 --- openjdk-25-25.0.4.1+1/debian/man/jstack.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jstack.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JSTACK" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JSTACK" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jstack \- print Java stack traces of Java threads for a specified Java process diff -Nru openjdk-25-25.0.4.1+1/debian/man/jstat.1 openjdk-25-25.0.5+8/debian/man/jstat.1 --- openjdk-25-25.0.4.1+1/debian/man/jstat.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jstat.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JSTAT" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JSTAT" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jstat \- monitor JVM statistics .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/jstatd.1 openjdk-25-25.0.5+8/debian/man/jstatd.1 --- openjdk-25-25.0.4.1+1/debian/man/jstatd.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jstatd.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JSTATD" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JSTATD" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jstatd \- monitor the creation and termination of instrumented Java HotSpot VMs diff -Nru openjdk-25-25.0.4.1+1/debian/man/jwebserver.1 openjdk-25-25.0.5+8/debian/man/jwebserver.1 --- openjdk-25-25.0.4.1+1/debian/man/jwebserver.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/jwebserver.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "JWEBSERVER" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "JWEBSERVER" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME jwebserver \- launch the Java Simple Web Server .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/keytool.1 openjdk-25-25.0.5+8/debian/man/keytool.1 --- openjdk-25-25.0.4.1+1/debian/man/keytool.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/keytool.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,7 +1,7 @@ '\" t -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "KEYTOOL" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "KEYTOOL" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME keytool \- a key and certificate management utility .SH SYNOPSIS diff -Nru openjdk-25-25.0.4.1+1/debian/man/rmiregistry.1 openjdk-25-25.0.5+8/debian/man/rmiregistry.1 --- openjdk-25-25.0.4.1+1/debian/man/rmiregistry.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/rmiregistry.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "RMIREGISTRY" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "RMIREGISTRY" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME rmiregistry \- create and start a remote object registry on the specified port on the current host diff -Nru openjdk-25-25.0.4.1+1/debian/man/serialver.1 openjdk-25-25.0.5+8/debian/man/serialver.1 --- openjdk-25-25.0.4.1+1/debian/man/serialver.1 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/man/serialver.1 2026-10-22 00:58:09.000000000 +0000 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 3.10.1 +.\" Automatically generated by Pandoc 3.11 .\" -.TH "SERIALVER" "1" "2026" "JDK 25.0.4.1" "JDK Commands" +.TH "SERIALVER" "1" "2026" "JDK 25.0.5" "JDK Commands" .SH NAME serialver \- return the \f[CR]serialVersionUID\f[R] for one or more classes in a form suitable for copying into an evolving class diff -Nru openjdk-25-25.0.4.1+1/debian/patches/jdk-8337853.diff openjdk-25-25.0.5+8/debian/patches/jdk-8337853.diff --- openjdk-25-25.0.4.1+1/debian/patches/jdk-8337853.diff 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/patches/jdk-8337853.diff 2026-10-22 00:58:09.000000000 +0000 @@ -0,0 +1,427 @@ +From 569d18fbe51a036629337c38230ae4892365a228 Mon Sep 17 00:00:00 2001 +From: Phil Race +Date: Mon, 23 Feb 2026 18:36:00 +0000 +Subject: [PATCH] 8337853: Remove SunLayoutEngineKey and SunLayoutEngineFactory + and its cache. + Remove layout engine cache that causes temporary directory to fill up with + the temporary font files. +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/openjdk-25/+bug/2155650 +Bug: https://bugs.openjdk.org/browse/JDK-8337853 +Origin: upstream, https://github.com/openjdk/jdk/commit/569d18fbe51a036629337c38230ae4892365a228 + +Reviewed-by: azvegint, dnguyen +--- + .../share/classes/java/awt/Font.java | 4 +- + .../sun/font/ExtendedTextSourceLabel.java | 4 +- + .../share/classes/sun/font/GlyphLayout.java | 114 ++--------------- + .../classes/sun/font/SunLayoutEngine.java | 118 ++---------------- + 4 files changed, 24 insertions(+), 216 deletions(-) + +--- a/src/java.desktop/share/classes/java/awt/Font.java ++++ b/src/java.desktop/share/classes/java/awt/Font.java +@@ -2709,7 +2709,7 @@ + int limit, + int flags) { + +- GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines ++ GlyphLayout gl = GlyphLayout.get(); + StandardGlyphVector gv = gl.layout(this, frc, text, + start, limit-start, flags, null); + GlyphLayout.done(gl); +--- a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java ++++ b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -329,7 +329,7 @@ + int start = source.getStart(); + int length = source.getLength(); + +- GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines ++ GlyphLayout gl = GlyphLayout.get(); + gv = gl.layout(font, frc, context, start, length, flags, null); // ??? use textsource + GlyphLayout.done(gl); + +--- a/src/java.desktop/share/classes/sun/font/GlyphLayout.java ++++ b/src/java.desktop/share/classes/sun/font/GlyphLayout.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2003, 2020, 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 +@@ -87,7 +87,6 @@ + // cached glyph layout data for reuse + private static volatile GlyphLayout cache; // reusable + +- private LayoutEngineFactory _lef; // set when get is called, unset when done is called + private TextRecord _textRecord; // the text we're working on, used by iterators + private ScriptRun _scriptRuns; // iterator over script runs + private FontRunIterator _fontRuns; // iterator over physical fonts in a composite +@@ -100,91 +99,10 @@ + private int _typo_flags; + private int _offset; + +- public static final class LayoutEngineKey { +- private Font2D font; +- private int script; +- private int lang; +- +- LayoutEngineKey() { +- } +- +- LayoutEngineKey(Font2D font, int script, int lang) { +- init(font, script, lang); +- } +- +- void init(Font2D font, int script, int lang) { +- this.font = font; +- this.script = script; +- this.lang = lang; +- } +- +- LayoutEngineKey copy() { +- return new LayoutEngineKey(font, script, lang); +- } +- +- Font2D font() { +- return font; +- } +- +- int script() { +- return script; +- } +- +- int lang() { +- return lang; +- } +- +- public boolean equals(Object rhs) { +- if (this == rhs) return true; +- if (rhs == null) return false; +- try { +- LayoutEngineKey that = (LayoutEngineKey)rhs; +- return this.script == that.script && +- this.lang == that.lang && +- this.font.equals(that.font); +- } +- catch (ClassCastException e) { +- return false; +- } +- } +- +- public int hashCode() { +- return script ^ lang ^ font.hashCode(); +- } +- } +- +- public static interface LayoutEngineFactory { +- /** +- * Given a font, script, and language, determine a layout engine to use. +- */ +- public LayoutEngine getEngine(Font2D font, int script, int lang); +- +- /** +- * Given a key, determine a layout engine to use. +- */ +- public LayoutEngine getEngine(LayoutEngineKey key); +- } +- +- public static interface LayoutEngine { +- /** +- * Given a strike descriptor, text, rtl flag, and starting point, append information about +- * glyphs, positions, and character indices to the glyphvector data, and advance the point. +- * +- * If the GVData does not have room for the glyphs, throws an IndexOutOfBoundsException and +- * leave pt and the gvdata unchanged. +- */ +- public void layout(FontStrikeDesc sd, float[] mat, float ptSize, int gmask, +- int baseIndex, TextRecord text, int typo_flags, Point2D.Float pt, GVData data); +- } +- + /** +- * Return a new instance of GlyphLayout, using the provided layout engine factory. +- * If null, the system layout engine factory will be used. ++ * Return a possibly recycled instance of GlyphLayout + */ +- public static GlyphLayout get(LayoutEngineFactory lef) { +- if (lef == null) { +- lef = SunLayoutEngine.instance(); +- } ++ public static GlyphLayout get() { + GlyphLayout result = null; + synchronized(GlyphLayout.class) { + if (cache != null) { +@@ -195,7 +113,6 @@ + if (result == null) { + result = new GlyphLayout(); + } +- result._lef = lef; + return result; + } + +@@ -204,7 +121,6 @@ + * of GlyphLayout objects. + */ + public static void done(GlyphLayout gl) { +- gl._lef = null; + cache = gl; // object reference assignment is thread safe, it says here... + } + +@@ -398,8 +314,6 @@ + } + } + +- int lang = -1; // default for now +- + Font2D font2D = FontUtilities.getFont2D(font); + if (font2D instanceof FontSubstitution) { + font2D = ((FontSubstitution)font2D).getCompositeFont2D(); +@@ -426,7 +340,7 @@ + } + int gmask = _fontRuns.getGlyphMask(); + int pos = _fontRuns.getPos(); +- nextEngineRecord(start, pos, script, lang, pfont, gmask); ++ nextEngineRecord(start, pos, script, pfont, gmask); + start = pos; + } + } +@@ -435,7 +349,7 @@ + while (_scriptRuns.next()) { + int limit = _scriptRuns.getScriptLimit(); + int script = _scriptRuns.getScriptCode(); +- nextEngineRecord(start, limit, script, lang, font2D, 0); ++ nextEngineRecord(start, limit, script, font2D, 0); + start = limit; + } + } +@@ -508,7 +422,7 @@ + this._gvdata.init(capacity); + } + +- private void nextEngineRecord(int start, int limit, int script, int lang, Font2D font, int gmask) { ++ private void nextEngineRecord(int start, int limit, int script, Font2D font, int gmask) { + EngineRecord er = null; + if (_ercount == _erecords.size()) { + er = new EngineRecord(); +@@ -516,7 +430,7 @@ + } else { + er = _erecords.get(_ercount); + } +- er.init(start, limit, font, script, lang, gmask); ++ er.init(start, limit, font, script, gmask); + ++_ercount; + } + +@@ -627,18 +541,18 @@ + private int limit; + private int gmask; + private int eflags; +- private LayoutEngineKey key; +- private LayoutEngine engine; ++ private Font2D font; ++ private int script; + + EngineRecord() { +- key = new LayoutEngineKey(); + } + +- void init(int start, int limit, Font2D font, int script, int lang, int gmask) { ++ void init(int start, int limit, Font2D font, int script, int gmask) { + this.start = start; + this.limit = limit; ++ this.font = font; ++ this.script = script; + this.gmask = gmask; +- this.key.init(font, script, lang); + this.eflags = 0; + + // only request canonical substitution if we have combining marks +@@ -659,14 +573,12 @@ + break; + } + } +- +- this.engine = _lef.getEngine(key); // flags? + } + + void layout() { + _textRecord.start = start; + _textRecord.limit = limit; +- engine.layout(_sd, _mat, ptSize, gmask, start - _offset, _textRecord, ++ SunLayoutEngine.layout(font, script, _sd, _mat, ptSize, gmask, start - _offset, _textRecord, + _typo_flags | eflags, _pt, _gvdata); + } + } +--- a/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java ++++ b/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java +@@ -1,4 +1,5 @@ + /* ++ * 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,126 +37,22 @@ + + import java.awt.geom.Point2D; + import java.lang.foreign.MemorySegment; +-import java.lang.ref.SoftReference; + import java.util.concurrent.ConcurrentHashMap; + import java.util.WeakHashMap; + +-/* +- * different ways to do this +- * 1) each physical font2d keeps a hashtable mapping scripts to layout +- * engines, we query and fill this cache. +- * 2) we keep a mapping independent of font using the key Most likely +- * few fonts will be used, so option 2 seems better +- * +- * Once we know which engine to use for a font, we always know, so we +- * shouldn't have to recheck each time we do layout. So the cache is +- * ok. +- * +- * Should we reuse engines? We could instantiate an engine for each +- * font/script pair. The engine would hold onto the table(s) from the +- * font that it needs. If we have multiple threads using the same +- * engine, we still need to keep the state separate, so the native +- * engines would still need to be allocated for each call, since they +- * keep their state in themselves. If they used the passed-in GVData +- * arrays directly (with some checks for space) then since each GVData +- * is different per thread, we could reuse the layout engines. This +- * still requires a separate layout engine per font, because of the +- * table state in the engine. If we pushed that out too and passed it +- * in with the native call as well, we'd be ok if the layout engines +- * keep all their process state on the stack, but I don't know if this +- * is true. Then we'd basically just be down to an engine index which +- * we pass into native and then invoke the engine code (now a +- * procedure call, not an object invocation) based on a switch on the +- * index. There would be only half a dozen engine objects then, not +- * potentially half a dozen per font. But we'd have to stack-allocate +- * some state that included the pointer to the required font tables. +- * +- * Seems for now that the way to do things is to come in with a +- * selector and the font. The selector indicates which engine to use, +- * the engine is stack allocated and initialized with the required +- * font tables (the selector indicates which). Then layout is called, +- * the contents are copied (or not), and the stack is destroyed on +- * exit. So the association is between the font/script (layout engine +- * desc) and one of a few permanent engine objects, which are +- * handed the key when they need to process something. In the native +- * case, the engine holds an index, and just passes it together with +- * the key info down to native. Some default cases are the 'default +- * layout' case that just runs the c2gmapper, this stays in java and +- * just uses the mapper from the font/strike. Another default case +- * might be the unicode arabic shaper, since this doesn't care about +- * the font (or script or lang?) it wouldn't need to extract this +- * data. It could be (yikes) ported back to java even to avoid +- * upcalls to check if the font supports a particular unicode +- * character. +- * +- * I'd expect that the majority of scripts use the default mapper for +- * a particular font. Loading the hashtable with 40 or so keys 30+ of +- * which all map to the same object is unfortunate. It might be worth +- * instead having a per-font list of 'scripts with non-default +- * engines', e.g. the factory has a hashtable mapping fonts to 'script +- * lists' (the factory has this since the design potentially has other +- * factories, though I admit there's no client for this yet and no +- * public api) and then the script list is queried for the script in +- * question. it can be preloaded at creation time with all the +- * scripts that don't have default engines-- either a list or a hash +- * table, so a null return from the table means 'default' and not 'i +- * don't know yet'. +- * +- * On the other hand, in most all cases the number of unique +- * script/font combinations will be small, so a flat hashtable should +- * suffice. +- * */ +-public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory { ++public final class SunLayoutEngine { ++ + static { + FontManagerNativeLibrary.load(); + } + +- private LayoutEngineKey key; +- +- private static LayoutEngineFactory instance; +- +- public static LayoutEngineFactory instance() { +- if (instance == null) { +- instance = new SunLayoutEngine(); +- } +- return instance; +- } +- + private SunLayoutEngine() { +- // actually a factory, key is null so layout cannot be called on it +- } +- +- public LayoutEngine getEngine(Font2D font, int script, int lang) { +- return getEngine(new LayoutEngineKey(font, script, lang)); +- } +- +- // !!! don't need this unless we have more than one sun layout engine... +- public LayoutEngine getEngine(LayoutEngineKey key) { +- ConcurrentHashMap cache = cacheref.get(); +- if (cache == null) { +- cache = new ConcurrentHashMap<>(); +- cacheref = new SoftReference<>(cache); +- } +- +- LayoutEngine e = cache.get(key); +- if (e == null) { +- LayoutEngineKey copy = key.copy(); +- e = new SunLayoutEngine(copy); +- cache.put(copy, e); +- } +- return e; +- } +- private SoftReference> cacheref = +- new SoftReference<>(null); +- +- private SunLayoutEngine(LayoutEngineKey key) { +- this.key = key; + } + + private static final WeakHashMap facePtr = + new WeakHashMap<>(); + +- private long getFacePtr(Font2D font2D) { ++ private static long getFacePtr(Font2D font2D) { + FaceRef ref; + synchronized (facePtr) { + ref = facePtr.computeIfAbsent(font2D, FaceRef::new); +@@ -170,17 +67,16 @@ + + } + +- public void layout(FontStrikeDesc desc, float[] mat, float ptSize, int gmask, ++ public static void layout(Font2D font, int script, FontStrikeDesc desc, float[] mat, float ptSize, int gmask, + int baseIndex, TextRecord tr, int typo_flags, + Point2D.Float pt, GVData data) { + +- Font2D font = key.font(); + FontStrike strike = font.getStrike(desc); + if (useFFM) { + MemorySegment face = HBShaper.getFace(font); + if (face != null) { + HBShaper.shape(font, strike, ptSize, mat, face, +- tr.text, data, key.script(), ++ tr.text, data, script, + tr.start, tr.limit, baseIndex, pt, + typo_flags, gmask); + } +@@ -188,7 +84,7 @@ + long pFace = getFacePtr(font); + if (pFace != 0) { + shape(font, strike, ptSize, mat, pFace, +- tr.text, data, key.script(), ++ tr.text, data, script, + tr.start, tr.limit, baseIndex, pt, + typo_flags, gmask); + } diff -Nru openjdk-25-25.0.4.1+1/debian/patches/jdk-8371066.diff openjdk-25-25.0.5+8/debian/patches/jdk-8371066.diff --- openjdk-25-25.0.4.1+1/debian/patches/jdk-8371066.diff 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/patches/jdk-8371066.diff 2026-10-22 00:58:09.000000000 +0000 @@ -0,0 +1,920 @@ +From 4042e821c6f582bf31201acb9f2d98d940383f1c Mon Sep 17 00:00:00 2001 +From: Daniel Gredler +Date: Wed, 12 Nov 2025 14:42:30 +0000 +Subject: [PATCH] 8371066: Remove unused class TextSourceLabel and associated + class hierarchy + This patch removes unused classes, it is added so that font memory leak fix + applies cleanly. +Bug: https://bugs.openjdk.org/browse/JDK-8371066 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/openjdk-25/+bug/2155650 +Origin: upstream, https://github.com/openjdk/jdk/commit/4042e821c6f582bf31201acb9f2d98d940383f1c +Reviewed-by: prr, psadhukhan +--- + .../share/classes/java/awt/font/TextLine.java | 2 +- + .../share/classes/sun/font/Decoration.java | 3 +- + .../classes/sun/font/ExtendedTextLabel.java | 146 ------------- + .../sun/font/ExtendedTextSourceLabel.java | 193 +++++++++++++++--- + .../share/classes/sun/font/TextLabel.java | 124 ----------- + .../classes/sun/font/TextLabelFactory.java | 40 +--- + .../classes/sun/font/TextSourceLabel.java | 173 ---------------- + 7 files changed, 169 insertions(+), 512 deletions(-) + delete mode 100644 src/java.desktop/share/classes/sun/font/ExtendedTextLabel.java + delete mode 100644 src/java.desktop/share/classes/sun/font/TextLabel.java + delete mode 100644 src/java.desktop/share/classes/sun/font/TextSourceLabel.java + +--- a/src/java.desktop/share/classes/java/awt/font/TextLine.java ++++ b/src/java.desktop/share/classes/java/awt/font/TextLine.java +@@ -1018,7 +1018,7 @@ + } + + TextLineComponent nextComponent = +- factory.createExtended(font, cm, decorator, startPos, startPos + lmCount); ++ factory.createTextLabel(font, cm, decorator, startPos, startPos + lmCount); + + ++numComponents; + if (numComponents > components.length) { +--- a/src/java.desktop/share/classes/sun/font/Decoration.java ++++ b/src/java.desktop/share/classes/sun/font/Decoration.java +@@ -54,7 +54,8 @@ + /** + * This class handles underlining, strikethrough, and foreground and + * background styles on text. Clients simply acquire instances +- * of this class and hand them off to ExtendedTextLabels or GraphicComponents. ++ * of this class and hand them off to ExtendedTextSourceLabels or ++ * GraphicComponents. + */ + public class Decoration { + +--- a/src/java.desktop/share/classes/sun/font/ExtendedTextLabel.java ++++ /dev/null +@@ -1,146 +0,0 @@ +-/* +- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved. +- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +- * +- * This code is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 only, as +- * published by the Free Software Foundation. Oracle designates this +- * particular file as subject to the "Classpath" exception as provided +- * by Oracle in the LICENSE file that accompanied this code. +- * +- * This code is distributed in the hope that it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +- * version 2 for more details (a copy is included in the LICENSE file that +- * accompanied this code). +- * +- * You should have received a copy of the GNU General Public License version +- * 2 along with this work; if not, write to the Free Software Foundation, +- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +- * or visit www.oracle.com if you need additional information or have any +- * questions. +- */ +-/* +- * +- * (C) Copyright IBM Corp. 1998-2003- All Rights Reserved. +- */ +- +-package sun.font; +- +-import java.awt.Font; +- +-import java.awt.font.GlyphJustificationInfo; +-import java.awt.font.LineMetrics; +- +-import java.awt.geom.Point2D; +-import java.awt.geom.Rectangle2D; +- +-/** +- * An extension of TextLabel that maintains information +- * about characters. +- */ +- +-public abstract class ExtendedTextLabel extends TextLabel +- implements TextLineComponent{ +- /** +- * Return the number of characters represented by this label. +- */ +- public abstract int getNumCharacters(); +- +- /** +- * Return the line metrics for all text in this label. +- */ +- public abstract CoreMetrics getCoreMetrics(); +- +- /** +- * Return the x location of the character at the given logical index. +- */ +- public abstract float getCharX(int logicalIndex); +- +- /** +- * Return the y location of the character at the given logical index. +- */ +- public abstract float getCharY(int logicalIndex); +- +- /** +- * Return the advance of the character at the given logical index. +- */ +- public abstract float getCharAdvance(int logicalIndex); +- +- /** +- * Return the visual bounds of the character at the given logical index. +- * This bounds encloses all the pixels of the character when the label is rendered +- * at x, y. +- */ +- public abstract Rectangle2D getCharVisualBounds(int logicalIndex, float x, float y); +- +- /** +- * Return the visual index of the character at the given logical index. +- */ +- public abstract int logicalToVisual(int logicalIndex); +- +- /** +- * Return the logical index of the character at the given visual index. +- */ +- public abstract int visualToLogical(int visualIndex); +- +- /** +- * Return the logical index of the character, starting with the character at +- * logicalStart, whose accumulated advance exceeds width. If the advances of +- * all characters do not exceed width, return getNumCharacters. If width is +- * less than zero, return logicalStart - 1. +- */ +- public abstract int getLineBreakIndex(int logicalStart, float width); +- +- /** +- * Return the accumulated advances of all characters between logicalStart and +- * logicalLimit. +- */ +- public abstract float getAdvanceBetween(int logicalStart, int logicalLimit); +- +- /** +- * Return whether a caret can exist on the leading edge of the +- * character at offset. If the character is part of a ligature +- * (for example) a caret may not be appropriate at offset. +- */ +- public abstract boolean caretAtOffsetIsValid(int offset); +- +- /** +- * A convenience overload of getCharVisualBounds that defaults the label origin +- * to 0, 0. +- */ +- public Rectangle2D getCharVisualBounds(int logicalIndex) { +- return getCharVisualBounds(logicalIndex, 0, 0); +- } +- +- public abstract TextLineComponent getSubset(int start, int limit, int dir); +- +- /** +- * Return the number of justification records this uses. +- */ +- public abstract int getNumJustificationInfos(); +- +- /** +- * Return GlyphJustificationInfo objects for the characters between +- * charStart and charLimit, starting at offset infoStart. Infos +- * will be in visual order. All positions between infoStart and +- * getNumJustificationInfos will be set. If a position corresponds +- * to a character outside the provided range, it is set to null. +- */ +- public abstract void getJustificationInfos(GlyphJustificationInfo[] infos, int infoStart, int charStart, int charLimit); +- +- /** +- * Apply deltas to the data in this component, starting at offset +- * deltaStart, and return the new component. There are two floats +- * for each justification info, for a total of 2 * getNumJustificationInfos. +- * The first delta is the left adjustment, the second is the right +- * adjustment. +- *

+- * If flags[0] is true on entry, rejustification is allowed. If +- * the new component requires rejustification (ligatures were +- * formed or split), flags[0] will be set on exit. +- */ +- public abstract TextLineComponent applyJustificationDeltas(float[] deltas, int deltaStart, boolean[] flags); +-} +--- a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java ++++ b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java +@@ -46,32 +46,35 @@ + + import java.util.Map; + +-/** +- * Default implementation of ExtendedTextLabel. +- */ +- + // {jbr} I made this class package-private to keep the + // Decoration.Label API package-private. + +-/* public */ +-class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.Label { ++/** ++ * A label. ++ * Visual bounds is a rect that encompasses the entire rendered area. ++ * Logical bounds is a rect that defines how to position this next ++ * to other objects. ++ * 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 { + +- TextSource source; +- private Decoration decorator; ++ private final TextSource source; ++ private final Decoration decorator; + + // caches + private Font font; + private AffineTransform baseTX; + private CoreMetrics cm; + +- Rectangle2D lb; +- Rectangle2D ab; +- Rectangle2D vb; +- Rectangle2D ib; +- StandardGlyphVector gv; +- float[] charinfo; ++ private Rectangle2D lb; ++ private Rectangle2D ab; ++ private Rectangle2D vb; ++ private Rectangle2D ib; ++ private StandardGlyphVector gv; ++ private float[] charinfo; + +- float advTracking; ++ private float advTracking; + + /** + * Create from a TextSource. +@@ -116,13 +119,11 @@ + advTracking = font.getSize() * AttributeValues.getTracking(atts); + } + +- +- // TextLabel API +- +- public Rectangle2D getLogicalBounds() { +- return getLogicalBounds(0, 0); +- } +- ++ /** ++ * Return a rectangle that corresponds to the logical bounds of the text ++ * when this label is rendered at x, y. ++ * This rectangle is used when positioning text next to other text. ++ */ + public Rectangle2D getLogicalBounds(float x, float y) { + if (lb == null) { + lb = createLogicalBounds(); +@@ -133,13 +134,16 @@ + (float)lb.getHeight()); + } + +- public float getAdvance() { +- if (lb == null) { +- lb = createLogicalBounds(); +- } +- return (float)lb.getWidth(); ++ public float getAdvance() { ++ if (lb == null) { ++ lb = createLogicalBounds(); + } ++ return (float)lb.getWidth(); ++ } + ++ /** ++ * Return a rectangle that surrounds the text outline when this label is rendered at x, y. ++ */ + public Rectangle2D getVisualBounds(float x, float y) { + if (vb == null) { + vb = decorator.getVisualBounds(this); +@@ -150,6 +154,12 @@ + (float)vb.getHeight()); + } + ++ /** ++ * Return a rectangle that corresponds to the alignment bounds of the text ++ * when this label is rendered at x, y. This rectangle is used when positioning text next ++ * to a margin. It differs from the logical bounds in that it does not include leading or ++ * trailing whitespace. ++ */ + public Rectangle2D getAlignBounds(float x, float y) { + if (ab == null) { + ab = createAlignBounds(); +@@ -161,6 +171,10 @@ + + } + ++ /** ++ * Return a rectangle that corresponds to the logical bounds of the text, adjusted ++ * to angle the leading and trailing edges by the italic angle. ++ */ + public Rectangle2D getItalicBounds(float x, float y) { + if (ib == null) { + ib = createItalicBounds(); +@@ -189,6 +203,9 @@ + return getGV().getOutline(x, y); + } + ++ /** ++ * Return an outline of the characters in the label when rendered at x, y. ++ */ + public Shape getOutline(float x, float y) { + return decorator.getOutline(this, x, y); + } +@@ -197,11 +214,64 @@ + g.drawGlyphVector(getGV(), x, y); + } + ++ /** ++ * Render the label at x, y in the graphics. ++ */ + public void draw(Graphics2D g, float x, float y) { + decorator.drawTextAndDecorations(this, g, x, y); + } + + /** ++ * A convenience method that returns the visual bounds when rendered at 0, 0. ++ */ ++ public Rectangle2D getVisualBounds() { ++ return getVisualBounds(0f, 0f); ++ } ++ ++ /** ++ * A convenience method that returns the logical bounds when rendered at 0, 0. ++ */ ++ public Rectangle2D getLogicalBounds() { ++ return getLogicalBounds(0f, 0f); ++ } ++ ++ /** ++ * A convenience method that returns the align bounds when rendered at 0, 0. ++ */ ++ public Rectangle2D getAlignBounds() { ++ return getAlignBounds(0f, 0f); ++ } ++ ++ /** ++ * A convenience method that returns the italic bounds when rendered at 0, 0. ++ */ ++ public Rectangle2D getItalicBounds() { ++ return getItalicBounds(0f, 0f); ++ } ++ ++ /** ++ * A convenience method that returns the outline when rendered at 0, 0. ++ */ ++ public Shape getOutline() { ++ return getOutline(0f, 0f); ++ } ++ ++ /** ++ * A convenience method that renders the label at 0, 0. ++ */ ++ public void draw(Graphics2D g) { ++ draw(g, 0f, 0f); ++ } ++ ++ /** ++ * A convenience overload of getCharVisualBounds that defaults the label origin ++ * to 0, 0. ++ */ ++ public Rectangle2D getCharVisualBounds(int logicalIndex) { ++ return getCharVisualBounds(logicalIndex, 0, 0); ++ } ++ ++ /** + * The logical bounds extends from the origin of the glyphvector to the + * position at which a following glyphvector's origin should be placed. + * We always assume glyph vectors are rendered from left to right, so +@@ -336,8 +406,6 @@ + return gv; + } + +- // ExtendedTextLabel API +- + private static final int posx = 0, + posy = 1, + advx = 2, +@@ -348,14 +416,23 @@ + vish = 7; + private static final int numvals = 8; + ++ /** ++ * Return the number of characters represented by this label. ++ */ + public int getNumCharacters() { + return source.getLength(); + } + ++ /** ++ * Return the line metrics for all text in this label. ++ */ + public CoreMetrics getCoreMetrics() { + return cm; + } + ++ /** ++ * Return the x location of the character at the given logical index. ++ */ + public float getCharX(int index) { + validate(index); + float[] charinfo = getCharinfo(); +@@ -367,6 +444,9 @@ + } + } + ++ /** ++ * Return the y location of the character at the given logical index. ++ */ + public float getCharY(int index) { + validate(index); + float[] charinfo = getCharinfo(); +@@ -378,6 +458,9 @@ + } + } + ++ /** ++ * Return the advance of the character at the given logical index. ++ */ + public float getCharAdvance(int index) { + validate(index); + float[] charinfo = getCharinfo(); +@@ -403,6 +486,11 @@ + charinfo[index + vish]); + } + ++ /** ++ * Return the visual bounds of the character at the given logical index. ++ * This bounds encloses all the pixels of the character when the label is rendered ++ * at x, y. ++ */ + public Rectangle2D getCharVisualBounds(int index, float x, float y) { + + Rectangle2D bounds = decorator.getCharVisualBounds(this, index); +@@ -470,16 +558,28 @@ + } + */ + ++ /** ++ * Return the visual index of the character at the given logical index. ++ */ + public int logicalToVisual(int logicalIndex) { + validate(logicalIndex); + return l2v(logicalIndex); + } + ++ /** ++ * Return the logical index of the character at the given visual index. ++ */ + public int visualToLogical(int visualIndex) { + validate(visualIndex); + return v2l(visualIndex); + } + ++ /** ++ * Return the logical index of the character, starting with the character at ++ * logicalStart, whose accumulated advance exceeds width. If the advances of ++ * all characters do not exceed width, return getNumCharacters. If width is ++ * less than zero, return logicalStart - 1. ++ */ + public int getLineBreakIndex(int start, float width) { + final float epsilon = 0.005f; + +@@ -504,6 +604,10 @@ + return start; + } + ++ /** ++ * Return the accumulated advances of all characters between logicalStart and ++ * logicalLimit. ++ */ + public float getAdvanceBetween(int start, int limit) { + float a = 0f; + +@@ -523,6 +627,11 @@ + return a; + } + ++ /** ++ * Return whether a caret can exist on the leading edge of the ++ * character at offset. If the character is part of a ligature ++ * (for example) a caret may not be appropriate at offset. ++ */ + public boolean caretAtOffsetIsValid(int offset) { + // REMIND: improve this implementation + +@@ -912,15 +1021,20 @@ + return sb.toString(); + } + +- //public static ExtendedTextLabel create(TextSource source) { +- // return new ExtendedTextSourceLabel(source); +- //} +- ++ /** ++ * Return the number of justification records this uses. ++ */ + public int getNumJustificationInfos() { + return getGV().getNumGlyphs(); + } + +- ++ /** ++ * Return GlyphJustificationInfo objects for the characters between ++ * charStart and charLimit, starting at offset infoStart. Infos ++ * will be in visual order. All positions between infoStart and ++ * getNumJustificationInfos will be set. If a position corresponds ++ * to a character outside the provided range, it is set to null. ++ */ + public void getJustificationInfos(GlyphJustificationInfo[] infos, int infoStart, int charStart, int charLimit) { + // This simple implementation only uses spaces for justification. + // Since regular characters aren't justified, we don't need to deal with +@@ -992,6 +1106,17 @@ + } + } + ++ /** ++ * Apply deltas to the data in this component, starting at offset ++ * deltaStart, and return the new component. There are two floats ++ * for each justification info, for a total of 2 * getNumJustificationInfos. ++ * The first delta is the left adjustment, the second is the right ++ * adjustment. ++ *

++ * If flags[0] is true on entry, rejustification is allowed. If ++ * the new component requires rejustification (ligatures were ++ * formed or split), flags[0] will be set on exit. ++ */ + public TextLineComponent applyJustificationDeltas(float[] deltas, int deltaStart, boolean[] flags) { + + // when we justify, we need to adjust the charinfo since spaces +--- a/src/java.desktop/share/classes/sun/font/TextLabel.java ++++ /dev/null +@@ -1,124 +0,0 @@ +-/* +- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved. +- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +- * +- * This code is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 only, as +- * published by the Free Software Foundation. Oracle designates this +- * particular file as subject to the "Classpath" exception as provided +- * by Oracle in the LICENSE file that accompanied this code. +- * +- * This code is distributed in the hope that it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +- * version 2 for more details (a copy is included in the LICENSE file that +- * accompanied this code). +- * +- * You should have received a copy of the GNU General Public License version +- * 2 along with this work; if not, write to the Free Software Foundation, +- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +- * or visit www.oracle.com if you need additional information or have any +- * questions. +- */ +-/* +- * +- * (C) Copyright IBM Corp. 1998-2003 All Rights Reserved +- */ +- +-package sun.font; +- +-import java.awt.Graphics2D; +-import java.awt.Shape; +- +-import java.awt.geom.Rectangle2D; +- +-/** +- * A label. +- * Visual bounds is a rect that encompasses the entire rendered area. +- * Logical bounds is a rect that defines how to position this next +- * to other objects. +- * Align bounds is a rect that defines how to align this to margins. +- * it generally allows some overhang that logical bounds would prevent. +- */ +-public abstract class TextLabel { +- +- /** +- * Return a rectangle that surrounds the text outline when this label is rendered at x, y. +- */ +- public abstract Rectangle2D getVisualBounds(float x, float y); +- +- /** +- * Return a rectangle that corresponds to the logical bounds of the text +- * when this label is rendered at x, y. +- * This rectangle is used when positioning text next to other text. +- */ +- public abstract Rectangle2D getLogicalBounds(float x, float y); +- +- /** +- * Return a rectangle that corresponds to the alignment bounds of the text +- * when this label is rendered at x, y. This rectangle is used when positioning text next +- * to a margin. It differs from the logical bounds in that it does not include leading or +- * trailing whitespace. +- */ +- public abstract Rectangle2D getAlignBounds(float x, float y); +- +- /** +- * Return a rectangle that corresponds to the logical bounds of the text, adjusted +- * to angle the leading and trailing edges by the italic angle. +- */ +- public abstract Rectangle2D getItalicBounds(float x, float y); +- +- /** +- * Return an outline of the characters in the label when rendered at x, y. +- */ +- public abstract Shape getOutline(float x, float y); +- +- /** +- * Render the label at x, y in the graphics. +- */ +- public abstract void draw(Graphics2D g, float x, float y); +- +- /** +- * A convenience method that returns the visual bounds when rendered at 0, 0. +- */ +- public Rectangle2D getVisualBounds() { +- return getVisualBounds(0f, 0f); +- } +- +- /** +- * A convenience method that returns the logical bounds when rendered at 0, 0. +- */ +- public Rectangle2D getLogicalBounds() { +- return getLogicalBounds(0f, 0f); +- } +- +- /** +- * A convenience method that returns the align bounds when rendered at 0, 0. +- */ +- public Rectangle2D getAlignBounds() { +- return getAlignBounds(0f, 0f); +- } +- +- /** +- * A convenience method that returns the italic bounds when rendered at 0, 0. +- */ +- public Rectangle2D getItalicBounds() { +- return getItalicBounds(0f, 0f); +- } +- +- /** +- * A convenience method that returns the outline when rendered at 0, 0. +- */ +- public Shape getOutline() { +- return getOutline(0f, 0f); +- } +- +- /** +- * A convenience method that renders the label at 0, 0. +- */ +- public void draw(Graphics2D g) { +- draw(g, 0f, 0f); +- } +-} +--- a/src/java.desktop/share/classes/sun/font/TextLabelFactory.java ++++ b/src/java.desktop/share/classes/sun/font/TextLabelFactory.java +@@ -42,8 +42,7 @@ + * @see Font + * @see FontRenderContext + * @see java.awt.font.GlyphVector +- * @see TextLabel +- * @see ExtendedTextLabel ++ * @see ExtendedTextSourceLabel + * @see Bidi + * @see java.awt.font.TextLayout + */ +@@ -100,7 +99,7 @@ + } + + /** +- * Create an extended glyph array for the text between start and limit. ++ * Create a glyph array for the text between start and limit. + * + * @param font the font to use to generate glyphs and character positions. + * @param start the start of the subrange for which to create the glyph array +@@ -113,11 +112,11 @@ + * at start. Clients should ensure that all text between start and limit + * has the same bidi level for the current line. + */ +- public ExtendedTextLabel createExtended(Font font, +- CoreMetrics lm, +- Decoration decorator, +- int start, +- int limit) { ++ public ExtendedTextSourceLabel createTextLabel(Font font, ++ CoreMetrics lm, ++ Decoration decorator, ++ int start, ++ int limit) { + + if (start >= limit || start < lineStart || limit > lineLimit) { + throw new IllegalArgumentException("bad start: " + start + " or limit: " + limit); +@@ -133,28 +132,4 @@ + return new ExtendedTextSourceLabel(source, decorator); + } + +- /** +- * Create a simple glyph array for the text between start and limit. +- * +- * @param font the font to use to generate glyphs and character positions. +- * @param start the start of the subrange for which to create the glyph array +- * @param limit the limit of the subrange for which to create glyph array +- */ +- public TextLabel createSimple(Font font, +- CoreMetrics lm, +- int start, +- int limit) { +- +- if (start >= limit || start < lineStart || limit > lineLimit) { +- throw new IllegalArgumentException("bad start: " + start + " or limit: " + limit); +- } +- +- int level = lineBidi == null ? 0 : lineBidi.getLevelAt(start - lineStart); +- int linedir = (lineBidi == null || lineBidi.baseIsLeftToRight()) ? 0 : 1; +- int layoutFlags = flags & ~0x9; // remove bidi, line direction flags +- if ((level & 0x1) != 0) layoutFlags |= 1; // rtl +- if ((linedir & 0x1) != 0) layoutFlags |= 8; // line rtl +- TextSource source = new StandardTextSource(text, start, limit - start, lineStart, lineLimit - lineStart, level, layoutFlags, font, frc, lm); +- return new TextSourceLabel(source); +- } + } +--- a/src/java.desktop/share/classes/sun/font/TextSourceLabel.java ++++ /dev/null +@@ -1,173 +0,0 @@ +-/* +- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. +- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +- * +- * This code is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 only, as +- * published by the Free Software Foundation. Oracle designates this +- * particular file as subject to the "Classpath" exception as provided +- * by Oracle in the LICENSE file that accompanied this code. +- * +- * This code is distributed in the hope that it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +- * version 2 for more details (a copy is included in the LICENSE file that +- * accompanied this code). +- * +- * You should have received a copy of the GNU General Public License version +- * 2 along with this work; if not, write to the Free Software Foundation, +- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +- * or visit www.oracle.com if you need additional information or have any +- * questions. +- */ +-/* +- * +- * (C) Copyright IBM Corp. 1998, 1999 - All Rights Reserved +- */ +- +-package sun.font; +- +-import java.awt.Font; +-import java.awt.Graphics2D; +-import java.awt.Rectangle; +-import java.awt.Shape; +-import java.awt.font.FontRenderContext; +-import java.awt.font.GlyphVector; +-import java.awt.geom.AffineTransform; +-import java.awt.geom.Rectangle2D; +- +-/** +- * Implementation of TextLabel based on String. +- */ +- +-public class TextSourceLabel extends TextLabel { +- TextSource source; +- +- // caches +- Rectangle2D lb; +- Rectangle2D ab; +- Rectangle2D vb; +- Rectangle2D ib; +- GlyphVector gv; +- +- public TextSourceLabel(TextSource source) { +- this(source, null, null, null); +- } +- +- public TextSourceLabel(TextSource source, Rectangle2D lb, Rectangle2D ab, GlyphVector gv) { +- this.source = source; +- +- this.lb = lb; +- this.ab = ab; +- this.gv = gv; +- } +- +- public TextSource getSource() { +- return source; +- } +- +- public final Rectangle2D getLogicalBounds(float x, float y) { +- if (lb == null) { +- lb = createLogicalBounds(); +- } +- return new Rectangle2D.Float((float)(lb.getX() + x), +- (float)(lb.getY() + y), +- (float)lb.getWidth(), +- (float)lb.getHeight()); +- } +- +- public final Rectangle2D getVisualBounds(float x, float y) { +- if (vb == null) { +- vb = createVisualBounds(); +- +- } +- return new Rectangle2D.Float((float)(vb.getX() + x), +- (float)(vb.getY() + y), +- (float)vb.getWidth(), +- (float)vb.getHeight()); +- } +- +- public final Rectangle2D getAlignBounds(float x, float y) { +- if (ab == null) { +- ab = createAlignBounds(); +- } +- return new Rectangle2D.Float((float)(ab.getX() + x), +- (float)(ab.getY() + y), +- (float)ab.getWidth(), +- (float)ab.getHeight()); +- } +- +- public Rectangle2D getItalicBounds(float x, float y) { +- if (ib == null) { +- ib = createItalicBounds(); +- } +- return new Rectangle2D.Float((float)(ib.getX() + x), +- (float)(ib.getY() + y), +- (float)ib.getWidth(), +- (float)ib.getHeight()); +- +- } +- +- public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) { +- return getGV().getPixelBounds(frc, x, y); // no cache +- } +- +- public AffineTransform getBaselineTransform() { +- Font font = source.getFont(); +- if (font.hasLayoutAttributes()) { +- return AttributeValues.getBaselineTransform(font.getAttributes()); +- } +- return null; +- } +- +- public Shape getOutline(float x, float y) { +- return getGV().getOutline(x, y); +- } +- +- public void draw(Graphics2D g, float x, float y) { +- g.drawGlyphVector(getGV(), x, y); +- } +- +- protected Rectangle2D createLogicalBounds() { +- return getGV().getLogicalBounds(); +- } +- +- protected Rectangle2D createVisualBounds() { +- return getGV().getVisualBounds(); +- } +- +- protected Rectangle2D createItalicBounds() { +- // !!! fix +- return getGV().getLogicalBounds(); +- } +- +- protected Rectangle2D createAlignBounds() { +- return createLogicalBounds(); +- } +- +- private GlyphVector getGV() { +- if (gv == null) { +- gv = createGV(); +- } +- +- return gv; +- } +- +- protected GlyphVector createGV() { +- Font font = source.getFont(); +- FontRenderContext frc = source.getFRC(); +- int flags = source.getLayoutFlags(); +- char[] context = source.getChars(); +- int start = source.getStart(); +- int length = source.getLength(); +- +- GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines +- StandardGlyphVector gv = gl.layout(font, frc, context, start, length, +- flags, null); // ??? use textsource +- GlyphLayout.done(gl); +- +- return gv; +- } +-} diff -Nru openjdk-25-25.0.4.1+1/debian/patches/jdk-8378603.diff openjdk-25-25.0.5+8/debian/patches/jdk-8378603.diff --- openjdk-25-25.0.4.1+1/debian/patches/jdk-8378603.diff 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/patches/jdk-8378603.diff 2026-10-22 00:58:09.000000000 +0000 @@ -0,0 +1,91 @@ +From 704efcb20dbe2f77e991b2343d5dccdf524882ba Mon Sep 17 00:00:00 2001 +From: Phil Race +Date: Mon, 27 Apr 2026 16:14:34 +0000 +Subject: [PATCH] 8378603: libfontmanager FFM path needs to use FFM to locate + both malloc and free + +Bug: https://bugs.openjdk.org/browse/JDK-8378603 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/openjdk-25/+bug/2155650 +Origin: upstream, https://github.com/openjdk/jdk/commit/704efcb20dbe2f77e991b2343d5dccdf524882ba +Reviewed-by: kizune, azvegint, jdv +--- + .../share/classes/sun/font/HBShaper.java | 11 +++++++++ + .../native/libfontmanager/hb-jdk-font-p.cc | 24 +++++++++++++++++-- + 2 files changed, 33 insertions(+), 2 deletions(-) + +diff --git a/src/java.desktop/share/classes/sun/font/HBShaper.java b/src/java.desktop/share/classes/sun/font/HBShaper.java +index dea8a9e22dd..1e0b918ce54 100644 +--- a/src/java.desktop/share/classes/sun/font/HBShaper.java ++++ b/src/java.desktop/share/classes/sun/font/HBShaper.java +@@ -174,6 +174,17 @@ private static VarHandle getVarHandle(StructLayout struct, String name) { + MethodHandle tmp1 = LINKER.downcallHandle(malloc_symbol, mallocDescriptor); + malloc_handle = tmp1; + ++ MemorySegment free_symbol = SYM_LOOKUP.findOrThrow("free"); ++ long free_address = free_symbol.address(); ++ FunctionDescriptor setFreeFnDescriptor = FunctionDescriptor.ofVoid(JAVA_LONG); ++ MemorySegment set_free = SYM_LOOKUP.findOrThrow("HBSetFreeFn"); ++ @SuppressWarnings("restricted") ++ MethodHandle set_free_handle = LINKER.downcallHandle(set_free, setFreeFnDescriptor); ++ try { ++ set_free_handle.invokeExact(free_address); ++ } catch (Throwable t) { ++ } ++ + FunctionDescriptor createFaceDescriptor = + FunctionDescriptor.of(ADDRESS, ADDRESS); + MemorySegment create_face_symbol = SYM_LOOKUP.findOrThrow("HBCreateFace"); +diff --git a/src/java.desktop/share/native/libfontmanager/hb-jdk-font-p.cc b/src/java.desktop/share/native/libfontmanager/hb-jdk-font-p.cc +index 590c273d151..1e5db4e0adf 100644 +--- a/src/java.desktop/share/native/libfontmanager/hb-jdk-font-p.cc ++++ b/src/java.desktop/share/native/libfontmanager/hb-jdk-font-p.cc +@@ -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 +@@ -174,6 +174,22 @@ static void _do_nothing(void) { + + typedef int (*GetTableDataFn) (int tag, char **dataPtr); + ++typedef void (*ffm_free_t) (void *ptr); ++ ++static ffm_free_t ffm_free_fn = NULL; ++ ++/* We pass the address of "free" which was obtained by FFM so that it matches ++ * the malloc found by FFM ++ */ ++#include ++static void ffmfree(void *ptr) { ++ if (ffm_free_fn != NULL) { ++ ffm_free_fn(ptr); ++ } else { ++ free(ptr); ++ } ++} ++ + static hb_blob_t * + reference_table(hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { + +@@ -200,11 +216,15 @@ reference_table(hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { + */ + return hb_blob_create((const char *)tableData, length, + HB_MEMORY_MODE_WRITABLE, +- tableData, free); ++ tableData, ffmfree); + } + + extern "C" { + ++JDKEXPORT void HBSetFreeFn(void *free_fn) { ++ ffm_free_fn = (ffm_free_t)free_fn; ++} ++ + JDKEXPORT hb_face_t* HBCreateFace(GetTableDataFn *get_data_upcall_fn) { + + hb_face_t *face = hb_face_create_for_tables(reference_table, get_data_upcall_fn, NULL); +-- +2.53.0 + diff -Nru openjdk-25-25.0.4.1+1/debian/patches/jdk-8378607.diff openjdk-25-25.0.5+8/debian/patches/jdk-8378607.diff --- openjdk-25-25.0.4.1+1/debian/patches/jdk-8378607.diff 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/patches/jdk-8378607.diff 2026-10-22 00:58:09.000000000 +0000 @@ -0,0 +1,89 @@ +From f3d7ca33d797c3475a4c31d612e7ed8f71d1f5b0 Mon Sep 17 00:00:00 2001 +From: Phil Race +Date: Sat, 28 Feb 2026 22:58:10 +0000 +Subject: [PATCH] 8378607: GlyphLayout cache can prevent Fonts from being GC'd +Bug: https://bugs.openjdk.org/browse/JDK-8378607 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/openjdk-25/+bug/2155650 +Origin: upstream, https://github.com/openjdk/jdk/commit/f3d7ca33d797c3475a4c31d612e7ed8f71d1f5b0 + +Reviewed-by: jdv, tr +--- + .../share/classes/sun/font/GlyphLayout.java | 26 +++++++++---------- + 1 file changed, 12 insertions(+), 14 deletions(-) + +diff --git a/src/java.desktop/share/classes/sun/font/GlyphLayout.java b/src/java.desktop/share/classes/sun/font/GlyphLayout.java +index df42cce344e..5bff127f143 100644 +--- a/src/java.desktop/share/classes/sun/font/GlyphLayout.java ++++ b/src/java.desktop/share/classes/sun/font/GlyphLayout.java +@@ -76,7 +76,7 @@ + import java.awt.geom.NoninvertibleTransformException; + import java.awt.geom.Point2D; + import java.util.ArrayList; +-import java.util.concurrent.ConcurrentHashMap; ++import java.util.WeakHashMap; + + import static java.lang.Character.*; + +@@ -125,18 +125,12 @@ public static void done(GlyphLayout gl) { + } + + private static final class SDCache { +- public Font key_font; +- public FontRenderContext key_frc; +- + public AffineTransform dtx; + public AffineTransform gtx; + public Point2D.Float delta; + public FontStrikeDesc sd; + + private SDCache(Font font, FontRenderContext frc) { +- key_font = font; +- key_frc = frc; +- + // !!! add getVectorTransform and hasVectorTransform to frc? then + // we could just skip this work... + +@@ -177,7 +171,7 @@ private SDCache(Font font, FontRenderContext frc) { + private static final Point2D.Float ZERO_DELTA = new Point2D.Float(); + + private static +- SoftReference> cacheRef; ++ SoftReference> cacheRef; + + private static final class SDKey { + private final Font font; +@@ -232,7 +226,7 @@ public static SDCache get(Font font, FontRenderContext frc) { + } + + SDKey key = new SDKey(font, frc); // garbage, yuck... +- ConcurrentHashMap cache = null; ++ WeakHashMap cache = null; + SDCache res = null; + if (cacheRef != null) { + cache = cacheRef.get(); +@@ -243,13 +237,17 @@ public static SDCache get(Font font, FontRenderContext frc) { + if (res == null) { + res = new SDCache(font, frc); + if (cache == null) { +- cache = new ConcurrentHashMap(10); ++ cache = new WeakHashMap(10); + cacheRef = new +- SoftReference>(cache); +- } else if (cache.size() >= 512) { +- cache.clear(); ++ SoftReference>(cache); ++ } else if (cache.size() >= 128) { ++ synchronized (SDCache.class) { ++ cache.clear(); ++ } ++ } ++ synchronized (SDCache.class) { ++ cache.put(key, res); + } +- cache.put(key, res); + } + return res; + } +-- +2.53.0 + diff -Nru openjdk-25-25.0.4.1+1/debian/patches/jdk-8378615.diff openjdk-25-25.0.5+8/debian/patches/jdk-8378615.diff --- openjdk-25-25.0.4.1+1/debian/patches/jdk-8378615.diff 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/patches/jdk-8378615.diff 2026-10-22 00:58:09.000000000 +0000 @@ -0,0 +1,127 @@ +From c6a20173a37ec56f3264d5a312543bdfc40ce3d2 Mon Sep 17 00:00:00 2001 +From: Phil Race +Date: Mon, 23 Mar 2026 17:15:07 +0000 +Subject: [PATCH] 8378615: FFM Bound up call stub keeps JNI Global Ref to bound + parameter +Bug: https://bugs.openjdk.org/browse/JDK-8378615 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/openjdk-25/+bug/2155650 +Origin: upstream, https://github.com/openjdk/jdk/commit/c6a20173a37ec56f3264d5a312543bdfc40ce3d2 +Reviewed-by: jdv, psadhukhan +--- + .../share/classes/sun/font/HBShaper.java | 45 +++++++------------ + 1 file changed, 16 insertions(+), 29 deletions(-) + +diff --git a/src/java.desktop/share/classes/sun/font/HBShaper.java b/src/java.desktop/share/classes/sun/font/HBShaper.java +index 7d3f58fb88f..3a532072004 100644 +--- a/src/java.desktop/share/classes/sun/font/HBShaper.java ++++ b/src/java.desktop/share/classes/sun/font/HBShaper.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 +@@ -138,6 +138,7 @@ private static VarHandle getVarHandle(StructLayout struct, String name) { + private static final MemorySegment get_h_advance_stub; + private static final MemorySegment get_v_advance_stub; + private static final MemorySegment get_contour_pt_stub; ++ private static final MemorySegment get_table_data_fn_stub; + + private static final MemorySegment store_layout_results_stub; + +@@ -209,6 +210,12 @@ private static VarHandle getVarHandle(StructLayout struct, String name) { + jdk_hb_shape_handle = tmp4; + + Arena garena = Arena.global(); // creating stubs that exist until VM exit. ++ ++ get_table_data_fn_stub = getUpcallStub(garena, ++ "getFontTableData", // method name ++ JAVA_INT, // return type ++ JAVA_INT, ADDRESS); // arg types ++ + FunctionDescriptor get_var_glyph_fd = getFunctionDescriptor(JAVA_INT, // return type + ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS, ADDRESS); // arg types + MethodHandle get_var_glyph_mh = +@@ -303,15 +310,9 @@ private static VarHandle getVarHandle(StructLayout struct, String name) { + clusterHandle = getVarHandle(GlyphInfoLayout, "cluster"); + } + +- +- /* +- * This is expensive but it is done just once per font. +- * The unbound stub could be cached but the savings would +- * be very low in the only case it is used. +- */ + @SuppressWarnings("restricted") +- private static MemorySegment getBoundUpcallStub +- (Arena arena, Class clazz, Object bindArg, String mName, ++ private static MemorySegment getUpcallStub ++ (Arena arena, String mName, + MemoryLayout retType, MemoryLayout... argTypes) { + + try { +@@ -320,10 +321,8 @@ private static VarHandle getVarHandle(StructLayout struct, String name) { + FunctionDescriptor.ofVoid(argTypes) : + FunctionDescriptor.of(retType, argTypes); + MethodType mType = nativeDescriptor.toMethodType(); +- mType = mType.insertParameterTypes(0, clazz); + MethodHandle mh = MH_LOOKUP.findStatic(HBShaper.class, mName, mType); +- MethodHandle bound_handle = mh.bindTo(bindArg); +- return LINKER.upcallStub(bound_handle, nativeDescriptor, arena); ++ return LINKER.upcallStub(mh, nativeDescriptor, arena); + } catch (IllegalAccessException | NoSuchMethodException e) { + return null; + } +@@ -480,15 +479,16 @@ static void shape( + }); + } + +- private static int getFontTableData(Font2D font2D, +- int tag, +- MemorySegment data_ptr_out) { ++ private static int getFontTableData(int tag, MemorySegment data_ptr_out) { + + /* + * On return, the data_out_ptr will point to memory allocated by native malloc, + * so it will be freed by the caller using native free - when it is + * done with it. + */ ++ ++ Font2D font2D = scopedVars.get().font(); ++ + @SuppressWarnings("restricted") + MemorySegment data_ptr = data_ptr_out.reinterpret(ADDRESS.byteSize()); + if (tag == 0) { +@@ -539,10 +539,6 @@ static MemorySegment getFace(Font2D font2D) { + private static class FaceRef implements DisposerRecord { + private Font2D font2D; + private MemorySegment face; +- // get_table_data_fn uses an Arena managed by GC, +- // so we need to keep a reference to it here until +- // this FaceRef is collected. +- private MemorySegment get_table_data_fn; + + private FaceRef(Font2D font) { + this.font2D = font; +@@ -561,16 +557,7 @@ private synchronized MemorySegment getFace() { + + private void createFace() { + try { +- get_table_data_fn = getBoundUpcallStub(Arena.ofAuto(), +- Font2D.class, +- font2D, // bind arg +- "getFontTableData", // method name +- JAVA_INT, // return type +- JAVA_INT, ADDRESS); // arg types +- if (get_table_data_fn == null) { +- return; +- } +- face = (MemorySegment)create_face_handle.invokeExact(get_table_data_fn); ++ face = (MemorySegment)create_face_handle.invokeExact(get_table_data_fn_stub); + } catch (Throwable t) { + } + } +-- +2.53.0 + diff -Nru openjdk-25-25.0.4.1+1/debian/patches/jdk-8384505.diff openjdk-25-25.0.5+8/debian/patches/jdk-8384505.diff --- openjdk-25-25.0.4.1+1/debian/patches/jdk-8384505.diff 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/patches/jdk-8384505.diff 2026-10-22 00:58:09.000000000 +0000 @@ -0,0 +1,39 @@ +From 759dce180ba7a88ad8a51509200d780948957d3a Mon Sep 17 00:00:00 2001 +From: Christian Stein +Date: Wed, 13 May 2026 13:37:15 +0000 +Subject: [PATCH] 8384505: Account for all jtreg-based frames in stack walk + test +Bug: https://bugs.openjdk.org/browse/JDK-8384505 +Origin: upstream, https://github.com/openjdk/jdk/commit/759dce180ba7a88ad8a51509200d780948957d3a +Reviewed-by: dfuchs, alanb + +--- a/test/jdk/java/lang/StackWalker/StackWalkTest.java ++++ b/test/jdk/java/lang/StackWalker/StackWalkTest.java +@@ -55,11 +55,11 @@ + static final Set infrastructureClasses = new TreeSet<>(Arrays.asList( + "jdk.internal.reflect.DirectMethodHandleAccessor", + "java.lang.reflect.Method", +- "com.sun.javatest.regtest.MainWrapper$MainThread", +- "com.sun.javatest.regtest.agent.MainWrapper$MainThread", +- "com.sun.javatest.regtest.agent.MainWrapper$MainTask", + "java.lang.Thread" + )); ++ static final List infrastructurePackages = List.of( ++ "com.sun.javatest.regtest." ++ ); + static final List> streamPipelines = Arrays.asList( + classForName("java.util.stream.AbstractPipeline"), + classForName("java.util.stream.TerminalOp") +@@ -130,6 +130,12 @@ + // safe to ignore + return; + } ++ for (String prefix : infrastructurePackages) { ++ if (sf.getClassName().startsWith(prefix)) { ++ // safe to ignore ++ return; ++ } ++ } + } + try { + recorder.compareFrame(count, sf); diff -Nru openjdk-25-25.0.4.1+1/debian/patches/jdk-8388170-proposed.diff openjdk-25-25.0.5+8/debian/patches/jdk-8388170-proposed.diff --- openjdk-25-25.0.4.1+1/debian/patches/jdk-8388170-proposed.diff 2026-08-18 21:50:36.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/patches/jdk-8388170-proposed.diff 1970-01-01 00:00:00.000000000 +0000 @@ -1,304 +0,0 @@ -From ea42ba233b9c228f891e0f334970f2e3adc66dae Mon Sep 17 00:00:00 2001 -From: Vladimir Petko -Date: Tue, 14 Jul 2026 14:34:14 +1200 -Subject: [PATCH] fix: do not use magic number in return address functions -Bug: https://bugs.openjdk.org/browse/JDK-8388170 - ---- - src/hotspot/cpu/aarch64/aarch64.ad | 6 +-- - src/hotspot/cpu/arm/arm_32.ad | 6 +-- - src/hotspot/cpu/ppc/ppc.ad | 6 +-- - src/hotspot/cpu/riscv/riscv.ad | 6 +-- - src/hotspot/cpu/s390/s390.ad | 68 ++++++++++++++++++++++------- - src/hotspot/cpu/x86/x86.ad | 6 +-- - src/hotspot/share/opto/machnode.hpp | 8 ++-- - 7 files changed, 72 insertions(+), 34 deletions(-) - ---- a/src/hotspot/cpu/aarch64/aarch64.ad -+++ b/src/hotspot/cpu/aarch64/aarch64.ad -@@ -1628,19 +1628,19 @@ - // from the start of the call to the point where the return address - // will point. - --int MachCallStaticJavaNode::ret_addr_offset() -+int MachCallStaticJavaNode::ret_addr_offset() const - { - // call should be a simple bl - int off = 4; - return off; - } - --int MachCallDynamicJavaNode::ret_addr_offset() -+int MachCallDynamicJavaNode::ret_addr_offset() const - { - return 16; // movz, movk, movk, bl - } - --int MachCallRuntimeNode::ret_addr_offset() { -+int MachCallRuntimeNode::ret_addr_offset() const { - // for generated stubs the call will be - // bl(addr) - // or with far branches ---- a/src/hotspot/cpu/ppc/ppc.ad -+++ b/src/hotspot/cpu/ppc/ppc.ad -@@ -1171,12 +1171,12 @@ - - // PPC port: Removed use of lazy constant construct. - --int MachCallStaticJavaNode::ret_addr_offset() { -+int MachCallStaticJavaNode::ret_addr_offset() const { - // It's only a single branch-and-link instruction. - return 4; - } - --int MachCallDynamicJavaNode::ret_addr_offset() { -+int MachCallDynamicJavaNode::ret_addr_offset() const { - // Offset is 4 with postalloc expanded calls (bl is one instruction). We use - // postalloc expanded calls if we use inline caches and do not update method data. - if (UseInlineCaches) return 4; -@@ -1191,7 +1191,7 @@ - } - } - --int MachCallRuntimeNode::ret_addr_offset() { -+int MachCallRuntimeNode::ret_addr_offset() const { - if (rule() == CallRuntimeDirect_rule) { - // CallRuntimeDirectNode uses call_c. - #if defined(ABI_ELFv2) ---- a/src/hotspot/cpu/riscv/riscv.ad -+++ b/src/hotspot/cpu/riscv/riscv.ad -@@ -1218,17 +1218,17 @@ - // from the start of the call to the point where the return address - // will point. - --int MachCallStaticJavaNode::ret_addr_offset() -+int MachCallStaticJavaNode::ret_addr_offset() const - { - return 3 * NativeInstruction::instruction_size; // auipc + ld + jalr - } - --int MachCallDynamicJavaNode::ret_addr_offset() -+int MachCallDynamicJavaNode::ret_addr_offset() const - { - return NativeMovConstReg::movptr2_instruction_size + (3 * NativeInstruction::instruction_size); // movptr2, auipc + ld + jal - } - --int MachCallRuntimeNode::ret_addr_offset() { -+int MachCallRuntimeNode::ret_addr_offset() const { - // For address inside the code cache the call will be: - // auipc + jalr - // For real runtime callouts it will be 8 instructions ---- a/src/hotspot/cpu/s390/s390.ad -+++ b/src/hotspot/cpu/s390/s390.ad -@@ -886,29 +886,62 @@ - return 0; - } - --int MachCallStaticJavaNode::ret_addr_offset() { -+int MachCallStaticJavaNode::ret_addr_offset() const { - if (_method) { -- return 8; -+ return MacroAssembler::call_far_pcrelative_size(); -+ - } else { - return MacroAssembler::call_far_patchable_ret_addr_offset(); - } - } - --int MachCallDynamicJavaNode::ret_addr_offset() { -+int MachCallDynamicJavaNode::ret_addr_offset() const { - // Consider size of receiver type profiling (C2 tiers). - int profile_receiver_type_size = 0; - - int vtable_index = this->_vtable_index; - if (vtable_index == -4) { -- return 14 + profile_receiver_type_size; -+ return MacroAssembler::load_const_from_toc_size() -+ + MacroAssembler::call_far_pcrelative_size() -+ + profile_receiver_type_size; - } else { - assert(!UseInlineCaches, "expect vtable calls only if not using ICs"); -- return 36 + profile_receiver_type_size; -+ // This should return the size of instructions in vtable dispatch -+ // branch of z_enc_java_dynamic_call -+ int offset = 0; -+ -+ // __ load_klass(Z_method, Z_R2); -+ if (UseCompactObjectHeaders) { -+ // load_narrow_klass_compact (z_lg z_srlg) -+ offset += 6 // z_lg -+ + 6; // z_srlg; -+ } else { -+ offset += 6; // z_llgf -+ } -+ offset += MacroAssembler::instr_size_for_decode_klass_not_null(); -+ -+ // check if displacement is valid, as it will generate different -+ // instructions: -+ int entry_offset = in_bytes(Klass::vtable_start_offset()) + -+ vtable_index * vtableEntry::size_in_bytes(); -+ int v_off = entry_offset + in_bytes(vtableEntry::method_offset()); -+ if (!Displacement::is_validDisp(v_off)) { -+ offset += MacroAssembler::load_const_size(); // it also generates load_cost -+ } -+ // both generate z_lg -+ offset += 6; // z_lg (z_method, v_off | Address(Z_method, Z_R1_scratch)) -+ // common footer -+ offset += 6; // z_lg(Z_R1_scratch, Method::from_compiled_offset()) -+ offset += 2; // z_basr -+ -+ return offset + profile_receiver_type_size; - } - } - --int MachCallRuntimeNode::ret_addr_offset() { -- return 12 + MacroAssembler::call_far_patchable_ret_addr_offset(); -+int MachCallRuntimeNode::ret_addr_offset() const { -+ return 6 // get_PC() (LARL) -+ + 6 // save_return_pc() (STG) -+ + MacroAssembler::call_far_patchable_ret_addr_offset(); - } - - // Compute padding required for nodes which need alignment -@@ -2379,8 +2412,8 @@ - // callee doesn't. - unsigned int start_off = __ offset(); - // Compute size of "larl + stg + call_c_opt". -- const int size_of_code = 6 + 6 + MacroAssembler::call_far_patchable_size(); -- __ get_PC(Z_R14, size_of_code); -+ const int ret_off = ret_addr_offset(); -+ __ get_PC(Z_R14, ret_off); - __ save_return_pc(); - assert(__ offset() - start_off == 12, "bad prelude len: %d", __ offset() - start_off); - -@@ -2391,14 +2424,13 @@ - return; - } - --#ifdef ASSERT -- // Plausibility check for size_of_code assumptions. -- unsigned int actual_ret_off = __ offset(); -- assert(start_off + size_of_code == actual_ret_off, "wrong return_pc"); --#endif -+ assert(__ offset() - start_off == (uint)ret_addr_offset(), -+ "z_enc_java_to_runtime_call return offset mismatch: emitted %d bytes, ret_addr_offset()=%d", -+ __ offset() - start_off, ret_addr_offset()); - %} - - enc_class z_enc_java_static_call(method meth) %{ -+ unsigned int start_off = __ offset(); - // Call to fixup routine. Fixup routine uses ScopeDesc info to determine - // whom we intended to call. - int ret_offset = 0; -@@ -2428,6 +2460,9 @@ - } - - __ clear_inst_mark(); -+ assert(__ offset() - start_off == (uint)ret_addr_offset(), -+ "z_enc_java_static_call return offset mismatch: emitted %d bytes, ret_addr_offset()=%d", -+ __ offset() - start_off, ret_addr_offset()); - %} - - // Java dynamic call -@@ -2482,8 +2517,10 @@ - __ z_lg(Z_R1_scratch, Address(Z_method, Method::from_compiled_offset())); - // Call target. Either compiled code or C2I adapter. - __ z_basr(Z_R14, Z_R1_scratch); -- unsigned int ret_off = __ offset(); - } -+ assert(__ offset() - start_off == (uint)ret_addr_offset(), -+ "z_enc_java_dynamic_call return offset mismatch: emitted %d bytes, ret_addr_offset()=%d", -+ __ offset() - start_off, ret_addr_offset()); - %} - - enc_class z_enc_cmov_reg(cmpOp cmp, iRegI dst, iRegI src) %{ ---- a/src/hotspot/share/opto/machnode.hpp -+++ b/src/hotspot/share/opto/machnode.hpp -@@ -926,7 +926,7 @@ - virtual bool pinned() const { return false; } - virtual const Type* Value(PhaseGVN* phase) const; - virtual const RegMask &in_RegMask(uint) const; -- virtual int ret_addr_offset() { return 0; } -+ virtual int ret_addr_offset() const { return 0; } - - NOT_LP64(bool return_value_is_used() const;) - -@@ -988,7 +988,7 @@ - // If this is an uncommon trap, return the request code, else zero. - int uncommon_trap_request() const; - -- virtual int ret_addr_offset(); -+ virtual int ret_addr_offset() const; - #ifndef PRODUCT - virtual void dump_spec(outputStream *st) const; - void dump_trap_args(outputStream *st) const; -@@ -1004,7 +1004,7 @@ - init_class_id(Class_MachCallDynamicJava); - DEBUG_ONLY(_vtable_index = -99); // throw an assert if uninitialized - } -- virtual int ret_addr_offset(); -+ virtual int ret_addr_offset() const; - #ifndef PRODUCT - virtual void dump_spec(outputStream *st) const; - #endif -@@ -1022,7 +1022,7 @@ - MachCallRuntimeNode() : MachCallNode() { - init_class_id(Class_MachCallRuntime); - } -- virtual int ret_addr_offset(); -+ virtual int ret_addr_offset() const; - #ifndef PRODUCT - virtual void dump_spec(outputStream *st) const; - #endif ---- a/src/hotspot/cpu/arm/arm_32.ad -+++ b/src/hotspot/cpu/arm/arm_32.ad -@@ -430,19 +430,19 @@ - // from the start of the call to the point where the return address - // will point. - --int MachCallStaticJavaNode::ret_addr_offset() { -+int MachCallStaticJavaNode::ret_addr_offset() const { - bool far = (_method == nullptr) ? maybe_far_call(this) : !cache_reachable(); - return ((far ? 3 : 1) + (_method_handle_invoke ? 1 : 0)) * - NativeInstruction::instruction_size; - } - --int MachCallDynamicJavaNode::ret_addr_offset() { -+int MachCallDynamicJavaNode::ret_addr_offset() const { - bool far = !cache_reachable(); - // mov_oop is always 2 words - return (2 + (far ? 3 : 1)) * NativeInstruction::instruction_size; - } - --int MachCallRuntimeNode::ret_addr_offset() { -+int MachCallRuntimeNode::ret_addr_offset() const { - // bl or movw; movt; blx - bool far = maybe_far_call(this); - return (far ? 3 : 1) * NativeInstruction::instruction_size; ---- a/src/hotspot/cpu/x86/x86_64.ad -+++ b/src/hotspot/cpu/x86/x86_64.ad -@@ -600,21 +600,21 @@ - // !!!!! Special hack to get all types of calls to specify the byte offset - // from the start of the call to the point where the return address - // will point. --int MachCallStaticJavaNode::ret_addr_offset() -+int MachCallStaticJavaNode::ret_addr_offset() const - { - int offset = 5; // 5 bytes from start of call to where return address points - offset += clear_avx_size(); - return offset; - } - --int MachCallDynamicJavaNode::ret_addr_offset() -+int MachCallDynamicJavaNode::ret_addr_offset() const - { - int offset = 15; // 15 bytes from start of call to where return address points - offset += clear_avx_size(); - return offset; - } - --int MachCallRuntimeNode::ret_addr_offset() { -+int MachCallRuntimeNode::ret_addr_offset() const { - int offset = 13; // movq r10,#addr; callq (r10) - if (this->ideal_Opcode() != Op_CallLeafVector) { - offset += clear_avx_size(); diff -Nru openjdk-25-25.0.4.1+1/debian/patches/jdk-8388170.diff openjdk-25-25.0.5+8/debian/patches/jdk-8388170.diff --- openjdk-25-25.0.4.1+1/debian/patches/jdk-8388170.diff 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/patches/jdk-8388170.diff 2026-10-22 00:58:09.000000000 +0000 @@ -0,0 +1,300 @@ +From ea42ba233b9c228f891e0f334970f2e3adc66dae Mon Sep 17 00:00:00 2001 +From: Vladimir Petko +Date: Tue, 14 Jul 2026 14:34:14 +1200 +Subject: [PATCH] fix: do not use magic number in return address functions +Bug: https://bugs.openjdk.org/browse/JDK-8388170 + +--- + src/hotspot/cpu/aarch64/aarch64.ad | 6 +-- + src/hotspot/cpu/arm/arm_32.ad | 6 +-- + src/hotspot/cpu/ppc/ppc.ad | 6 +-- + src/hotspot/cpu/riscv/riscv.ad | 6 +-- + src/hotspot/cpu/s390/s390.ad | 68 ++++++++++++++++++++++------- + src/hotspot/cpu/x86/x86.ad | 6 +-- + src/hotspot/share/opto/machnode.hpp | 8 ++-- + 7 files changed, 72 insertions(+), 34 deletions(-) + +--- a/src/hotspot/cpu/aarch64/aarch64.ad ++++ b/src/hotspot/cpu/aarch64/aarch64.ad +@@ -1628,19 +1628,19 @@ + // from the start of the call to the point where the return address + // will point. + +-int MachCallStaticJavaNode::ret_addr_offset() ++int MachCallStaticJavaNode::ret_addr_offset() const + { + // call should be a simple bl + int off = 4; + return off; + } + +-int MachCallDynamicJavaNode::ret_addr_offset() ++int MachCallDynamicJavaNode::ret_addr_offset() const + { + return 16; // movz, movk, movk, bl + } + +-int MachCallRuntimeNode::ret_addr_offset() { ++int MachCallRuntimeNode::ret_addr_offset() const { + // for generated stubs the call will be + // bl(addr) + // or with far branches +--- a/src/hotspot/cpu/ppc/ppc.ad ++++ b/src/hotspot/cpu/ppc/ppc.ad +@@ -1171,16 +1171,16 @@ + + // PPC port: Removed use of lazy constant construct. + +-int MachCallStaticJavaNode::ret_addr_offset() { ++int MachCallStaticJavaNode::ret_addr_offset() const { + // It's only a single branch-and-link instruction. + return 4; + } + +-int MachCallDynamicJavaNode::ret_addr_offset() { ++int MachCallDynamicJavaNode::ret_addr_offset() const { + return 12; + } + +-int MachCallRuntimeNode::ret_addr_offset() { ++int MachCallRuntimeNode::ret_addr_offset() const { + if (rule() == CallRuntimeDirect_rule) { + // CallRuntimeDirectNode uses call_c. + #if defined(ABI_ELFv2) +--- a/src/hotspot/cpu/riscv/riscv.ad ++++ b/src/hotspot/cpu/riscv/riscv.ad +@@ -1218,17 +1218,17 @@ + // from the start of the call to the point where the return address + // will point. + +-int MachCallStaticJavaNode::ret_addr_offset() ++int MachCallStaticJavaNode::ret_addr_offset() const + { + return 3 * NativeInstruction::instruction_size; // auipc + ld + jalr + } + +-int MachCallDynamicJavaNode::ret_addr_offset() ++int MachCallDynamicJavaNode::ret_addr_offset() const + { + return NativeMovConstReg::movptr2_instruction_size + (3 * NativeInstruction::instruction_size); // movptr2, auipc + ld + jal + } + +-int MachCallRuntimeNode::ret_addr_offset() { ++int MachCallRuntimeNode::ret_addr_offset() const { + // For address inside the code cache the call will be: + // auipc + jalr + // For real runtime callouts it will be 8 instructions +--- a/src/hotspot/cpu/s390/s390.ad ++++ b/src/hotspot/cpu/s390/s390.ad +@@ -886,29 +886,62 @@ + return 0; + } + +-int MachCallStaticJavaNode::ret_addr_offset() { ++int MachCallStaticJavaNode::ret_addr_offset() const { + if (_method) { +- return 8; ++ return MacroAssembler::call_far_pcrelative_size(); ++ + } else { + return MacroAssembler::call_far_patchable_ret_addr_offset(); + } + } + +-int MachCallDynamicJavaNode::ret_addr_offset() { ++int MachCallDynamicJavaNode::ret_addr_offset() const { + // Consider size of receiver type profiling (C2 tiers). + int profile_receiver_type_size = 0; + + int vtable_index = this->_vtable_index; + if (vtable_index == -4) { +- return 14 + profile_receiver_type_size; ++ return MacroAssembler::load_const_from_toc_size() ++ + MacroAssembler::call_far_pcrelative_size() ++ + profile_receiver_type_size; + } else { + assert(!UseInlineCaches, "expect vtable calls only if not using ICs"); +- return 36 + profile_receiver_type_size; ++ // This should return the size of instructions in vtable dispatch ++ // branch of z_enc_java_dynamic_call ++ int offset = 0; ++ ++ // __ load_klass(Z_method, Z_R2); ++ if (UseCompactObjectHeaders) { ++ // load_narrow_klass_compact (z_lg z_srlg) ++ offset += 6 // z_lg ++ + 6; // z_srlg; ++ } else { ++ offset += 6; // z_llgf ++ } ++ offset += MacroAssembler::instr_size_for_decode_klass_not_null(); ++ ++ // check if displacement is valid, as it will generate different ++ // instructions: ++ int entry_offset = in_bytes(Klass::vtable_start_offset()) + ++ vtable_index * vtableEntry::size_in_bytes(); ++ int v_off = entry_offset + in_bytes(vtableEntry::method_offset()); ++ if (!Displacement::is_validDisp(v_off)) { ++ offset += MacroAssembler::load_const_size(); // it also generates load_cost ++ } ++ // both generate z_lg ++ offset += 6; // z_lg (z_method, v_off | Address(Z_method, Z_R1_scratch)) ++ // common footer ++ offset += 6; // z_lg(Z_R1_scratch, Method::from_compiled_offset()) ++ offset += 2; // z_basr ++ ++ return offset + profile_receiver_type_size; + } + } + +-int MachCallRuntimeNode::ret_addr_offset() { +- return 12 + MacroAssembler::call_far_patchable_ret_addr_offset(); ++int MachCallRuntimeNode::ret_addr_offset() const { ++ return 6 // get_PC() (LARL) ++ + 6 // save_return_pc() (STG) ++ + MacroAssembler::call_far_patchable_ret_addr_offset(); + } + + // Compute padding required for nodes which need alignment +@@ -2379,8 +2412,8 @@ + // callee doesn't. + unsigned int start_off = __ offset(); + // Compute size of "larl + stg + call_c_opt". +- const int size_of_code = 6 + 6 + MacroAssembler::call_far_patchable_size(); +- __ get_PC(Z_R14, size_of_code); ++ const int ret_off = ret_addr_offset(); ++ __ get_PC(Z_R14, ret_off); + __ save_return_pc(); + assert(__ offset() - start_off == 12, "bad prelude len: %d", __ offset() - start_off); + +@@ -2391,14 +2424,13 @@ + return; + } + +-#ifdef ASSERT +- // Plausibility check for size_of_code assumptions. +- unsigned int actual_ret_off = __ offset(); +- assert(start_off + size_of_code == actual_ret_off, "wrong return_pc"); +-#endif ++ assert(__ offset() - start_off == (uint)ret_addr_offset(), ++ "z_enc_java_to_runtime_call return offset mismatch: emitted %d bytes, ret_addr_offset()=%d", ++ __ offset() - start_off, ret_addr_offset()); + %} + + enc_class z_enc_java_static_call(method meth) %{ ++ unsigned int start_off = __ offset(); + // Call to fixup routine. Fixup routine uses ScopeDesc info to determine + // whom we intended to call. + int ret_offset = 0; +@@ -2428,6 +2460,9 @@ + } + + __ clear_inst_mark(); ++ assert(__ offset() - start_off == (uint)ret_addr_offset(), ++ "z_enc_java_static_call return offset mismatch: emitted %d bytes, ret_addr_offset()=%d", ++ __ offset() - start_off, ret_addr_offset()); + %} + + // Java dynamic call +@@ -2482,8 +2517,10 @@ + __ z_lg(Z_R1_scratch, Address(Z_method, Method::from_compiled_offset())); + // Call target. Either compiled code or C2I adapter. + __ z_basr(Z_R14, Z_R1_scratch); +- unsigned int ret_off = __ offset(); + } ++ assert(__ offset() - start_off == (uint)ret_addr_offset(), ++ "z_enc_java_dynamic_call return offset mismatch: emitted %d bytes, ret_addr_offset()=%d", ++ __ offset() - start_off, ret_addr_offset()); + %} + + enc_class z_enc_cmov_reg(cmpOp cmp, iRegI dst, iRegI src) %{ +--- a/src/hotspot/share/opto/machnode.hpp ++++ b/src/hotspot/share/opto/machnode.hpp +@@ -926,7 +926,7 @@ + virtual bool pinned() const { return false; } + virtual const Type* Value(PhaseGVN* phase) const; + virtual const RegMask &in_RegMask(uint) const; +- virtual int ret_addr_offset() { return 0; } ++ virtual int ret_addr_offset() const { return 0; } + + NOT_LP64(bool return_value_is_used() const;) + +@@ -988,7 +988,7 @@ + // If this is an uncommon trap, return the request code, else zero. + int uncommon_trap_request() const; + +- virtual int ret_addr_offset(); ++ virtual int ret_addr_offset() const; + #ifndef PRODUCT + virtual void dump_spec(outputStream *st) const; + void dump_trap_args(outputStream *st) const; +@@ -1004,7 +1004,7 @@ + init_class_id(Class_MachCallDynamicJava); + DEBUG_ONLY(_vtable_index = -99); // throw an assert if uninitialized + } +- virtual int ret_addr_offset(); ++ virtual int ret_addr_offset() const; + #ifndef PRODUCT + virtual void dump_spec(outputStream *st) const; + #endif +@@ -1022,7 +1022,7 @@ + MachCallRuntimeNode() : MachCallNode() { + init_class_id(Class_MachCallRuntime); + } +- virtual int ret_addr_offset(); ++ virtual int ret_addr_offset() const; + #ifndef PRODUCT + virtual void dump_spec(outputStream *st) const; + #endif +--- a/src/hotspot/cpu/arm/arm_32.ad ++++ b/src/hotspot/cpu/arm/arm_32.ad +@@ -430,19 +430,19 @@ + // from the start of the call to the point where the return address + // will point. + +-int MachCallStaticJavaNode::ret_addr_offset() { ++int MachCallStaticJavaNode::ret_addr_offset() const { + bool far = (_method == nullptr) ? maybe_far_call(this) : !cache_reachable(); + return ((far ? 3 : 1) + (_method_handle_invoke ? 1 : 0)) * + NativeInstruction::instruction_size; + } + +-int MachCallDynamicJavaNode::ret_addr_offset() { ++int MachCallDynamicJavaNode::ret_addr_offset() const { + bool far = !cache_reachable(); + // mov_oop is always 2 words + return (2 + (far ? 3 : 1)) * NativeInstruction::instruction_size; + } + +-int MachCallRuntimeNode::ret_addr_offset() { ++int MachCallRuntimeNode::ret_addr_offset() const { + // bl or movw; movt; blx + bool far = maybe_far_call(this); + return (far ? 3 : 1) * NativeInstruction::instruction_size; +--- a/src/hotspot/cpu/x86/x86_64.ad ++++ b/src/hotspot/cpu/x86/x86_64.ad +@@ -600,21 +600,21 @@ + // !!!!! Special hack to get all types of calls to specify the byte offset + // from the start of the call to the point where the return address + // will point. +-int MachCallStaticJavaNode::ret_addr_offset() ++int MachCallStaticJavaNode::ret_addr_offset() const + { + int offset = 5; // 5 bytes from start of call to where return address points + offset += clear_avx_size(); + return offset; + } + +-int MachCallDynamicJavaNode::ret_addr_offset() ++int MachCallDynamicJavaNode::ret_addr_offset() const + { + int offset = 15; // 15 bytes from start of call to where return address points + offset += clear_avx_size(); + return offset; + } + +-int MachCallRuntimeNode::ret_addr_offset() { ++int MachCallRuntimeNode::ret_addr_offset() const { + int offset = 13; // movq r10,#addr; callq (r10) + if (this->ideal_Opcode() != Op_CallLeafVector) { + offset += clear_avx_size(); diff -Nru openjdk-25-25.0.4.1+1/debian/patches/series openjdk-25-25.0.5+8/debian/patches/series --- openjdk-25-25.0.4.1+1/debian/patches/series 2026-08-18 21:50:36.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/patches/series 2026-10-22 00:58:09.000000000 +0000 @@ -45,4 +45,12 @@ jdk-8385738.diff jdk-8387580.diff jdk-8377035.diff -jdk-8388170-proposed.diff +jdk-8388170.diff +jdk-8384505.diff +# start: fix FFM font rendering issues in openjdk-25 +jdk-8337853.diff +jdk-8371066.diff +jdk-8378603.diff +jdk-8378607.diff +jdk-8378615.diff +# end: FFM font rendering issues diff -Nru openjdk-25-25.0.4.1+1/debian/rules openjdk-25-25.0.5+8/debian/rules --- openjdk-25-25.0.4.1+1/debian/rules 2026-08-18 22:34:35.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/rules 2026-10-22 00:58:09.000000000 +0000 @@ -90,6 +90,7 @@ is_upstream_release = yes + srcdir = . builddir = build zbuilddir = build-zero @@ -302,6 +303,24 @@ DEB_BUILD_MAINT_OPTIONS = optimize=-lto endif +# This is a machine-specific issue +# https://bugs.launchpad.net/ubuntu/+source/openjdk-21/+bug/2095441 +# vectorization instructions will produce invalid offsets in JVMState, e.g. +# monoff 14 > scloff 12 when run in qemu/lxd environment. The issue does +# not occur with gcc >= 15. +ifneq (,$(filter $(distrel),focal jammy noble)) +ifeq ($(DEB_HOST_ARCH),s390x) + NO_TREE_SLP_VECTORIZE = -fno-tree-slp-vectorize +endif +endif + +# Older RISCV backports need -latomic for __atomic_exchange_1 +ifneq (,$(filter $(distrel),focal jammy)) +ifeq ($(DEB_HOST_ARCH),riscv64) + LINK_ATOMIC = -latomic +endif +endif + # for Hotspot: hotspot/make/linux/makefiles/vm.make # Don't overwrite Hotspot opt level : # -O3 is already default option for hotspot @@ -311,14 +330,16 @@ DEB_BUILD_MAINT_OPTIONS="$(DEB_BUILD_MAINT_OPTIONS)" \ DEB_CFLAGS_MAINT_STRIP="-O2 -Werror=format-security" \ DEB_CXXFLAGS_MAINT_STRIP="-O2 -Werror=format-security" \ - DEB_CFLAGS_MAINT_APPEND="-fno-stack-protector -Wno-deprecated-declarations" \ - DEB_CXXFLAGS_MAINT_APPEND="-fno-stack-protector -Wno-deprecated-declarations$(if $(filter $(DEB_HOST_ARCH), armel armhf), -fpermissive)" \ + DEB_CFLAGS_MAINT_APPEND="$(NO_TREE_SLP_VECTORIZE) -fno-stack-protector -Wno-deprecated-declarations" \ + DEB_CXXFLAGS_MAINT_APPEND="$(NO_TREE_SLP_VECTORIZE) -fno-stack-protector -Wno-deprecated-declarations$(if $(filter $(DEB_HOST_ARCH), armel armhf), -fpermissive)" \ DEB_CFLAGS_MAINT_APPEND="$(if $(filter $(distrel), jammy), $(if $(filter $(DEB_HOST_ARCH), armel armhf), -DSTAP_SDT_ARG_CONSTRAINT=g))" # jdk/make/CompileDemos.gmk (SetupJVMTIDemo) doesn't like commas in flags dpkg_buildflags_hs += \ DEB_LDFLAGS_MAINT_STRIP="-Wl,-z,relro -Wl,-Bsymbolic-functions" \ - DEB_LDFLAGS_MAINT_APPEND="-Xlinker -z -Xlinker relro -Xlinker -Bsymbolic-functions -Xlinker --no-as-needed" + DEB_LDFLAGS_MAINT_APPEND="-Xlinker -z -Xlinker relro -Xlinker -Bsymbolic-functions -Xlinker --no-as-needed $(LINK_ATOMIC)" + dpkg_buildflags_hs += dpkg-buildflags + export EXTRA_CPPFLAGS_HS := $(shell $(dpkg_buildflags_hs) --get CPPFLAGS) export EXTRA_CFLAGS_HS := $(shell $(dpkg_buildflags_hs) --get CFLAGS; $(dpkg_buildflags_hs) --get CPPFLAGS) export EXTRA_CXXFLAGS_HS := $(shell $(dpkg_buildflags_hs) --get CXXFLAGS) -Wno-deprecated-declarations @@ -334,7 +355,7 @@ # jdk/make/CompileDemos.gmk (SetupJVMTIDemo) doesn't like commas in flags dpkg_buildflags_zero += \ DEB_LDFLAGS_MAINT_STRIP="-Wl,-z,relro -Wl,-Bsymbolic-functions" \ - DEB_LDFLAGS_MAINT_APPEND="-Xlinker -z -Xlinker relro -Xlinker -Bsymbolic-functions -Xlinker --no-as-needed" + DEB_LDFLAGS_MAINT_APPEND="-Xlinker -z -Xlinker relro -Xlinker -Bsymbolic-functions -Xlinker --no-as-needed $(LINK_ATOMIC)" dpkg_buildflags_zero += dpkg-buildflags export EXTRA_CPPFLAGS_ZERO := $(shell $(dpkg_buildflags_zero) --get CPPFLAGS) export EXTRA_CFLAGS_ZERO := $(shell $(dpkg_buildflags_zero) --get CFLAGS; $(dpkg_buildflags_zero) --get CPPFLAGS) @@ -452,6 +473,13 @@ --with-boot-jdk-jvmargs="-XX:ThreadStackSize=2240 -Xss4M" endif +ifeq ($(derivative)-$(DEB_HOST_ARCH),Ubuntu-s390x) + # Disable C2 compiler to workaround launchpad build issue + # This argument overrides earler --with-boot-jdk-jvmargs setting + COMMON_CONFIGURE_ARGS += \ + --with-boot-jdk-jvmargs="-XX:TieredStopAtLevel=1 -XX:ThreadStackSize=2240 -Xss4M" +endif + ifeq ($(with_check),yes) COMMON_CONFIGURE_ARGS += --with-jtreg=/usr/share/jtreg else @@ -554,6 +582,7 @@ COMMON_CONFIGURE_ARGS += \ --with-debug-level=release \ --with-native-debug-symbols=external \ + --with-external-symbols-in-bundles=full \ --enable-unlimited-crypto \ --with-zlib=system \ --with-giflib=system \ @@ -2139,7 +2168,7 @@ dh_builddeb -a $(nodemo) $(nojrez) #$(bd_options) git_project = jdk25u -git_tag = jdk-25.0.4.1+1 +git_tag = jdk-25.0.5+8 package_version = $(shell echo $(PKGVERSION) | sed 's/-[^-][^-]*$$//') ifneq ($(is_upstream_release),yes) package_version := $(subst +,~,$(package_version)) diff -Nru openjdk-25-25.0.4.1+1/debian/tests/control openjdk-25-25.0.5+8/debian/tests/control --- openjdk-25-25.0.4.1+1/debian/tests/control 2026-08-21 21:53:08.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/tests/control 2026-10-24 19:36:02.000000000 +0000 @@ -7,12 +7,12 @@ Restrictions: allow-stderr, superficial Tests: hotspot-autopkgtest.sh -Depends: @, jtreg8 (>= 8+2~), libtestng7-java, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-daemon, libatk-wrapper-java, libatk-wrapper-java-jni +Depends: @, jtreg8 (>= 8.2.1+1~), libtestng7-java, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-daemon, libatk-wrapper-java, libatk-wrapper-java-jni Restrictions: allow-stderr, skippable, flaky, rw-build-tree Architecture: amd64 arm64 ppc64 ppc64el riscv64 s390x alpha ia64 powerpc ppc64 sh4 x32 armel loong64 mipsel mips64el riscv64 Tests: jdk-autopkgtest.sh -Depends: @, jtreg8 (>= 8+2~), libtestng7-java, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-daemon, libatk-wrapper-java, libatk-wrapper-java-jni +Depends: @, jtreg8 (>= 8.2.1+1~), libtestng7-java, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-daemon, libatk-wrapper-java, libatk-wrapper-java-jni Restrictions: allow-stderr, skippable, flaky, rw-build-tree Architecture: amd64 arm64 ppc64 ppc64el riscv64 s390x alpha ia64 powerpc ppc64 sh4 x32 armel loong64 mipsel mips64el riscv64 diff -Nru openjdk-25-25.0.4.1+1/debian/tests/problems-loong-hotspot.txt openjdk-25-25.0.5+8/debian/tests/problems-loong-hotspot.txt --- openjdk-25-25.0.4.1+1/debian/tests/problems-loong-hotspot.txt 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/tests/problems-loong-hotspot.txt 2026-10-22 00:58:09.000000000 +0000 @@ -0,0 +1,554 @@ +applications/ctw/modules/java_compiler.java 0000000 generic-all +applications/ctw/modules/java_datatransfer.java 0000000 generic-all +applications/ctw/modules/java_instrument.java 0000000 generic-all +applications/ctw/modules/java_logging.java 0000000 generic-all +applications/ctw/modules/java_management.java 0000000 generic-all +applications/ctw/modules/java_management_rmi.java 0000000 generic-all +applications/ctw/modules/java_naming.java 0000000 generic-all +applications/ctw/modules/java_net_http.java 0000000 generic-all +applications/ctw/modules/java_prefs.java 0000000 generic-all +applications/ctw/modules/java_rmi.java 0000000 generic-all +applications/ctw/modules/java_scripting.java 0000000 generic-all +applications/ctw/modules/java_security_jgss.java 0000000 generic-all +applications/ctw/modules/java_security_sasl.java 0000000 generic-all +applications/ctw/modules/java_smartcardio.java 0000000 generic-all +applications/ctw/modules/java_sql.java 0000000 generic-all +applications/ctw/modules/java_sql_rowset.java 0000000 generic-all +applications/ctw/modules/java_transaction_xa.java 0000000 generic-all +applications/ctw/modules/java_xml_crypto.java 0000000 generic-all +applications/ctw/modules/jdk_accessibility.java 0000000 generic-all +applications/ctw/modules/jdk_attach.java 0000000 generic-all +applications/ctw/modules/jdk_charsets.java 0000000 generic-all +applications/ctw/modules/jdk_crypto_cryptoki.java 0000000 generic-all +applications/ctw/modules/jdk_dynalink.java 0000000 generic-all +applications/ctw/modules/jdk_editpad.java 0000000 generic-all +applications/ctw/modules/jdk_httpserver.java 0000000 generic-all +applications/ctw/modules/jdk_incubator_vector.java 0000000 generic-all +applications/ctw/modules/jdk_internal_ed.java 0000000 generic-all +applications/ctw/modules/jdk_internal_jvmstat.java 0000000 generic-all +applications/ctw/modules/jdk_internal_le.java 0000000 generic-all +applications/ctw/modules/jdk_internal_md.java 0000000 generic-all +applications/ctw/modules/jdk_internal_opt.java 0000000 generic-all +applications/ctw/modules/jdk_jartool.java 0000000 generic-all +applications/ctw/modules/jdk_javadoc.java 0000000 generic-all +applications/ctw/modules/jdk_jcmd.java 0000000 generic-all +applications/ctw/modules/jdk_jconsole.java 0000000 generic-all +applications/ctw/modules/jdk_jdeps.java 0000000 generic-all +applications/ctw/modules/jdk_jdi.java 0000000 generic-all +applications/ctw/modules/jdk_jfr.java 0000000 generic-all +applications/ctw/modules/jdk_jlink.java 0000000 generic-all +applications/ctw/modules/jdk_jpackage.java 0000000 generic-all +applications/ctw/modules/jdk_jshell.java 0000000 generic-all +applications/ctw/modules/jdk_jstatd.java 0000000 generic-all +applications/ctw/modules/jdk_management.java 0000000 generic-all +applications/ctw/modules/jdk_management_agent.java 0000000 generic-all +applications/ctw/modules/jdk_management_jfr.java 0000000 generic-all +applications/ctw/modules/jdk_naming_dns.java 0000000 generic-all +applications/ctw/modules/jdk_naming_rmi.java 0000000 generic-all +applications/ctw/modules/jdk_net.java 0000000 generic-all +applications/ctw/modules/jdk_nio_mapmode.java 0000000 generic-all +applications/ctw/modules/jdk_sctp.java 0000000 generic-all +applications/ctw/modules/jdk_security_auth.java 0000000 generic-all +applications/ctw/modules/jdk_security_jgss.java 0000000 generic-all +applications/ctw/modules/jdk_unsupported.java 0000000 generic-all +applications/ctw/modules/jdk_unsupported_desktop.java 0000000 generic-all +applications/ctw/modules/jdk_xml_dom.java 0000000 generic-all +applications/ctw/modules/jdk_zipfs.java 0000000 generic-all +compiler/arguments/CheckCICompilerCount.java 0000000 generic-all +compiler/arguments/CheckCompileThresholdScaling.java 0000000 generic-all +compiler/arguments/TestCompileThresholdScaling.java 0000000 generic-all +compiler/arguments/TestCompilerCounts.java#product 0000000 generic-all +compiler/arguments/TestMethodArguments.java 0000000 generic-all +compiler/arraycopy/TestACNonEscapingSrcBadAddPBaseType.java 0000000 generic-all +compiler/arraycopy/TestDeadCloneMem.java 0000000 generic-all +compiler/arraycopy/TestObjectArrayClone.java 0000000 generic-all +compiler/c2/ClearArray.java 0000000 generic-all +compiler/c2/ReachabilityFenceOnConstantTest.java 0000000 generic-all +compiler/c2/StackOverflowInSetNextCall.java 0000000 generic-all +compiler/c2/Test6866651.java 0000000 generic-all +compiler/c2/Test6901572.java 0000000 generic-all +compiler/c2/Test6931567.java 0000000 generic-all +compiler/c2/Test6992759.java 0000000 generic-all +compiler/c2/Test7020614.java 0000000 generic-all +compiler/c2/Test7024475.java 0000000 generic-all +compiler/c2/Test8004741.java 0000000 generic-all +compiler/c2/TestCMoveInfiniteGVN.java 0000000 generic-all +compiler/c2/TestCastX2NotProcessedIGVN.java 0000000 generic-all +compiler/c2/TestDeadDataLoopCmoveIdentity.java 0000000 generic-all +compiler/c2/TestDivModNodes.java 0000000 generic-all +compiler/c2/TestGVNCrash.java 0000000 generic-all +compiler/c2/TestInfiniteLoopCompilationFailure.java 0000000 generic-all +compiler/c2/TestLoadSplitThruPhiNull.java 0000000 generic-all +compiler/c2/TestMergeStores.java#id0 0000000 generic-all +compiler/c2/TestMergeStores.java#id1 0000000 generic-all +compiler/c2/TestMergeStores.java#id2 0000000 generic-all +compiler/c2/TestMergeStoresMemorySegment.java#byte-array 0000000 generic-all +compiler/c2/TestMergeStoresMemorySegment.java#byte-buffer 0000000 generic-all +compiler/c2/TestMergeStoresMemorySegment.java#byte-buffer-direct 0000000 generic-all +compiler/c2/TestMergeStoresMemorySegment.java#char-array 0000000 generic-all +compiler/c2/TestMergeStoresMemorySegment.java#double-array 0000000 generic-all +compiler/c2/TestMergeStoresMemorySegment.java#float-array 0000000 generic-all +compiler/c2/TestMergeStoresMemorySegment.java#int-array 0000000 generic-all +compiler/c2/TestMergeStoresMemorySegment.java#long-array 0000000 generic-all +compiler/c2/TestMergeStoresMemorySegment.java#native 0000000 generic-all +compiler/c2/TestMergeStoresMemorySegment.java#short-array 0000000 generic-all +compiler/c2/TestMergeStoresNullAdrType.java 0000000 generic-all +compiler/c2/TestModDivTopInput.java 0000000 generic-all +compiler/c2/TestRenumberLiveNodesInfiniteLoop.java 0000000 generic-all +compiler/c2/TestShiftRightAndAccumulate.java#id0 0000000 generic-all +compiler/c2/TestUnsignedByteCompare1.java 0000000 generic-all +compiler/c2/aarch64/TestFloat16Replicate.java 0000000 generic-all +compiler/c2/cmove/TestConditionalMove.java 0000000 generic-all +compiler/c2/cmove/TestScalarConditionalMoveCmpObj.java 0000000 generic-all +compiler/c2/gvn/MissedOptWithShiftConvCastAnd.java#id0 0000000 generic-all +compiler/c2/gvn/MissedOptWithShiftConvCastAnd.java#id1 0000000 generic-all +compiler/c2/gvn/TestCompressExpandTopInput.java 0000000 generic-all +compiler/c2/irTests/ConvF2HFIdealizationTests.java 0000000 generic-all +compiler/c2/irTests/FPModWithoutControlProj.java 0000000 generic-all +compiler/c2/irTests/TestConvI2LCastLongLoop.java 0000000 generic-all +compiler/c2/irTests/TestCountedLoopPhiValue.java 0000000 generic-all +compiler/c2/irTests/TestShiftAndMask.java 0000000 generic-all +compiler/c2/irTests/TestVectorizationMismatchedAccess.java 0000000 generic-all +compiler/c2/irTests/TestVectorizationNotRun.java 0000000 generic-all +compiler/c2/irTests/igvn/TestIntegerMulRing.java 0000000 generic-all +compiler/calls/NativeCalls.java 0000000 generic-all +compiler/ccp/TestAndConZeroCCP.java 0000000 generic-all +compiler/ccp/TestModValueMonotonic.java 0000000 generic-all +compiler/ccp/TestPushCmpU3Node.java 0000000 generic-all +compiler/ccp/TestShiftConvertAndNotification.java#id0 0000000 generic-all +compiler/cha/AbstractRootMethod.java 0000000 generic-all +compiler/cha/DefaultRootMethod.java 0000000 generic-all +compiler/cha/StrengthReduceInterfaceCall.java 0000000 generic-all +compiler/classUnloading/methodUnloading/TestMethodUnloading.java 0000000 generic-all +compiler/codecache/CheckSegmentedCodeCache.java 0000000 generic-all +compiler/codecache/OverflowCodeCacheTest.java#id0 0000000 generic-all +compiler/codecache/cli/TestSegmentedCodeCacheOption.java 0000000 generic-all +compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java 0000000 generic-all +compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java 0000000 generic-all +compiler/codegen/TestCheckCastPPRawOopSchedulingAtSafepoint.java 0000000 generic-all +compiler/codegen/TestGCMLoadPlacement.java 0000000 generic-all +compiler/codegen/TestTrichotomyExpressions.java 0000000 generic-all +compiler/controldependency/TestAddPChainMismatchedBase2.java 0000000 generic-all +compiler/controldependency/TestDivDependentOnMainLoopGuard.java 0000000 generic-all +compiler/controldependency/TestRemoveCastPPWithCMoveUse.java 0000000 generic-all +compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java 0000000 generic-all +compiler/escapeAnalysis/TestCopyOfBrokenAntiDependency.java 0000000 generic-all +compiler/escapeAnalysis/TestInvalidLocation.java 0000000 generic-all +compiler/escapeAnalysis/TestMemoryPhiAlias.java 0000000 generic-all +compiler/escapeAnalysis/TestRematerializeObjects.java#nEA 0000000 generic-all +compiler/escapeAnalysis/TestRematerializeObjects.java#yEA 0000000 generic-all +compiler/exceptions/TestLateMHInlineExceptions.java 0000000 generic-all +compiler/gcbarriers/EqvUncastStepOverBarrier.java 0000000 generic-all +compiler/gcbarriers/TestG1BarrierGeneration.java 0000000 generic-all +compiler/igvn/TestIncorrectDeadPathTypeNode.java 0000000 generic-all +compiler/inlining/LateInlineQueueDrainTest.java#id0 0000000 generic-all +compiler/inlining/LateInlineQueueDrainTest.java#id1 0000000 generic-all +compiler/inlining/TestDelayAfterInliningCutoff.java 0000000 generic-all +compiler/inlining/TestSubtypeCheckTypeInfo.java 0000000 generic-all +compiler/intrinsics/IntrinsicDisabledTest.java 0000000 generic-all +compiler/intrinsics/SortingDeoptimizationTest.java 0000000 generic-all +compiler/intrinsics/TestPopCountValueTransforms.java 0000000 generic-all +compiler/intrinsics/bigInteger/TestMultiplyToLen.java 0000000 generic-all +compiler/intrinsics/mathexact/OverflowTest.java#id0 0000000 generic-all +compiler/intrinsics/mathexact/OverflowTest.java#id1 0000000 generic-all +compiler/intrinsics/mathexact/OverflowTest.java#id2 0000000 generic-all +compiler/intrinsics/mathexact/OverflowTest.java#id3 0000000 generic-all +compiler/intrinsics/mathexact/OverflowTest.java#id4 0000000 generic-all +compiler/intrinsics/mathexact/OverflowTest.java#id5 0000000 generic-all +compiler/intrinsics/mathexact/OverflowTest.java#id6 0000000 generic-all +compiler/intrinsics/mathexact/sanity/AddExactIntTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/AddExactLongTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java 0000000 generic-all +compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java 0000000 generic-all +compiler/intrinsics/sha/TestDigest.java 0000000 generic-all +compiler/intrinsics/string/TestCountPositives.java#id0 0000000 generic-all +compiler/intrinsics/string/TestHasNegatives.java#id0 0000000 generic-all +compiler/intrinsics/string/TestStringConstructionIntrinsics.java#id0 0000000 generic-all +compiler/intrinsics/string/TestStringIntrinsics.java 0000000 generic-all +compiler/intrinsics/unsafe/DirectByteBufferTest.java 0000000 generic-all +compiler/intrinsics/unsafe/HeapByteBufferTest.java#id0 0000000 generic-all +compiler/intrinsics/unsafe/HeapByteBufferTest.java#id1 0000000 generic-all +compiler/intrinsics/zip/TestCRC32C.java 0000000 generic-all +compiler/jsr292/NonInlinedCall/InvokeTest.java 0000000 generic-all +compiler/jsr292/NonInlinedCall/RedefineTest.java 0000000 generic-all +compiler/jsr292/NullConstantReceiver.java 0000000 generic-all +compiler/locks/TestNestedLocksElimination.java 0000000 generic-all +compiler/longcountedloops/TestAssertWhenOuterStripMinedLoopRemoved.java 0000000 generic-all +compiler/longcountedloops/TestLoopNestTooManyTraps.java 0000000 generic-all +compiler/longcountedloops/TestShortRunningIntLoopWithLongChecksPredicates.java 0000000 generic-all +compiler/longcountedloops/TestShortRunningLongCountedLoop.java 0000000 generic-all +compiler/longcountedloops/TestShortRunningLongCountedLoopPredicatesClone.java 0000000 generic-all +compiler/longcountedloops/TestShortRunningLongCountedLoopScaleOverflow.java 0000000 generic-all +compiler/loopopts/FillArrayWithUnsafe.java 0000000 generic-all +compiler/loopopts/InfiniteLoopBadControlNeverBranch.java 0000000 generic-all +compiler/loopopts/TestArrayFillIntrinsic.java 0000000 generic-all +compiler/loopopts/TestCMoveLimitType.java#id0 0000000 generic-all +compiler/loopopts/TestCMoveWithDeadPhi.java 0000000 generic-all +compiler/loopopts/TestCountedLoopCastIV.java 0000000 generic-all +compiler/loopopts/TestDeadIrreducibleLoopsMain.java#id0 0000000 generic-all +compiler/loopopts/TestDeadIrreducibleLoopsMain.java#id1 0000000 generic-all +compiler/loopopts/TestDeadIrreducibleLoopsMain.java#id2 0000000 generic-all +compiler/loopopts/TestDeadIrreducibleLoopsMain.java#id3 0000000 generic-all +compiler/loopopts/TestInfLoopNearUsePlacement.java 0000000 generic-all +compiler/loopopts/TestInfiniteLoopCCP.java 0000000 generic-all +compiler/loopopts/TestInfiniteLoopNest.java 0000000 generic-all +compiler/loopopts/TestLoopPeeling.java 0000000 generic-all +compiler/loopopts/TestLoopPredicationDivZeroCheck.java 0000000 generic-all +compiler/loopopts/TestOverUnrolling2.java 0000000 generic-all +compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java#Xbatch 0000000 generic-all +compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java#Xcomp-compile-test 0000000 generic-all +compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java#Xcomp-run-inline 0000000 generic-all +compiler/loopopts/TestPeelingSkeletonPredicateInitialization.java 0000000 generic-all +compiler/loopopts/TestPredicateInputBelowLoopPredicate.java 0000000 generic-all +compiler/loopopts/TestReassociateInvariants.java 0000000 generic-all +compiler/loopopts/TestRedundantSafepointElimination.java 0000000 generic-all +compiler/loopopts/TestRemoveEmptyCountedLoop.java 0000000 generic-all +compiler/loopopts/TestRemoveEmptyLoop.java 0000000 generic-all +compiler/loopopts/TestSplitThruPhiInfinitely.java 0000000 generic-all +compiler/loopopts/TestStrangeControl.java 0000000 generic-all +compiler/loopopts/TestSunkNodeInInfiniteLoop.java 0000000 generic-all +compiler/loopopts/TestZeroTripGuardShared.java 0000000 generic-all +compiler/loopopts/VerifyGraphEdgesWithDeadCodeCheckFromSafepoints.java 0000000 generic-all +compiler/loopopts/superword/SumRedAbsNeg_Double.java 0000000 generic-all +compiler/loopopts/superword/SumRedAbsNeg_Float.java 0000000 generic-all +compiler/loopopts/superword/SumRedSqrt_Double.java 0000000 generic-all +compiler/loopopts/superword/SumRed_Double.java 0000000 generic-all +compiler/loopopts/superword/SumRed_Long.java 0000000 generic-all +compiler/loopopts/superword/TestAliasing.java 0000000 generic-all +compiler/loopopts/superword/TestAliasingFuzzer.java#random-flags 0000000 generic-all +compiler/loopopts/superword/TestAliasingFuzzer.java#vanilla 0000000 generic-all +compiler/loopopts/superword/TestAutoVectorizationOverrideProfitability.java 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vanilla-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vanilla-U 0000000 generic-all +compiler/loopopts/superword/TestEliminateAllocationWithCastP2XUse.java 0000000 generic-all +compiler/loopopts/superword/TestEquivalentInvariants.java 0000000 generic-all +compiler/loopopts/superword/TestLargeScaleAndStride.java#AlignVector 0000000 generic-all +compiler/loopopts/superword/TestLargeScaleAndStride.java#StoreToLoadForwardingFailureDetection 0000000 generic-all +compiler/loopopts/superword/TestLargeScaleAndStride.java#vanilla 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#byte-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#byte-array-AlignVector 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#byte-array-AlignVector-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#byte-array-AlignVector-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#byte-array-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#byte-array-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#byte-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#byte-buffer 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#byte-buffer-direct 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#char-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#double-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#float-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#int-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#int-array-AlignVector 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#long-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#long-array-AlignVector 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#native 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#native-AlignVector 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#native-AlignVector-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#native-AlignVector-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#native-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#native-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#native-NoSpeculativeAliasingCheck-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment.java#short-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#byte-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#byte-array-AlignVector 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#byte-array-AlignVector-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#byte-array-AlignVector-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#byte-array-NoAutoAlignment 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#byte-array-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#byte-array-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#byte-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#byte-buffer 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#byte-buffer-direct 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#char-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#double-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#float-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#int-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#int-array-AlignVector 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#int-array-AlignVector-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#int-array-NoAutoAlignment 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#int-array-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#int-array-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#int-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#long-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#long-array-AlignVector 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#long-array-AlignVector-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#long-array-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#native 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#native-AlignVector 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#native-AlignVector-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#native-AlignVector-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#native-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#native-NoSpeculativeAliasingCheck 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#native-NoSpeculativeAliasingCheck-NoShortRunningLongLoop 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentAliasing.java#short-array 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentByteSizeLongLoopLimit.java 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentField.java 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentFilterSummands.java 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java#byte-buffer-direct-AlignVector 0000000 generic-all +compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java#native-AlignVector 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment_ReassociateInvariants2.java 0000000 generic-all +compiler/loopopts/superword/TestMemorySegment_SubOfShift.java 0000000 generic-all +compiler/loopopts/superword/TestNegBaseOffset.java 0000000 generic-all +compiler/loopopts/superword/TestPickLastMemoryState.java 0000000 generic-all +compiler/loopopts/superword/TestReductions.java#force-vectorization 0000000 generic-all +compiler/loopopts/superword/TestReductions.java#no-vectorization 0000000 generic-all +compiler/loopopts/superword/TestReductions.java#vanilla 0000000 generic-all +compiler/loopopts/superword/TestReinterpretAndCast.java 0000000 generic-all +compiler/loopopts/superword/TestUnorderedReductionPartialVectorization.java 0000000 generic-all +compiler/loopopts/superword/Vec_MulAddS2I.java 0000000 generic-all +compiler/loopstripmining/AntiDependentLoadInOuterStripMinedLoop.java 0000000 generic-all +compiler/loopstripmining/LoadDependsOnIfIdenticalToLoopExit.java 0000000 generic-all +compiler/loopstripmining/TestConservativeAntiDep.java 0000000 generic-all +compiler/loopstripmining/TestEliminatedLoadPinnedOnBackedge.java 0000000 generic-all +compiler/loopstripmining/TestNondeleteableSafePoint.java 0000000 generic-all +compiler/loopstripmining/TestPinnedUseInOuterLSMUnusedBySfpt.java 0000000 generic-all +compiler/loopstripmining/TestStoresSunkInOuterStripMinedLoop.java 0000000 generic-all +compiler/membars/DekkerTest.java 0000000 generic-all +compiler/predicates/TestDisabledParsePredicates.java 0000000 generic-all +compiler/predicates/TestWrongRuntimePredicateDetection.java 0000000 generic-all +compiler/predicates/assertion/TestAssertionPredicates.java#NoFlags 0000000 generic-all +compiler/profiling/TestPrintMethodData.java 0000000 generic-all +compiler/rangechecks/RangeCheckEliminationScaleNotOne.java 0000000 generic-all +compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java 0000000 generic-all +compiler/rangechecks/TestArrayAccessAboveRCAfterUnswitching.java 0000000 generic-all +compiler/rangechecks/TestExplicitRangeChecks.java 0000000 generic-all +compiler/rangechecks/TestFoldComparesFuzzer.java 0000000 generic-all +compiler/rangechecks/TestFoldedIfsWrongReexec.java 0000000 generic-all +compiler/rangechecks/TestRangeCheckCmpUUnderflow.java 0000000 generic-all +compiler/regalloc/TestC2IntPressure.java 0000000 generic-all +compiler/runtime/Test7196199.java 0000000 generic-all +compiler/runtime/TestConstantsInError.java 0000000 generic-all +compiler/runtime/TestDontCompileHugeMethods.java 0000000 generic-all +compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java 0000000 generic-all +compiler/runtime/safepoints/TestRegisterRestoring.java 0000000 generic-all +compiler/splitif/TestCrashAtIGVNSplitIfSubType.java 0000000 generic-all +compiler/splitif/TestLongCountedLoopConvL2I.java 0000000 generic-all +compiler/splitif/TestSplitDivThroughPhiWithControl.java#fuzzer 0000000 generic-all +compiler/splitif/TestSplitDivThroughPhiWithControl.java#normal 0000000 generic-all +compiler/stable/TestStableBoolean.java 0000000 generic-all +compiler/stable/TestStableByte.java 0000000 generic-all +compiler/stable/TestStableChar.java 0000000 generic-all +compiler/stable/TestStableDouble.java 0000000 generic-all +compiler/stable/TestStableFloat.java 0000000 generic-all +compiler/stable/TestStableInt.java 0000000 generic-all +compiler/stable/TestStableLong.java 0000000 generic-all +compiler/stable/TestStableObject.java 0000000 generic-all +compiler/stable/TestStableShort.java 0000000 generic-all +compiler/stable/TestStableUByte.java 0000000 generic-all +compiler/stable/TestStableUShort.java 0000000 generic-all +compiler/startup/SmallCodeCacheStartup.java 0000000 generic-all +compiler/types/TestCheckCastPPBecomesTOP.java 0000000 generic-all +compiler/types/TestMeetInstanceId.java 0000000 generic-all +compiler/uncommontrap/Test8009761.java 0000000 generic-all +compiler/uncommontrap/TestStackBangMonitorOwned.java 0000000 generic-all +compiler/unsafe/UnsafeBooleanTest.java 0000000 generic-all +compiler/valhalla/valuetypes/CompareAndSetFlatArrayField.java 0000000 generic-all +compiler/valhalla/valuetypes/TestAcmpEdgeCases.java 0000000 generic-all +compiler/valhalla/valuetypes/TestAcmpStressUnstableIf.java 0000000 generic-all +compiler/valhalla/valuetypes/TestAcmpWithUnstableIf.java 0000000 generic-all +compiler/valhalla/valuetypes/TestAllocationMergeAndFolding.java#id0 0000000 generic-all +compiler/valhalla/valuetypes/TestAllocationMergeAndFolding.java#id1 0000000 generic-all +compiler/valhalla/valuetypes/TestAllocationMergeAndFolding.java#id2 0000000 generic-all +compiler/valhalla/valuetypes/TestAllocationMergeAndFolding.java#id3 0000000 generic-all +compiler/valhalla/valuetypes/TestAllocationMergeAndFolding.java#id4 0000000 generic-all +compiler/valhalla/valuetypes/TestAllocationMergeAndFolding.java#id6 0000000 generic-all +compiler/valhalla/valuetypes/TestArrayCopy.java#AlwaysIncrementalInline 0000000 generic-all +compiler/valhalla/valuetypes/TestArrayCopy.java#NoTraps 0000000 generic-all +compiler/valhalla/valuetypes/TestArrayCopy.java#default 0000000 generic-all +compiler/valhalla/valuetypes/TestArrayMetadata.java#expand-zero 0000000 generic-all +compiler/valhalla/valuetypes/TestArrayRematerializationWithProperties.java 0000000 generic-all +compiler/valhalla/valuetypes/TestArraysCopyOf.java#id0 0000000 generic-all +compiler/valhalla/valuetypes/TestArraysCopyOf.java#id1 0000000 generic-all +compiler/valhalla/valuetypes/TestArraysCopyOf.java#id2 0000000 generic-all +compiler/valhalla/valuetypes/TestArraysCopyOf.java#id3 0000000 generic-all +compiler/valhalla/valuetypes/TestArraysCopyOf.java#id4 0000000 generic-all +compiler/valhalla/valuetypes/TestArraysCopyOf.java#id5 0000000 generic-all +compiler/valhalla/valuetypes/TestArraysCopyOf.java#id6 0000000 generic-all +compiler/valhalla/valuetypes/TestBufferTearingC1.java 0000000 generic-all +compiler/valhalla/valuetypes/TestC1AcmpCEE.java 0000000 generic-all +compiler/valhalla/valuetypes/TestC2CCalls.java#no-bimorphic 0000000 generic-all +compiler/valhalla/valuetypes/TestC2CCalls.java#no-bimorphic-no-prof 0000000 generic-all +compiler/valhalla/valuetypes/TestC2CCalls.java#no-bimorphic-no-prof2 0000000 generic-all +compiler/valhalla/valuetypes/TestC2CCalls.java#no-bimorphic2 0000000 generic-all +compiler/valhalla/valuetypes/TestDeadSubstitutabilityCallInIdeal.java 0000000 generic-all +compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java#default 0000000 generic-all +compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java#no-TLAB 0000000 generic-all +compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java#no-mono 0000000 generic-all +compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java#no-mono-AII 0000000 generic-all +compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java#no-mono-no-FF 0000000 generic-all +compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java#no-mono-no-FF-AII 0000000 generic-all +compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java#no-mono-no-field 0000000 generic-all +compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java#no-mono-no-field-AII 0000000 generic-all +compiler/valhalla/valuetypes/TestExplosiveValueClass.java 0000000 generic-all +compiler/valhalla/valuetypes/TestFlatArrayCheckHoisting.java 0000000 generic-all +compiler/valhalla/valuetypes/TestIncorrectlyEliminatedStoreToFlatArray.java 0000000 generic-all +compiler/valhalla/valuetypes/TestIsSubstitutableReresolution.java 0000000 generic-all +compiler/valhalla/valuetypes/TestMakeFromOopReturnValue.java 0000000 generic-all +compiler/valhalla/valuetypes/TestMeetingAryPtr.java 0000000 generic-all +compiler/valhalla/valuetypes/TestMemBars.java 0000000 generic-all +compiler/valhalla/valuetypes/TestMissingOptUseBaseOopParsing.java 0000000 generic-all +compiler/valhalla/valuetypes/TestMultidimArrays.java 0000000 generic-all +compiler/valhalla/valuetypes/TestNestedLoopUnswitchingWithManyFlatArrayChecks.java 0000000 generic-all +compiler/valhalla/valuetypes/TestNewAcmp.java 0000000 generic-all +compiler/valhalla/valuetypes/TestReallocWithoutEA.java 0000000 generic-all +compiler/valhalla/valuetypes/TestSafepointAtPollReturn.java 0000000 generic-all +compiler/valhalla/valuetypes/TestScalarizedCallingConventionLimits.java 0000000 generic-all +compiler/valhalla/valuetypes/TestSpeculateArrayAccess.java 0000000 generic-all +compiler/valhalla/valuetypes/TestSubstitutabilityWithCOH.java 0000000 generic-all +compiler/valhalla/valuetypes/TestUnloadedReturnTypes.java 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#CompileonlyTest 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#DeoptimizeALot 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#DontInlineHelper 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#DontInlineMyAbstractInit 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#DontInlineMyValueInit 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#DontInlineObjectInit 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#DontInlineObjectInitDeoptimizeALot 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#StressIncrementalInlining 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#StressIncrementalInliningCompileOnlyTest 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#StressIncrementalInliningDontInlineMyAbstractInit 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#StressIncrementalInliningDontInlineMyValueInit 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#StressIncrementalInliningDontInlineObjectInit 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#StressIncrementalInliningOnStackReplacement 0000000 generic-all +compiler/valhalla/valuetypes/TestValueConstruction.java#Xbatch 0000000 generic-all +compiler/vectorization/TestAbsCharVector.java 0000000 generic-all +compiler/vectorization/TestFloat16VectorOperations.java 0000000 generic-all +compiler/vectorization/TestMacroLogicVector.java 0000000 generic-all +compiler/vectorization/TestReplicateAtConv.java 0000000 generic-all +compiler/vectorization/TestReplicateLoopIV.java 0000000 generic-all +compiler/vectorization/TestRotateByteAndShortVector.java 0000000 generic-all +compiler/vectorization/TestSubwordTruncation.java 0000000 generic-all +compiler/vectorization/TestVectorAlgorithms.java#noOptimizeFill 0000000 generic-all +compiler/vectorization/TestVectorAlgorithms.java#noSuperWord 0000000 generic-all +compiler/vectorization/TestVectorAlgorithms.java#vanilla 0000000 generic-all +gc/g1/TestCodeCacheUnloadDuringConcCycle.java 0000000 generic-all +gc/g1/TestCodeCacheWhiteBox.java 0000000 generic-all +gc/parallel/TestObjectCountAfterGC.java 0000000 generic-all +gtest/GTestWrapper.java 0000000 generic-all +gtest/LargePageGtests.java#use-large-pages 0000000 generic-all +gtest/LargePageGtests.java#use-large-pages-1G 0000000 generic-all +gtest/NMTGtests.java#nmt-detail 0000000 generic-all +gtest/NMTGtests.java#nmt-off 0000000 generic-all +gtest/NMTGtests.java#nmt-summary 0000000 generic-all +runtime/BootClassAppendProp/BootClassPathAppend.java 0000000 generic-all +runtime/ErrorHandling/CreateCoredumpOnCrash.java 0000000 generic-all +runtime/HiddenClasses/TestHiddenClassUnloading.java 0000000 generic-all +runtime/LocalLong/LocalLongTest.java 0000000 generic-all +runtime/Metaspace/DefineClass.java 0000000 generic-all +runtime/Monitor/TestRecursiveLocking.java#Xint_alternate_AB 0000000 generic-all +runtime/Monitor/TestRecursiveLocking.java#Xint_outer_inner 0000000 generic-all +runtime/NMT/MallocLimitTest.java#compiler-limit-fatal 0000000 generic-all +runtime/NMT/MallocLimitTest.java#compiler-limit-oom 0000000 generic-all +runtime/NMT/SummaryDiffThreadCount.java 0000000 generic-all +runtime/NMT/VirtualAllocCommitMerge.java 0000000 generic-all +runtime/cds/AOTMapTest.java 0000000 generic-all +runtime/cds/appcds/ArchivedFieldMetadataMismatchTest.java 0000000 generic-all +runtime/cds/appcds/HelloValueClassTest.java 0000000 generic-all +runtime/cds/appcds/RewriteBytecodesInlineTest.java 0000000 generic-all +runtime/cds/appcds/ValueFieldExclusionTest.java#flattened 0000000 generic-all +runtime/cds/appcds/ValueFieldExclusionTest.java#static 0000000 generic-all +runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java 0000000 generic-all +runtime/cds/appcds/aotCache/AOTMapTest.java#aot 0000000 generic-all +runtime/cds/appcds/aotCache/InvalidModuleOptions.java 0000000 generic-all +runtime/cds/appcds/aotCache/LoadableDescriptorTest.java 0000000 generic-all +runtime/cds/appcds/aotCache/RedefineClassesInProfile.java 0000000 generic-all +runtime/cds/appcds/aotCache/aotClassLinking/AOTClassLinkingVMOptions.java 0000000 generic-all +runtime/cds/appcds/aotCache/aotClassLinking/AddExports.java 0000000 generic-all +runtime/cds/appcds/aotCache/aotClassLinking/TestSetupAOTTest.java 0000000 generic-all +runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java 0000000 generic-all +runtime/cds/appcds/dynamicArchive/DynamicArchiveRelocationTest.java 0000000 generic-all +runtime/cds/appcds/dynamicArchive/HelloDynamicValueClass.java 0000000 generic-all +runtime/cds/appcds/jigsaw/modulepath/ExportModule.java 0000000 generic-all +runtime/cds/appcds/resolvedConstants/ResolvedConstants.java#aot 0000000 generic-all +runtime/cds/appcds/resolvedConstants/ResolvedConstants.java#dynamic 0000000 generic-all +runtime/cds/appcds/resolvedConstants/ResolvedConstants.java#static 0000000 generic-all +runtime/handshake/AsyncHandshakeWalkStackTest.java 0000000 generic-all +runtime/handshake/HandshakeTransitionTest.java 0000000 generic-all +runtime/handshake/HandshakeWalkStackTest.java 0000000 generic-all +runtime/handshake/SystemMembarHandshakeTransitionTest.java 0000000 generic-all +runtime/jni/nativeStack/TestNativeStack.java 0000000 generic-all +runtime/lockStack/TestStackWalk.java 0000000 generic-all +runtime/locking/TestRecursiveMonitorChurn.java 0000000 generic-all +runtime/logging/DeoptLoggingTest.java 0000000 generic-all +runtime/logging/ExceptionsTest.java 0000000 generic-all +runtime/logging/MonitorMismatchTest.java 0000000 generic-all +runtime/valhalla/valuetypes/AnnotationsTests.java 0000000 generic-all +runtime/valhalla/valuetypes/FlatArraysTest.java#default 0000000 generic-all +runtime/valhalla/valuetypes/FlattenableSemanticTest.java 0000000 generic-all +runtime/valhalla/valuetypes/Ifacmp.java 0000000 generic-all +runtime/valhalla/valuetypes/MonitorEnterTest.java 0000000 generic-all +runtime/valhalla/valuetypes/NPEInPreviewTest.java 0000000 generic-all +runtime/valhalla/valuetypes/QuickeningTest.java 0000000 generic-all +runtime/valhalla/valuetypes/TestArrayCopy.java 0000000 generic-all +runtime/valhalla/valuetypes/ValueWithJni.java 0000000 generic-all +runtime/valhalla/valuetypes/field_layout/ValueComparisonTest.java 0000000 generic-all +runtime/valhalla/valuetypes/field_layout/ValueObjectContainerTest.java 0000000 generic-all +runtime/valhalla/valuetypes/field_layout/ValueRandomLayoutTest.java 0000000 generic-all +runtime/valhalla/valuetypes/verifier/VTMonitor.java 0000000 generic-all +runtime/whitebox/WBStackSize.java 0000000 generic-all +serviceability/dcmd/compiler/PerfMapTest.java 0000000 generic-all +serviceability/dcmd/framework/HelpTest.java 0000000 generic-all +serviceability/dcmd/framework/InvalidCommandTest.java 0000000 generic-all +serviceability/dcmd/framework/VMVersionTest.java 0000000 generic-all +serviceability/dcmd/thread/PrintConcurrentLocksTest.java 0000000 generic-all +serviceability/dcmd/thread/PrintTest.java 0000000 generic-all +serviceability/jvmti/8036666/GetObjectLockCount.java 0000000 generic-all +serviceability/jvmti/CanGenerateAllClassHook/CanGenerateAllClassHook.java 0000000 generic-all +serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGeneratedTest.java 0000000 generic-all +serviceability/jvmti/ForceEarlyReturn/ForceEarlyReturnStrictInitFields.java 0000000 generic-all +serviceability/jvmti/GetLocalVariable/GetLocalVars.java 0000000 generic-all +serviceability/jvmti/GetLocalVariable/GetSetLocalSlotOverflow.java 0000000 generic-all +serviceability/jvmti/GetModulesInfo/JvmtiGetAllModulesTest.java 0000000 generic-all +serviceability/jvmti/GetOwnedMonitorStackDepthInfo/GetOwnedMonitorStackDepthInfoTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorEventOnOffTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorGCParallelTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorGCSerialTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorGCTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorInterpreterArrayTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatIntervalTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorTest.java 0000000 generic-all +serviceability/jvmti/NotifyFramePop/NotifyFramePopTest.java 0000000 generic-all +serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java 0000000 generic-all +serviceability/jvmti/SuspendWithCurrentThread/SuspendWithCurrentThread.java 0000000 generic-all +serviceability/jvmti/SuspendWithObjectMonitorEnter/SuspendWithObjectMonitorEnter.java 0000000 generic-all +serviceability/jvmti/events/FramePop/ClearAllFramePops/ClearAllFramePops.java#platform 0000000 generic-all +serviceability/jvmti/events/FramePop/ClearAllFramePops/ClearAllFramePops.java#virtual 0000000 generic-all +serviceability/jvmti/events/FramePop/framepop01/framepop01.java 0000000 generic-all +serviceability/jvmti/events/FramePop/framepop02/framepop02.java#id0 0000000 generic-all +serviceability/jvmti/events/FramePop/framepop02/framepop02.java#id1 0000000 generic-all +serviceability/jvmti/events/MethodEntry/mentry01/mentry01.java 0000000 generic-all +serviceability/jvmti/events/MethodExit/mexit01/mexit01.java 0000000 generic-all +serviceability/jvmti/events/MethodExit/mexit02/mexit02.java 0000000 generic-all +serviceability/jvmti/events/NotifyFramePopStressTest/NotifyFramePopStressTest.java 0000000 generic-all +serviceability/jvmti/thread/GetCurrentContendedMonitor/contmon01/contmon01.java 0000000 generic-all +serviceability/jvmti/thread/GetCurrentContendedMonitor/contmon02/contmon02.java 0000000 generic-all +serviceability/jvmti/thread/GetFrameLocation/frameloc01/frameloc01.java 0000000 generic-all +serviceability/jvmti/thread/GetStackTrace/GetStackTraceCurrentThreadTest/GetStackTraceCurrentThreadTest.java 0000000 generic-all +serviceability/jvmti/thread/ResumeThread/resumethrd01/resumethrd01.java 0000000 generic-all +serviceability/jvmti/thread/ResumeThread/resumethrd02/resumethrd02.java 0000000 generic-all +serviceability/jvmti/thread/ResumeThreadList/resumethrdlst01/resumethrdlst01.java 0000000 generic-all +serviceability/jvmti/thread/ResumeThreadList/resumethrdlst02/resumethrdlst02.java 0000000 generic-all +serviceability/jvmti/thread/SuspendThread/suspendthrd01/suspendthrd01.java 0000000 generic-all +serviceability/jvmti/thread/SuspendThreadList/suspendthrdlst01/suspendthrdlst01.java 0000000 generic-all +serviceability/jvmti/valhalla/ForceEarlyReturn/ValueForceEarlyReturn.java 0000000 generic-all +serviceability/jvmti/valhalla/GetCtorLocal/ValueGetCtorLocal.java 0000000 generic-all +serviceability/jvmti/valhalla/GetSetLocal/ValueGetSetLocal.java 0000000 generic-all +serviceability/jvmti/valhalla/Heapwalking/ValueHeapwalkingTest.java 0000000 generic-all +serviceability/jvmti/valhalla/SetTag/ValueTagMapTest.java 0000000 generic-all +serviceability/jvmti/vthread/BoundVThreadTest/BoundVThreadTest.java 0000000 generic-all +serviceability/jvmti/vthread/CheckHiddenFrames/CheckHiddenFrames.java 0000000 generic-all +serviceability/jvmti/vthread/FollowReferences/VThreadStackRefTest.java#no-vmcontinuations 0000000 generic-all +serviceability/jvmti/vthread/ForceEarlyReturnTest/ForceEarlyReturnTest.java#no-vmcontinuations 0000000 generic-all +serviceability/jvmti/vthread/ForceEarlyReturnTest/ForceEarlyReturnTest.java#platform 0000000 generic-all +serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java#no-vmcontinuations 0000000 generic-all +serviceability/jvmti/vthread/NullAsCurrentThreadTest/NullAsCurrentThreadTest.java#default 0000000 generic-all +serviceability/jvmti/vthread/PopFrameTest/PopFrameTest.java#no-vmcontinuations 0000000 generic-all +serviceability/jvmti/vthread/PopFrameTest/PopFrameTest.java#platform 0000000 generic-all +serviceability/jvmti/vthread/VThreadNotifyFramePopTest/VThreadNotifyFramePopTest.java#default 0000000 generic-all diff -Nru openjdk-25-25.0.4.1+1/debian/tests/problems-loong-jdk.txt openjdk-25-25.0.5+8/debian/tests/problems-loong-jdk.txt --- openjdk-25-25.0.4.1+1/debian/tests/problems-loong-jdk.txt 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/tests/problems-loong-jdk.txt 2026-10-22 00:58:09.000000000 +0000 @@ -0,0 +1,771 @@ +com/sun/crypto/provider/CICO/PBEFunc/CICOPBEFuncTest.java 0000000 generic-all +com/sun/crypto/provider/Cipher/AEAD/AEADBufferTest.java 0000000 generic-all +com/sun/crypto/provider/Cipher/AES/CICO.java 0000000 generic-all +com/sun/crypto/provider/Cipher/DES/PerformanceTest.java 0000000 generic-all +com/sun/crypto/provider/Cipher/KeyWrap/TestCipherKeyWrapperTest.java 0000000 generic-all +com/sun/crypto/provider/Cipher/PBE/PBES2Test.java 0000000 generic-all +com/sun/crypto/provider/Cipher/PBE/PBESameBuffer/PBESameBuffer.java 0000000 generic-all +com/sun/crypto/provider/Cipher/PBE/PBESealedObject.java 0000000 generic-all +com/sun/crypto/provider/Cipher/PBE/PBMacBuffer.java 0000000 generic-all +com/sun/crypto/provider/Cipher/PBE/PBMacDoFinalVsUpdate.java 0000000 generic-all +com/sun/crypto/provider/Cipher/PBE/TestCipherKeyWrapperPBEKey.java 0000000 generic-all +com/sun/crypto/provider/Cipher/TextLength/TestCipherTextLength.java 0000000 generic-all +com/sun/crypto/provider/KDF/HKDFSaltIKMTest.java 0000000 generic-all +com/sun/crypto/provider/KeyAgreement/DHKeyAgreementPadding.java 0000000 generic-all +com/sun/crypto/provider/KeyAgreement/SameDHKeyStressTest.java 0000000 generic-all +com/sun/crypto/provider/KeyAgreement/SupportedDHKeys.java 0000000 generic-all +com/sun/crypto/provider/KeyFactory/TestProviderLeak.java 0000000 generic-all +com/sun/jdi/EarlyReturnTest.java 0000000 generic-all +com/sun/jdi/FramesTest.java 0000000 generic-all +com/sun/jdi/MonitorFrameInfo.java 0000000 generic-all +com/sun/jdi/PopAndStepTest.java 0000000 generic-all +com/sun/jdi/PopAsynchronousTest.java 0000000 generic-all +com/sun/jdi/redefineMethod/RedefineTest.java 0000000 generic-all +com/sun/net/httpserver/FailAndStopTest.java 0000000 generic-all +com/sun/net/httpserver/HttpsParametersClientAuthTest.java 0000000 generic-all +com/sun/net/httpserver/Test1.java 0000000 generic-all +com/sun/security/ec/ECOperationsFuzzTest.java#id0 0000000 generic-all +com/sun/security/ec/ECOperationsFuzzTest.java#id1 0000000 generic-all +com/sun/security/util/math/intpoly/MontgomeryPolynomialFuzzTest.java#id0 0000000 generic-all +com/sun/security/util/math/intpoly/MontgomeryPolynomialFuzzTest.java#id1 0000000 generic-all +java/foreign/StdLibTest.java 0000000 generic-all +java/foreign/TestDowncallStack.java 0000000 generic-all +java/foreign/TestLargeSegmentCopy.java 0000000 generic-all +java/foreign/TestRestricted.java 0000000 generic-all +java/foreign/TestStringEncoding.java 0000000 generic-all +java/foreign/TestUpcallScope.java 0000000 generic-all +java/foreign/TestUpcallStack.java 0000000 generic-all +java/io/BufferedInputStream/TransferTo.java 0000000 generic-all +java/io/DataInputStream/ReadUTF.java 0000000 generic-all +java/io/DataOutputStream/WriteUTF.java 0000000 generic-all +java/io/PushbackInputStream/TransferTo.java 0000000 generic-all +java/io/SequenceInputStream/TransferTo.java 0000000 generic-all +java/io/Serializable/valueObjects/SerializeAllValueClasses.java 0000000 generic-all +java/io/Serializable/valueObjects/SerializedObjectCombo.java 0000000 generic-all +java/io/Serializable/valueObjects/ValueSerializationTest.java 0000000 generic-all +java/lang/Character/CheckUnicode.java 0000000 generic-all +java/lang/Character/Supplementary.java 0000000 generic-all +java/lang/Character/UnicodeCasingTest.java 0000000 generic-all +java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java 0000000 generic-all +java/lang/CompressExpandTest.java 0000000 generic-all +java/lang/Float/Binary16Conversion.java 0000000 generic-all +java/lang/Object/ValueObjects.java 0000000 generic-all +java/lang/StackWalker/LocalsAndOperands.java#id0 0000000 generic-all +java/lang/StackWalker/LocalsAndOperands.java#id1 0000000 generic-all +java/lang/StrictMath/ExhaustingTests.java 0000000 generic-all +java/lang/String/CompactString/MaxSizeUTF16String.java 0000000 generic-all +java/lang/String/IndexOf.java#id0 0000000 generic-all +java/lang/String/Split.java 0000000 generic-all +java/lang/String/StringRepeat.java#id1 0000000 generic-all +java/lang/String/UnicodeCasingTest.java 0000000 generic-all +java/lang/StringBuffer/ECoreIndexOf.java#id0 0000000 generic-all +java/lang/StringBuilder/HugeCapacity.java 0000000 generic-all +java/lang/StringBuilder/RacingSBThreads.java 0000000 generic-all +java/lang/System/LoggerFinder/SignedLoggerFinderTest/SignedLoggerFinderTest.java 0000000 generic-all +java/lang/Thread/GenerifyStackTraces.java 0000000 generic-all +java/lang/Thread/virtual/stress/LotsOfUncontendedMonitorEnter.java 0000000 generic-all +java/lang/constant/MethodTypeDescTest.java 0000000 generic-all +java/lang/invoke/LFCaching/LFGarbageCollectedTest.java 0000000 generic-all +java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java 0000000 generic-all +java/lang/invoke/VarHandles/VarHandleTestAccessNullRestrictedValue.java 0000000 generic-all +java/lang/invoke/VarHandles/VarHandleTestAccessValue.java 0000000 generic-all +java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessNullRestrictedValue.java 0000000 generic-all +java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java 0000000 generic-all +java/lang/invoke/VarHandles/VarHandleTestMethodTypeNullRestrictedValue.java 0000000 generic-all +java/lang/invoke/VarHandles/VarHandleTestMethodTypeValue.java 0000000 generic-all +java/lang/invoke/callerSensitive/CallerSensitiveAccess.java 0000000 generic-all +java/lang/ref/ReachabilityFenceTest.java 0000000 generic-all +java/lang/reflect/PublicMethods/PublicMethodsTest.java 0000000 generic-all +java/math/BigDecimal/SquareRootTests.java 0000000 generic-all +java/math/BigInteger/ByteArrayConstructorTest.java 0000000 generic-all +java/math/BigInteger/LargeValueExceptions.java 0000000 generic-all +java/math/BigInteger/PrimeTest.java 0000000 generic-all +java/math/BigInteger/largeMemory/StringConstructorOverflow.java 0000000 generic-all +java/math/BigInteger/largeMemory/SymmetricRangeTests.java 0000000 generic-all +java/net/HttpURLConnection/SetAuthenticator/HTTPSetAuthenticatorTest.java 0000000 generic-all +java/net/MulticastSocket/NoLoopbackPackets.java 0000000 generic-all +java/net/MulticastSocket/SetLoopbackMode.java 0000000 generic-all +java/net/MulticastSocket/Test.java 0000000 generic-all +java/net/httpclient/AsFileDownloadTest.java 0000000 generic-all +java/net/httpclient/BasicHTTP3Test.java 0000000 generic-all +java/net/httpclient/BasicRedirectTest.java 0000000 generic-all +java/net/httpclient/BufferSize1Test.java 0000000 generic-all +java/net/httpclient/CancelRequestTest.java 0000000 generic-all +java/net/httpclient/CancelStreamedBodyTest.java 0000000 generic-all +java/net/httpclient/CancelledPartialResponseTest.java 0000000 generic-all +java/net/httpclient/CancelledResponse2.java 0000000 generic-all +java/net/httpclient/ConcurrentResponses.java 0000000 generic-all +java/net/httpclient/CookieHeaderTest.java 0000000 generic-all +java/net/httpclient/CustomRequestPublisher.java 0000000 generic-all +java/net/httpclient/CustomResponseSubscriber.java 0000000 generic-all +java/net/httpclient/DependentActionsTest.java 0000000 generic-all +java/net/httpclient/DependentPromiseActionsTest.java 0000000 generic-all +java/net/httpclient/DigestEchoClientSSL.java 0000000 generic-all +java/net/httpclient/DurationOverflowTest.java#withPropertyConfig 0000000 generic-all +java/net/httpclient/DurationOverflowTest.java#withoutPropertyConfig 0000000 generic-all +java/net/httpclient/EncodedCharsInURI.java 0000000 generic-all +java/net/httpclient/EscapedOctetsInURI.java 0000000 generic-all +java/net/httpclient/FilePublisherTest.java 0000000 generic-all +java/net/httpclient/FlowAdapterPublisherTest.java 0000000 generic-all +java/net/httpclient/FlowAdapterSubscriberTest.java 0000000 generic-all +java/net/httpclient/ForbiddenHeadTest.java 0000000 generic-all +java/net/httpclient/GZIPInputStreamTest.java 0000000 generic-all +java/net/httpclient/HeadTest.java#withCertificateCompression 0000000 generic-all +java/net/httpclient/HeadTest.java#withoutCertificateCompression 0000000 generic-all +java/net/httpclient/HttpClientClose.java 0000000 generic-all +java/net/httpclient/HttpClientLocalAddrTest.java 0000000 generic-all +java/net/httpclient/HttpClientShutdown.java 0000000 generic-all +java/net/httpclient/HttpRedirectTest.java 0000000 generic-all +java/net/httpclient/HttpResponseConnectionLabelTest.java 0000000 generic-all +java/net/httpclient/HttpVersionsTest.java 0000000 generic-all +java/net/httpclient/ISO_8859_1_Test.java 0000000 generic-all +java/net/httpclient/InvalidInputStreamSubscriptionRequest.java#http1 0000000 generic-all +java/net/httpclient/InvalidInputStreamSubscriptionRequest.java#http2 0000000 generic-all +java/net/httpclient/InvalidInputStreamSubscriptionRequest.java#http3 0000000 generic-all +java/net/httpclient/InvalidSubscriptionRequest.java 0000000 generic-all +java/net/httpclient/MappingResponseSubscriber.java 0000000 generic-all +java/net/httpclient/NoBodyPartOne.java 0000000 generic-all +java/net/httpclient/NoBodyPartThree.java 0000000 generic-all +java/net/httpclient/NoBodyPartTwo.java 0000000 generic-all +java/net/httpclient/NonAsciiCharsInURI.java 0000000 generic-all +java/net/httpclient/PathSubscriber/BodyHandlerOfFileDownloadTest.java 0000000 generic-all +java/net/httpclient/PathSubscriber/BodyHandlerOfFileTest.java 0000000 generic-all +java/net/httpclient/PathSubscriber/BodySubscriberOfFileTest.java 0000000 generic-all +java/net/httpclient/PlainConnectionLockTest.java#default 0000000 generic-all +java/net/httpclient/ProxyAuthDisabledSchemesSSL.java 0000000 generic-all +java/net/httpclient/ResponseBodyBeforeError.java 0000000 generic-all +java/net/httpclient/ResponsePublisher.java 0000000 generic-all +java/net/httpclient/ShortResponseBodyGet.java 0000000 generic-all +java/net/httpclient/ShortResponseBodyPost.java 0000000 generic-all +java/net/httpclient/ShortResponseBodyPostWithRetry.java 0000000 generic-all +java/net/httpclient/SpecialHeadersTest.java 0000000 generic-all +java/net/httpclient/StreamingBody.java 0000000 generic-all +java/net/httpclient/ThrowingPublishersCustomAfterCancel.java 0000000 generic-all +java/net/httpclient/ThrowingPublishersCustomBeforeCancel.java 0000000 generic-all +java/net/httpclient/ThrowingPublishersIOAfterCancel.java 0000000 generic-all +java/net/httpclient/ThrowingPublishersIOBeforeCancel.java 0000000 generic-all +java/net/httpclient/ThrowingPublishersInNextRequest.java 0000000 generic-all +java/net/httpclient/ThrowingPublishersInRequest.java 0000000 generic-all +java/net/httpclient/ThrowingPublishersInSubscribe.java 0000000 generic-all +java/net/httpclient/ThrowingPublishersSanity.java 0000000 generic-all +java/net/httpclient/ThrowingSubscribersAsInputStream.java 0000000 generic-all +java/net/httpclient/ThrowingSubscribersAsInputStreamAsync.java 0000000 generic-all +java/net/httpclient/ThrowingSubscribersAsLimiting.java 0000000 generic-all +java/net/httpclient/ThrowingSubscribersAsLimitingAsync.java 0000000 generic-all +java/net/httpclient/ThrowingSubscribersAsLines.java 0000000 generic-all +java/net/httpclient/ThrowingSubscribersAsLinesAsync.java 0000000 generic-all +java/net/httpclient/ThrowingSubscribersAsString.java 0000000 generic-all +java/net/httpclient/ThrowingSubscribersAsStringAsync.java 0000000 generic-all +java/net/httpclient/ThrowingSubscribersSanity.java 0000000 generic-all +java/net/httpclient/TimeoutResponseBodyTest.java#retriesDisabled 0000000 generic-all +java/net/httpclient/TimeoutResponseBodyTest.java#retriesEnabledForResponseFailure 0000000 generic-all +java/net/httpclient/TimeoutResponseHeaderTest.java#retriesEnabledForResponseFailure 0000000 generic-all +java/net/httpclient/TlsContextTest.java 0000000 generic-all +java/net/httpclient/UserAuthWithAuthenticator.java 0000000 generic-all +java/net/httpclient/UserCookieTest.java 0000000 generic-all +java/net/httpclient/altsvc/AltServiceReasonableAssurance.java 0000000 generic-all +java/net/httpclient/http2/BadHeadersTest.java 0000000 generic-all +java/net/httpclient/http2/ContinuationFrameTest.java 0000000 generic-all +java/net/httpclient/http2/H2GoAwayTest.java 0000000 generic-all +java/net/httpclient/http2/HpackBinaryTestDriver.java 0000000 generic-all +java/net/httpclient/http2/HpackCircularBufferDriver.java 0000000 generic-all +java/net/httpclient/http2/HpackDecoderDriver.java 0000000 generic-all +java/net/httpclient/http2/HpackEncoderDriver.java 0000000 generic-all +java/net/httpclient/http2/HpackHuffmanDriver.java 0000000 generic-all +java/net/httpclient/http2/SimpleGet.java 0000000 generic-all +java/net/httpclient/http3/H3BadHeadersTest.java 0000000 generic-all +java/net/httpclient/http3/H3BasicTest.java 0000000 generic-all +java/net/httpclient/http3/H3ConnectionPoolTest.java 0000000 generic-all +java/net/httpclient/http3/H3DataLimitsTest.java 0000000 generic-all +java/net/httpclient/http3/H3ErrorHandlingTest.java 0000000 generic-all +java/net/httpclient/http3/H3FixedThreadPoolTest.java 0000000 generic-all +java/net/httpclient/http3/H3MalformedResponseTest.java 0000000 generic-all +java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java#reno-cc 0000000 generic-all +java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java#useNioSelector 0000000 generic-all +java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java#with-continuations 0000000 generic-all +java/net/httpclient/http3/H3SimpleGet.java#reno-cc 0000000 generic-all +java/net/httpclient/http3/H3SimpleGet.java#useNioSelector 0000000 generic-all +java/net/httpclient/http3/H3SimpleGet.java#with-continuations 0000000 generic-all +java/net/httpclient/http3/H3SimplePost.java 0000000 generic-all +java/net/httpclient/http3/H3StreamLimitReachedTest.java#with-default-wait 0000000 generic-all +java/net/httpclient/http3/H3StreamLimitReachedTest.java#with-no-wait 0000000 generic-all +java/net/httpclient/websocket/HandshakeUrlEncodingTest.java 0000000 generic-all +java/net/httpclient/websocket/HeaderWriterDriver.java 0000000 generic-all +java/net/httpclient/websocket/ReaderDriver.java 0000000 generic-all +java/net/httpclient/websocket/WSHandshakeExceptionTest.java 0000000 generic-all +java/nio/Buffer/AllocateDirectInit.java 0000000 generic-all +java/nio/Buffer/BulkPutBuffer.java 0000000 generic-all +java/nio/Buffer/EqualsCompareTest.java 0000000 generic-all +java/nio/MappedByteBuffer/Truncate.java 0000000 generic-all +java/nio/channels/Channels/TransferTo.java 0000000 generic-all +java/nio/channels/Channels/TransferTo2.java 0000000 generic-all +java/nio/channels/Channels/TransferTo_2GB_transferFrom.java 0000000 generic-all +java/nio/channels/Channels/TransferTo_2GB_transferTo.java 0000000 generic-all +java/nio/channels/FileChannel/ExpandingMap.java 0000000 generic-all +java/nio/channels/FileChannel/LargeGatheringWrite.java 0000000 generic-all +java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java 0000000 generic-all +java/nio/channels/Selector/RegisterDuringSelect.java 0000000 generic-all +java/nio/channels/Selector/SelectAndClose.java 0000000 generic-all +java/nio/charset/CharsetDecoder/XcodeOverflow.java 0000000 generic-all +java/nio/charset/coders/BashStreams.java 0000000 generic-all +java/security/AsymmetricKey/GetParams.java 0000000 generic-all +java/security/KeyAgreement/KeySizeTest.java 0000000 generic-all +java/security/KeyPairGenerator/Failover.java 0000000 generic-all +java/security/KeyPairGenerator/FinalizeHalf.java 0000000 generic-all +java/security/KeyStore/PBETest.java 0000000 generic-all +java/security/KeyStore/PKCS12/ConvertP12Test.java 0000000 generic-all +java/security/KeyStore/PKCS12/EntryProtectionTest.java 0000000 generic-all +java/security/KeyStore/PKCS12/KeytoolWriteP12Test.java 0000000 generic-all +java/security/KeyStore/PKCS12/MetadataEmptyTest.java 0000000 generic-all +java/security/KeyStore/PKCS12/MetadataStoreLoadTest.java 0000000 generic-all +java/security/KeyStore/PKCS12/StoreTrustedCertAPITest.java 0000000 generic-all +java/security/KeyStore/PKCS12/StoreTrustedCertKeytool.java 0000000 generic-all +java/security/KeyStore/PKCS12/WriteP12Test.java 0000000 generic-all +java/security/KeyStore/ProbeKeystores.java 0000000 generic-all +java/security/KeyStore/TestKeyStoreBasic.java 0000000 generic-all +java/security/KeyStore/TestKeyStoreEntry.java 0000000 generic-all +java/security/MessageDigest/TestDigestIOStream.java 0000000 generic-all +java/security/MessageDigest/TestSameLength.java 0000000 generic-all +java/security/PEM/PEMEncoderTest.java 0000000 generic-all +java/security/SecureRandom/NoSync.java 0000000 generic-all +java/security/Security/signedfirst/DynStatic.java 0000000 generic-all +java/security/SignedJar/SignedJarWithCustomClassLoader.java 0000000 generic-all +java/security/SignedObject/Chain.java 0000000 generic-all +java/security/cert/CertPathValidator/crlDP/CheckAllCRLs.java 0000000 generic-all +java/sql/test/sql/JavatimeTest.java 0000000 generic-all +java/text/Format/DateFormat/Bug6530336.java 0000000 generic-all +java/text/Format/DateFormat/Bug8141243.java 0000000 generic-all +java/text/Format/DateFormat/Bug8209047.java 0000000 generic-all +java/text/Format/DateFormat/CaseInsensitiveParseTest.java 0000000 generic-all +java/text/Format/DateFormat/DateFormatTest.java 0000000 generic-all +java/text/Format/DateFormat/SDFTCKZoneNamesTest.java 0000000 generic-all +java/text/Format/DateFormat/SimpleDateFormatPatternTest.java 0000000 generic-all +java/text/Format/NumberFormat/NumberRegression.java 0000000 generic-all +java/text/Format/NumberFormat/NumberTest.java 0000000 generic-all +java/time/tck/java/time/TCKLocalDateTime.java 0000000 generic-all +java/time/tck/java/time/temporal/TCKWeekFields.java 0000000 generic-all +java/time/test/java/time/chrono/TestIsoChronoImpl.java 0000000 generic-all +java/time/test/java/time/chrono/TestJapaneseChronoImpl.java 0000000 generic-all +java/time/test/java/time/format/TestZoneTextPrinterParser.java 0000000 generic-all +java/util/Arrays/ArraysEqCmpTest.java 0000000 generic-all +java/util/Arrays/Sorting.java 0000000 generic-all +java/util/Arrays/TimSortStackSize2.java 0000000 generic-all +java/util/Base64/TestBase64.java 0000000 generic-all +java/util/BitSet/HugeToString.java 0000000 generic-all +java/util/BitSet/stream/BitSetStreamTest.java 0000000 generic-all +java/util/Calendar/Bug8167273.java 0000000 generic-all +java/util/Calendar/CalendarTest.java 0000000 generic-all +java/util/Calendar/CalendarTestScripts/JapaneseRollTests.java 0000000 generic-all +java/util/Calendar/RollDayOfWeekTest.java 0000000 generic-all +java/util/Collection/MOAT.java 0000000 generic-all +java/util/Collections/RotateHuge.java 0000000 generic-all +java/util/DoubleStreamSums/CompensatedSums.java 0000000 generic-all +java/util/DoubleSummaryStatistics/NegativeCompensation.java 0000000 generic-all +java/util/Formatter/Padding.java 0000000 generic-all +java/util/Map/Collisions.java 0000000 generic-all +java/util/Map/InPlaceOpsCollisions.java 0000000 generic-all +java/util/PluggableLocale/CurrencyNameProviderTest.java 0000000 generic-all +java/util/PluggableLocale/DateFormatProviderTest.java 0000000 generic-all +java/util/PluggableLocale/NumberFormatProviderTest.java 0000000 generic-all +java/util/PluggableLocale/TimeZoneNameProviderTest.java 0000000 generic-all +java/util/Random/RandomCanaryPi.java 0000000 generic-all +java/util/Random/RandomExponentialTest.java 0000000 generic-all +java/util/Random/RandomTest.java 0000000 generic-all +java/util/Random/RandomTestBsi1999.java 0000000 generic-all +java/util/Spliterator/SpliteratorCollisions.java 0000000 generic-all +java/util/TimeZone/DaylightTimeTest.java 0000000 generic-all +java/util/UUID/UUIDTest.java 0000000 generic-all +java/util/concurrent/ConcurrentQueues/ConcurrentQueueLoops.java 0000000 generic-all +java/util/concurrent/atomic/AtomicReferenceFieldUpdaterValueObjectTest.java 0000000 generic-all +java/util/concurrent/atomic/DoubleAdderDemo.java 0000000 generic-all +java/util/concurrent/atomic/LongAdderDemo.java 0000000 generic-all +java/util/concurrent/forkjoin/Integrate.java 0000000 generic-all +java/util/concurrent/tck/JSR166TestCase.java#default 0000000 generic-all +java/util/concurrent/tck/JSR166TestCase.java#forkjoinpool-common-parallelism 0000000 generic-all +java/util/concurrent/tck/JSR166TestCase.java#others 0000000 generic-all +java/util/jar/JarEntry/GetMethodsReturnClones.java 0000000 generic-all +java/util/jar/JarFile/IgnoreUnrelatedSignatureFiles.java 0000000 generic-all +java/util/jar/JarFile/jarVerification/MultiProviderTest.java 0000000 generic-all +java/util/jar/JarInputStream/ExtraFileInMetaInf.java 0000000 generic-all +java/util/regex/NegativeArraySize.java 0000000 generic-all +java/util/regex/RegExTest.java 0000000 generic-all +java/util/stream/GathererTest.java 0000000 generic-all +java/util/stream/boottest/java.base/java/util/stream/SpinedBufferIntegerTest.java 0000000 generic-all +java/util/stream/test/org/openjdk/tests/java/util/SplittableRandomTest.java 0000000 generic-all +java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java 0000000 generic-all +java/util/stream/test/org/openjdk/tests/java/util/stream/CountLargeTest.java 0000000 generic-all +java/util/stream/test/org/openjdk/tests/java/util/stream/InfiniteStreamWithLimitOpTest.java 0000000 generic-all +java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java 0000000 generic-all +java/util/stream/test/org/openjdk/tests/java/util/stream/StreamLinkTest.java 0000000 generic-all +java/util/stream/test/org/openjdk/tests/java/util/stream/StreamSpliteratorTest.java 0000000 generic-all +java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpTest.java 0000000 generic-all +java/util/stream/test/org/openjdk/tests/java/util/stream/mapMultiOpTest.java 0000000 generic-all +java/util/zip/ZipFile/TestZipFileEncodings.java 0000000 generic-all +java/util/zip/ZipFile/ZipFileSharedSourceTest.java 0000000 generic-all +javax/crypto/Cipher/TestCipherMode.java 0000000 generic-all +javax/crypto/KEM/GenLargeNumberOfKeys.java 0000000 generic-all +javax/crypto/KEM/KemTest.java 0000000 generic-all +javax/crypto/KeyGenerator/CompareKeys.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSDataExchangeTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSEnginesClosureTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSHandshakeTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSMFLNTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSNamedGroups.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSRehandshakeTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSSequenceNumberTest.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSSignatureSchemes.java 0000000 generic-all +javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java 0000000 generic-all +javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java 0000000 generic-all +javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java#tls12 0000000 generic-all +javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java#tls13 0000000 generic-all +javax/net/ssl/SSLEngine/Basics.java 0000000 generic-all +javax/net/ssl/SSLEngine/ExtendedKeySocket.java 0000000 generic-all +javax/net/ssl/SSLEngine/LargeBufs.java 0000000 generic-all +javax/net/ssl/ServerName/SNIWildcardMatching.java 0000000 generic-all +javax/net/ssl/Stapling/HttpsUrlConnClient.java 0000000 generic-all +javax/net/ssl/Stapling/SSLEngineWithStapling.java 0000000 generic-all +javax/net/ssl/Stapling/SSLSocketWithStapling.java 0000000 generic-all +javax/net/ssl/TLS/TLSDataExchangeTest.java 0000000 generic-all +javax/net/ssl/TLS/TLSEnginesClosureTest.java 0000000 generic-all +javax/net/ssl/TLS/TLSHandshakeTest.java 0000000 generic-all +javax/net/ssl/TLS/TLSMFLNTest.java 0000000 generic-all +javax/net/ssl/TLS/TLSNotEnabledRC4Test.java 0000000 generic-all +javax/net/ssl/TLS/TLSRehandshakeTest.java 0000000 generic-all +javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java 0000000 generic-all +javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java 0000000 generic-all +javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java 0000000 generic-all +javax/net/ssl/TLSCommon/ConcurrentClientAccessTest.java 0000000 generic-all +javax/net/ssl/TLSCommon/TLSWithEdDSA.java 0000000 generic-all +javax/net/ssl/TLSCommon/TestSessionLocalPrincipal.java 0000000 generic-all +javax/net/ssl/TLSv1/TLSDataExchangeTest.java 0000000 generic-all +javax/net/ssl/TLSv1/TLSEnginesClosureTest.java 0000000 generic-all +javax/net/ssl/TLSv1/TLSHandshakeTest.java 0000000 generic-all +javax/net/ssl/TLSv1/TLSMFLNTest.java 0000000 generic-all +javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java 0000000 generic-all +javax/net/ssl/TLSv1/TLSRehandshakeTest.java 0000000 generic-all +javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java 0000000 generic-all +javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java 0000000 generic-all +javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java 0000000 generic-all +javax/net/ssl/TLSv11/TLSDataExchangeTest.java 0000000 generic-all +javax/net/ssl/TLSv11/TLSEnginesClosureTest.java 0000000 generic-all +javax/net/ssl/TLSv11/TLSHandshakeTest.java 0000000 generic-all +javax/net/ssl/TLSv11/TLSMFLNTest.java 0000000 generic-all +javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java 0000000 generic-all +javax/net/ssl/TLSv11/TLSRehandshakeTest.java 0000000 generic-all +javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java 0000000 generic-all +javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java 0000000 generic-all +javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java 0000000 generic-all +javax/net/ssl/TLSv12/TLSEnginesClosureTest.java 0000000 generic-all +javax/xml/crypto/dsig/Basic.java 0000000 generic-all +javax/xml/crypto/dsig/GenerationTests.java 0000000 generic-all +javax/xml/crypto/dsig/PSSSpec.java 0000000 generic-all +javax/xml/crypto/dsig/Properties.java 0000000 generic-all +jdk/classfile/CorpusTest.java 0000000 generic-all +jdk/classfile/VerifierSelfTest.java 0000000 generic-all +jdk/internal/jimage/JImageOpenTest.java 0000000 generic-all +jdk/internal/jrtfs/Basic.java 0000000 generic-all +jdk/internal/jrtfs/ClassResourcesParityTest.java#enable-preview 0000000 generic-all +jdk/internal/jrtfs/ClassResourcesParityTest.java#no-enable-preview 0000000 generic-all +jdk/internal/loader/NativeLibraries/Main.java 0000000 generic-all +jdk/internal/loader/URLClassPath/FileLoaderTest.java 0000000 generic-all +jdk/internal/math/FloatingDecimal/TestFloatingDecimal.java 0000000 generic-all +jdk/internal/math/FloatingDecimal/TestRandomFloatingDecimal.java 0000000 generic-all +jdk/internal/math/ToDecimal/DoubleToDecimalTest.java 0000000 generic-all +jdk/internal/math/ToDecimal/FloatToDecimalTest.java 0000000 generic-all +jdk/internal/util/ModifiedUtfTest.java 0000000 generic-all +jdk/modules/etc/DefaultModules.java 0000000 generic-all +jdk/modules/incubator/ImageModules.java 0000000 generic-all +jdk/nio/zipfs/LargeEntriesTest.java 0000000 generic-all +jdk/nio/zipfs/ZipFSOutputStreamTest.java 0000000 generic-all +jdk/security/jarsigner/JarWithOneNonDisabledDigestAlg.java 0000000 generic-all +jdk/security/jarsigner/Spec.java 0000000 generic-all +jni/nullCaller/NullCallerTest.java 0000000 generic-all +sun/misc/CopyMemory.java 0000000 generic-all +sun/net/www/protocol/file/FileMap.java 0000000 generic-all +sun/net/www/protocol/file/GetHeaderFields.java 0000000 generic-all +sun/net/www/protocol/file/GetLastModified.java 0000000 generic-all +sun/net/www/protocol/https/ChunkedOutputStream.java 0000000 generic-all +sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/B6216082.java 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java#tls12 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java#tls13 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/IPAddressDNSIdentities.java#tls12 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/IPAddressDNSIdentities.java#tls13 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java#tls12 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java#tls13 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/Identities.java#tls12 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/Identities.java#tls13 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.java 0000000 generic-all +sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.java 0000000 generic-all +sun/net/www/protocol/jar/jarbug/TestDriver.java 0000000 generic-all +sun/nio/ch/TempBuffer.java 0000000 generic-all +sun/nio/cs/FindDecoderBugs.java 0000000 generic-all +sun/nio/cs/FindEncoderBugs.java 0000000 generic-all +sun/nio/cs/StreamEncoderOut.java 0000000 generic-all +sun/nio/cs/TestEUC_TW.java 0000000 generic-all +sun/nio/cs/TestStringCoding.java 0000000 generic-all +sun/nio/cs/TestUTF8.java 0000000 generic-all +sun/security/ec/ECDSAPrimitive.java 0000000 generic-all +sun/security/ec/TestEC.java 0000000 generic-all +sun/security/ec/ed/EdDSATest.java 0000000 generic-all +sun/security/ec/ed/TestEdOps.java 0000000 generic-all +sun/security/ec/xec/XECIterative.java 0000000 generic-all +sun/security/krb5/auto/AcceptorSubKey.java 0000000 generic-all +sun/security/krb5/auto/Addresses.java 0000000 generic-all +sun/security/krb5/auto/AddressesAndNameType.java 0000000 generic-all +sun/security/krb5/auto/AlwaysEncPaReq.java 0000000 generic-all +sun/security/krb5/auto/Basic.java 0000000 generic-all +sun/security/krb5/auto/BasicKrb5Test.java 0000000 generic-all +sun/security/krb5/auto/BasicProc.java 0000000 generic-all +sun/security/krb5/auto/CaseSensitive.java 0000000 generic-all +sun/security/krb5/auto/CleanState.java 0000000 generic-all +sun/security/krb5/auto/Cleaners.java 0000000 generic-all +sun/security/krb5/auto/DiffNameSameKey.java 0000000 generic-all +sun/security/krb5/auto/DiffSaltParams.java 0000000 generic-all +sun/security/krb5/auto/DupEtypes.java 0000000 generic-all +sun/security/krb5/auto/DynamicKeytab.java 0000000 generic-all +sun/security/krb5/auto/FileKeyTab.java 0000000 generic-all +sun/security/krb5/auto/ForwardableCheck.java 0000000 generic-all +sun/security/krb5/auto/Forwarded.java 0000000 generic-all +sun/security/krb5/auto/GSS.java 0000000 generic-all +sun/security/krb5/auto/GSSUnbound.java 0000000 generic-all +sun/security/krb5/auto/HttpNegotiateServer.java 0000000 generic-all +sun/security/krb5/auto/HttpsCB.java 0000000 generic-all +sun/security/krb5/auto/IgnoreChannelBinding.java 0000000 generic-all +sun/security/krb5/auto/KPEquals.java 0000000 generic-all +sun/security/krb5/auto/KdcPolicy.java 0000000 generic-all +sun/security/krb5/auto/KvnoNA.java 0000000 generic-all +sun/security/krb5/auto/LifeTimeInSeconds.java 0000000 generic-all +sun/security/krb5/auto/LoginModuleOptions.java 0000000 generic-all +sun/security/krb5/auto/LoginNoPass.java 0000000 generic-all +sun/security/krb5/auto/LongLife.java 0000000 generic-all +sun/security/krb5/auto/MSOID2.java 0000000 generic-all +sun/security/krb5/auto/ModuleName.java 0000000 generic-all +sun/security/krb5/auto/MoreKvno.java 0000000 generic-all +sun/security/krb5/auto/NewInquireTypes.java 0000000 generic-all +sun/security/krb5/auto/NewSalt.java 0000000 generic-all +sun/security/krb5/auto/NoAddresses.java 0000000 generic-all +sun/security/krb5/auto/NoInitNoKeytab.java 0000000 generic-all +sun/security/krb5/auto/NonAscii.java 0000000 generic-all +sun/security/krb5/auto/NonMutualSpnego.java 0000000 generic-all +sun/security/krb5/auto/NoneReplayCacheTest.java 0000000 generic-all +sun/security/krb5/auto/NullRenewUntil.java 0000000 generic-all +sun/security/krb5/auto/OkAsDelegate.java 0000000 generic-all +sun/security/krb5/auto/OkAsDelegateXRealm.java 0000000 generic-all +sun/security/krb5/auto/OnlyDesLogin.java 0000000 generic-all +sun/security/krb5/auto/PrincipalNameEquals.java 0000000 generic-all +sun/security/krb5/auto/RRC.java 0000000 generic-all +sun/security/krb5/auto/ReferralsTest.java 0000000 generic-all +sun/security/krb5/auto/Renew.java 0000000 generic-all +sun/security/krb5/auto/Renewal.java 0000000 generic-all +sun/security/krb5/auto/ReplayCacheTest.java 0000000 generic-all +sun/security/krb5/auto/ReplayCacheTestProc.java 0000000 generic-all +sun/security/krb5/auto/ReplayCacheTestProcWithMD5.java 0000000 generic-all +sun/security/krb5/auto/S4U2proxy.java 0000000 generic-all +sun/security/krb5/auto/S4U2proxyGSS.java 0000000 generic-all +sun/security/krb5/auto/S4U2self.java 0000000 generic-all +sun/security/krb5/auto/S4U2selfAsServer.java 0000000 generic-all +sun/security/krb5/auto/S4U2selfAsServerGSS.java 0000000 generic-all +sun/security/krb5/auto/S4U2selfGSS.java 0000000 generic-all +sun/security/krb5/auto/S4U2selfNotF.java 0000000 generic-all +sun/security/krb5/auto/SPNEGO.java 0000000 generic-all +sun/security/krb5/auto/SaslBasic.java 0000000 generic-all +sun/security/krb5/auto/SaslMutual.java 0000000 generic-all +sun/security/krb5/auto/SaslUnbound.java 0000000 generic-all +sun/security/krb5/auto/SpnegoLifeTime.java 0000000 generic-all +sun/security/krb5/auto/SpnegoReqFlags.java 0000000 generic-all +sun/security/krb5/auto/SpnegoUnknownMech.java 0000000 generic-all +sun/security/krb5/auto/Test5653.java 0000000 generic-all +sun/security/krb5/auto/TicketSName.java 0000000 generic-all +sun/security/krb5/auto/TwoOrThree.java 0000000 generic-all +sun/security/krb5/auto/TwoPrinces.java 0000000 generic-all +sun/security/krb5/auto/TwoTab.java 0000000 generic-all +sun/security/krb5/auto/UnboundService.java 0000000 generic-all +sun/security/krb5/auto/UseCacheAndStoreKey.java 0000000 generic-all +sun/security/krb5/auto/UserIterCount.java 0000000 generic-all +sun/security/krb5/auto/principalProperty/PrincipalSystemPropTest.java 0000000 generic-all +sun/security/krb5/etype/WeakCrypto.java 0000000 generic-all +sun/security/krb5/ktab/BufferBoundary.java 0000000 generic-all +sun/security/krb5/ktab/KeyTabIndex.java 0000000 generic-all +sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java 0000000 generic-all +sun/security/pkcs12/EmptyPassword.java 0000000 generic-all +sun/security/pkcs12/GetSetEntryTest.java 0000000 generic-all +sun/security/pkcs12/KeytoolOpensslInteropTest.java#UseExistingPKCS12 0000000 generic-all +sun/security/pkcs12/PBMAC1Test.java 0000000 generic-all +sun/security/pkcs12/PKCS12SameKeyId.java 0000000 generic-all +sun/security/pkcs12/ParamsPreferences.java 0000000 generic-all +sun/security/pkcs12/ProbeBER.java 0000000 generic-all +sun/security/pkcs12/SameDN.java 0000000 generic-all +sun/security/pkcs12/StoreSecretKeyTest.java 0000000 generic-all +sun/security/pkcs12/WrongPBES2.java 0000000 generic-all +sun/security/provider/DSA/SupportedDSAParamGen.java 0000000 generic-all +sun/security/provider/DSA/SupportedDSAParamGenLongKey.java 0000000 generic-all +sun/security/provider/DSA/TestAlgParameterGenerator.java 0000000 generic-all +sun/security/provider/DSA/TestLegacyDSAKeyPairGenerator.java 0000000 generic-all +sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java 0000000 generic-all +sun/security/provider/KeyStore/CaseSensitiveAliases.java 0000000 generic-all +sun/security/provider/MessageDigest/SHAKEhash.java 0000000 generic-all +sun/security/provider/MessageDigest/SHAKEsqueeze.java 0000000 generic-all +sun/security/provider/NSASuiteB/TestDSAGenParameterSpec.java 0000000 generic-all +sun/security/provider/NSASuiteB/TestDSAGenParameterSpecLongKey.java 0000000 generic-all +sun/security/provider/SecureRandom/StrongSeedReader.java 0000000 generic-all +sun/security/provider/X509Factory/BigCRL.java 0000000 generic-all +sun/security/provider/certpath/PKIXCertComparator/Order.java 0000000 generic-all +sun/security/rsa/KeySizeTest.java 0000000 generic-all +sun/security/rsa/PrivateKeyEqualityTest.java 0000000 generic-all +sun/security/rsa/SignatureTest.java 0000000 generic-all +sun/security/rsa/SignedObjectChain.java 0000000 generic-all +sun/security/rsa/SpecTest.java 0000000 generic-all +sun/security/rsa/TestKeyPairGenerator.java 0000000 generic-all +sun/security/rsa/TestKeyPairGeneratorExponent.java 0000000 generic-all +sun/security/rsa/TestKeyPairGeneratorLength.java 0000000 generic-all +sun/security/rsa/TestSigGen15.java 0000000 generic-all +sun/security/rsa/pss/SerializedPSSKey.java 0000000 generic-all +sun/security/rsa/pss/SignatureTest2.java 0000000 generic-all +sun/security/rsa/pss/SignatureTestPSS.java 0000000 generic-all +sun/security/rsa/pss/TestPSSKeySupport.java 0000000 generic-all +sun/security/rsa/pss/TestSigGenPSS.java 0000000 generic-all +sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java 0000000 generic-all +sun/security/ssl/SSLCipher/ReadOnlyEngine.java 0000000 generic-all +sun/security/ssl/SSLEngineImpl/SSLEngineDeadlock.java 0000000 generic-all +sun/security/ssl/SSLLogger/DebugPropertyValuesTest.java 0000000 generic-all +sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java 0000000 generic-all +sun/security/ssl/SSLSessionImpl/NoInvalidateSocketException.java 0000000 generic-all +sun/security/ssl/SSLSessionImpl/ResumeClientTLS12withSNI.java 0000000 generic-all +sun/security/ssl/SSLSocketImpl/SSLSocketBruteForceClose.java 0000000 generic-all +sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForServerTLS13.java 0000000 generic-all +sun/security/ssl/SignatureScheme/MD5NotAllowedInTLS13CertificateSignature.java 0000000 generic-all +sun/security/ssl/SignatureScheme/RsaSsaPssConstraints.java 0000000 generic-all +sun/security/ssl/Stapling/StatusResponseManager.java 0000000 generic-all +sun/security/ssl/X509KeyManager/CertChecking.java 0000000 generic-all +sun/security/ssl/X509KeyManager/PreferredKey.java 0000000 generic-all +sun/security/ssl/X509KeyManager/SelectOneKeyOutOfMany.java 0000000 generic-all +sun/security/ssl/X509TrustManagerImpl/BasicConstraints12.java 0000000 generic-all +sun/security/ssl/X509TrustManagerImpl/CertChainAlgorithmConstraints.java 0000000 generic-all +sun/security/ssl/rsa/SignedObjectChain.java 0000000 generic-all +sun/security/tools/jarsigner/AlgOptions.java 0000000 generic-all +sun/security/tools/jarsigner/CertPolicy.java 0000000 generic-all +sun/security/tools/jarsigner/CheckAlgParams.java 0000000 generic-all +sun/security/tools/jarsigner/CheckSignerCertChain.java 0000000 generic-all +sun/security/tools/jarsigner/CheckUsage.java 0000000 generic-all +sun/security/tools/jarsigner/Collator.java 0000000 generic-all +sun/security/tools/jarsigner/ConciseJarsigner.java 0000000 generic-all +sun/security/tools/jarsigner/Crl.java 0000000 generic-all +sun/security/tools/jarsigner/DefaultOptions.java 0000000 generic-all +sun/security/tools/jarsigner/DefaultSigalg.java 0000000 generic-all +sun/security/tools/jarsigner/DiffEnd.java 0000000 generic-all +sun/security/tools/jarsigner/DigestDontIgnoreCase.java 0000000 generic-all +sun/security/tools/jarsigner/DisableCurveTest.java 0000000 generic-all +sun/security/tools/jarsigner/EC.java 0000000 generic-all +sun/security/tools/jarsigner/EmptyIndividualSectionName.java 0000000 generic-all +sun/security/tools/jarsigner/EmptyManifest.java 0000000 generic-all +sun/security/tools/jarsigner/EnableRevocation.java 0000000 generic-all +sun/security/tools/jarsigner/EntriesOrder.java 0000000 generic-all +sun/security/tools/jarsigner/FailedSigning.java 0000000 generic-all +sun/security/tools/jarsigner/InsufficientSectionDelimiter.java 0000000 generic-all +sun/security/tools/jarsigner/JvIndex.java 0000000 generic-all +sun/security/tools/jarsigner/ML_DSA.java 0000000 generic-all +sun/security/tools/jarsigner/MainAttributesConfused.java 0000000 generic-all +sun/security/tools/jarsigner/MultiManifest.java 0000000 generic-all +sun/security/tools/jarsigner/NameClash.java 0000000 generic-all +sun/security/tools/jarsigner/NewSize7.java 0000000 generic-all +sun/security/tools/jarsigner/OldSig.java 0000000 generic-all +sun/security/tools/jarsigner/OnlyManifest.java 0000000 generic-all +sun/security/tools/jarsigner/Options.java 0000000 generic-all +sun/security/tools/jarsigner/PassType.java 0000000 generic-all +sun/security/tools/jarsigner/PosixPermissionsTest.java 0000000 generic-all +sun/security/tools/jarsigner/PreserveRawManifestEntryAndDigest.java 0000000 generic-all +sun/security/tools/jarsigner/RemoveDifferentKeyAlgBlockFile.java 0000000 generic-all +sun/security/tools/jarsigner/RemovedFiles.java 0000000 generic-all +sun/security/tools/jarsigner/RestrictedAlgo.java 0000000 generic-all +sun/security/tools/jarsigner/SameName.java 0000000 generic-all +sun/security/tools/jarsigner/SectionsOnly.java 0000000 generic-all +sun/security/tools/jarsigner/SignedAgain.java 0000000 generic-all +sun/security/tools/jarsigner/SymLinkTest.java 0000000 generic-all +sun/security/tools/jarsigner/TimestampCheck.java 0000000 generic-all +sun/security/tools/jarsigner/TsacertOptionTest.java 0000000 generic-all +sun/security/tools/jarsigner/VerifyJarEntryName.java 0000000 generic-all +sun/security/tools/jarsigner/VersionTest.java 0000000 generic-all +sun/security/tools/jarsigner/Warning.java 0000000 generic-all +sun/security/tools/jarsigner/WasSignedByOtherSigner.java 0000000 generic-all +sun/security/tools/jarsigner/WeakSize.java 0000000 generic-all +sun/security/tools/jarsigner/multiRelease/MVJarSigningTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/AliasNotInStoreTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/AliasNotInStoreTest2.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/BadExtendedKeyUsageTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/BadNetscapeCertTypeTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/ChainNotValidatedTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/HasExpiredCertTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/HasExpiringCertTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/HasUnsignedEntryTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/LowerCaseManifest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/MultipleWarningsTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/NoTimestampTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/NotSignedByAliasTest.java 0000000 generic-all +sun/security/tools/jarsigner/warnings/NotYetValidCertTest.java 0000000 generic-all +sun/security/tools/keytool/CheckCertAKID.java 0000000 generic-all +sun/security/tools/keytool/CloseFile.java 0000000 generic-all +sun/security/tools/keytool/DefaultOptions.java 0000000 generic-all +sun/security/tools/keytool/DupImport.java 0000000 generic-all +sun/security/tools/keytool/EmptySubject.java 0000000 generic-all +sun/security/tools/keytool/GenKeyPairSigner.java 0000000 generic-all +sun/security/tools/keytool/GenerateAll.java 0000000 generic-all +sun/security/tools/keytool/GroupName.java 0000000 generic-all +sun/security/tools/keytool/ImportReadAll.java 0000000 generic-all +sun/security/tools/keytool/JKStoPKCS12.java 0000000 generic-all +sun/security/tools/keytool/KeyAlg.java 0000000 generic-all +sun/security/tools/keytool/KeyToolTest.java 0000000 generic-all +sun/security/tools/keytool/LineEndings.java 0000000 generic-all +sun/security/tools/keytool/ListAlias.java 0000000 generic-all +sun/security/tools/keytool/ListOrder.java 0000000 generic-all +sun/security/tools/keytool/NewSize7.java 0000000 generic-all +sun/security/tools/keytool/OutdatedKeyStoreWarning.java 0000000 generic-all +sun/security/tools/keytool/PKCS12Passwd.java 0000000 generic-all +sun/security/tools/keytool/ProbingFailure.java 0000000 generic-all +sun/security/tools/keytool/ReadJar.java 0000000 generic-all +sun/security/tools/keytool/SelfIssued.java 0000000 generic-all +sun/security/tools/keytool/Serial64.java 0000000 generic-all +sun/security/tools/keytool/StartDateTest.java 0000000 generic-all +sun/security/tools/keytool/StorePasswords.java 0000000 generic-all +sun/security/tools/keytool/TestSha1Usage.java 0000000 generic-all +sun/security/tools/keytool/TryStore.java 0000000 generic-all +sun/security/tools/keytool/WeakAlg.java 0000000 generic-all +sun/security/tools/keytool/WeakSecretKeyTest.java 0000000 generic-all +sun/security/tools/keytool/fakecacerts/TrustedCRL.java 0000000 generic-all +sun/security/tools/keytool/fakecacerts/TrustedCert.java 0000000 generic-all +sun/security/tools/keytool/fakegen/DefaultSignatureAlgorithm.java 0000000 generic-all +sun/security/tools/keytool/fakegen/PSS.java 0000000 generic-all +sun/security/util/Debug/DebugOptions.java 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#Curve25519OrderField 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#Curve448OrderField 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#IntegerPolynomial1305 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#IntegerPolynomial25519 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#IntegerPolynomial448 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#IntegerPolynomialP256 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#IntegerPolynomialP384 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#IntegerPolynomialP521 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#P256OrderField 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#P384OrderField 0000000 generic-all +sun/security/util/math/TestIntegerModuloP.java#P521OrderField 0000000 generic-all +sun/security/validator/CertReplace.java#certreplace 0000000 generic-all +sun/security/validator/CertReplace.java#samedn 0000000 generic-all +sun/security/x509/AlgorithmId/OmitAlgIdParam.java 0000000 generic-all +sun/security/x509/URICertStore/CRLReadTimeout.java#0 0000000 generic-all +sun/security/x509/URICertStore/CRLReadTimeout.java#1 0000000 generic-all +sun/security/x509/URICertStore/CRLReadTimeout.java#2 0000000 generic-all +sun/security/x509/URICertStore/CRLReadTimeout.java#3 0000000 generic-all +sun/security/x509/URICertStore/CRLReadTimeout.java#4 0000000 generic-all +sun/security/x509/X509CRLImpl/OrderAndDup.java 0000000 generic-all +sun/util/resources/TimeZone/Bug4640234.java 0000000 generic-all +sun/util/resources/TimeZone/Bug8139107.java 0000000 generic-all +sun/util/resources/cldr/TimeZoneNamesTest.java 0000000 generic-all +tools/jar/CreateMissingParentDirectories.java 0000000 generic-all +tools/jar/JarBackSlash.java 0000000 generic-all +tools/jar/UpdateManifest.java 0000000 generic-all +tools/jar/compat/CLICompatibility.java 0000000 generic-all +tools/jar/index/MetaInf.java 0000000 generic-all +tools/jar/multiRelease/Basic.java 0000000 generic-all +tools/jimage/JImageListTest.java 0000000 generic-all +tools/jimage/VerifyJimage.java#compare 0000000 generic-all +tools/jimage/VerifyJimage.java#load 0000000 generic-all +tools/jlink/DefaultProviderTest.java 0000000 generic-all +tools/jlink/JLink20000Packages.java 0000000 generic-all +tools/jlink/JLinkDedupTestBatchSizeOne.java 0000000 generic-all +tools/jlink/JLinkNegativeTest.java 0000000 generic-all +tools/jlink/JLinkPluginsTest.java 0000000 generic-all +tools/jlink/JLinkReproducible2Test.java 0000000 generic-all +tools/jlink/JLinkSigningTest.java 0000000 generic-all +tools/jlink/JLinkTest.java 0000000 generic-all +tools/jlink/ModuleNamesOrderTest.java 0000000 generic-all +tools/jlink/plugins/CompressorPluginTest.java 0000000 generic-all +tools/jlink/plugins/ExcludeJmodSectionPluginTest.java 0000000 generic-all +tools/jlink/plugins/GenerateJLIClassesPluginTest.java 0000000 generic-all +tools/jlink/plugins/IncludeLocalesPluginTest.java 0000000 generic-all +tools/jlink/plugins/StripNativeDebugSymbolsPlugin/StripNativeDebugSymbolsPluginTest.java 0000000 generic-all +tools/jlink/plugins/StripParameterNamesTest.java 0000000 generic-all +tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java 0000000 generic-all +tools/jlink/runtimeImage/AddOptionsTest.java 0000000 generic-all +tools/jlink/runtimeImage/BasicJlinkMissingJavaBase.java 0000000 generic-all +tools/jlink/runtimeImage/BasicJlinkTest.java 0000000 generic-all +tools/jlink/runtimeImage/CustomModuleJlinkTest.java 0000000 generic-all +tools/jlink/runtimeImage/GenerateJLIClassesTest.java 0000000 generic-all +tools/jlink/runtimeImage/JavaSEReproducibleTest.java 0000000 generic-all +tools/jlink/runtimeImage/KeepPackagedModulesFailTest.java 0000000 generic-all +tools/jlink/runtimeImage/ModifiedFilesExitTest.java 0000000 generic-all +tools/jlink/runtimeImage/ModifiedFilesWarningTest.java 0000000 generic-all +tools/jlink/runtimeImage/MultiHopTest.java 0000000 generic-all +tools/jlink/runtimeImage/PackagedModulesVsRuntimeImageLinkTest.java 0000000 generic-all +tools/jlink/runtimeImage/PatchedJDKModuleJlinkTest.java 0000000 generic-all +tools/jlink/runtimeImage/SystemModulesTest.java 0000000 generic-all +tools/jlink/runtimeImage/SystemModulesTest2.java 0000000 generic-all +tools/jlink/runtimeImage/UpgradeableFileCacertsTest.java 0000000 generic-all +tools/jmod/hashes/HashesTest.java 0000000 generic-all +tools/launcher/ExecutionEnvironment.java 0000000 generic-all +tools/launcher/HelpFlagsTest.java 0000000 generic-all +tools/launcher/JliLaunchTest.java 0000000 generic-all +tools/launcher/VersionCheck.java 0000000 generic-all +tools/sincechecker/modules/java.base/JavaBaseCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.compiler/JavaCompilerCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.instrument/JavaInstrumentCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.management.rmi/JavaManagementRmiCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.management/JavaManagementCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.naming/JavaNamingCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.net.http/JavaNetHttpCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.scripting/JavaScriptingCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.security.jgss/JavaSecurityJgssCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.security.sasl/JavaSecuritySaslCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.smartcardio/JavaSmartcardioCheckSince.java 0000000 generic-all +tools/sincechecker/modules/java.xml.crypto/JavaXmlCryptoCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.attach/JdkAttachCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.charsets/JdkCharsetsCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.crypto.cryptoki/JdkCryptoCryptokiCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.dynalink/JdkDynalinkCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.editpad/JdkEditpadCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.httpserver/JdkHttpServerCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.jartool/JdkJartoolCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.javadoc/JdkJavadocCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.jcmd/JdkJcmdCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.jconsole/JdkJconsoleCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.jdeps/JdkJdepsCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.jdi/JdkJdiCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.jdwp.agent/JdkJdwpAgentCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.jlink/JdkJlinkCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.jshell/JdkJshellCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.jstatd/JdkJstatdCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.localedata/JdkLocaledataCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.management.agent/JdkManagementAgentCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.management.jfr/JdkManagementJfrCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.management/JdkManagementCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.net/JdkNetCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.sctp/JdkSctpCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.security.auth/JavaScriptingCheckSince.java 0000000 generic-all +tools/sincechecker/modules/jdk.security.jgss/JavaScriptingCheckSince.java 0000000 generic-all +valhalla/valuetypes/FlatVarHandleTest.java 0000000 generic-all +valhalla/valuetypes/LambdaMetaFactory/LambdaTest.java 0000000 generic-all +valhalla/valuetypes/MethodHandleTest.java 0000000 generic-all +valhalla/valuetypes/Nest.java 0000000 generic-all +valhalla/valuetypes/NullRestrictedArraysTest.java 0000000 generic-all +valhalla/valuetypes/NullRestrictedTest.java 0000000 generic-all +valhalla/valuetypes/RecursiveValueClass.java 0000000 generic-all +valhalla/valuetypes/Reflection.java 0000000 generic-all +valhalla/valuetypes/SubstitutabilityTest.java 0000000 generic-all +valhalla/valuetypes/ValueObjectMethodsTest.java 0000000 generic-all diff -Nru openjdk-25-25.0.4.1+1/debian/tests/problems-loong-other.txt openjdk-25-25.0.5+8/debian/tests/problems-loong-other.txt --- openjdk-25-25.0.4.1+1/debian/tests/problems-loong-other.txt 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/tests/problems-loong-other.txt 2026-10-22 00:58:09.000000000 +0000 @@ -0,0 +1,134 @@ +jdk/internal/shellsupport/doc/FullJavadocHelperTest.java 0000000 generic-all +jdk/internal/shellsupport/doc/JavadocHelperTest.java 0000000 generic-all +jdk/javadoc/doclet/testDateOption/TestDateOption.java 0000000 generic-all +jdk/javadoc/doclet/testGeneratedBy/TestGeneratedBy.java 0000000 generic-all +jdk/javadoc/doclet/testHeadTag/TestHeadTag.java 0000000 generic-all +jdk/javadoc/doclet/testImplicitlyDeclaredClasses/TestImplicitlyDeclaredClasses.java 0000000 generic-all +jdk/javadoc/doclet/testJavaFX/TestJavaFXCombo.java 0000000 generic-all +jdk/javadoc/doclet/testLinkPlatform/TestLinkPlatform.java 0000000 generic-all +jdk/javadoc/doclet/testModules/TestModules.java 0000000 generic-all +jdk/javadoc/doclet/testSearch/TestSearch.java 0000000 generic-all +jdk/javadoc/doclet/testSingletonLists/TestSingletonLists.java 0000000 generic-all +jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java 0000000 generic-all +jdk/javadoc/doclet/testVersionOption/TestVersionOption.java 0000000 generic-all +jdk/javadoc/tool/TestScriptInComment.java 0000000 generic-all +jdk/javadoc/tool/VerifyLocale.java 0000000 generic-all +jdk/jshell/ClassMembersTest.java 0000000 generic-all +jdk/jshell/ForwardReferenceImportTest.java 0000000 generic-all +jdk/jshell/ModifiersTest.java 0000000 generic-all +jdk/jshell/StartOptionTest.java 0000000 generic-all +jdk/jshell/TerminalNoExecTest.java 0000000 generic-all +jdk/jshell/ToolBasicTest.java 0000000 generic-all +jdk/jshell/ToolCommandOptionTest.java 0000000 generic-all +jdk/jshell/ToolLocalSimpleTest.java 0000000 generic-all +jdk/jshell/ToolProviderTest.java 0000000 generic-all +jdk/jshell/ToolReloadTest.java 0000000 generic-all +jdk/jshell/ToolRetainTest.java 0000000 generic-all +jdk/jshell/ToolSimpleTest.java 0000000 generic-all +jdk/jshell/ToolTabCommandTest.java 0000000 generic-all +jdk/jshell/ToolTabSnippetTest.java 0000000 generic-all +jdk/jshell/ToolingTest.java 0000000 generic-all +tools/javac/7003595/T7003595.java 0000000 generic-all +tools/javac/7118412/ShadowingTest.java 0000000 generic-all +tools/javac/7142086/T7142086.java#id0 0000000 generic-all +tools/javac/Diagnostics/6769027/T6769027.java 0000000 generic-all +tools/javac/T7093325.java 0000000 generic-all +tools/javac/TryWithResources/InterruptedExceptionTest.java 0000000 generic-all +tools/javac/TryWithResources/UnusedResourcesTest.java 0000000 generic-all +tools/javac/VersionOpt.java 0000000 generic-all +tools/javac/annotations/ParameterArrayLimit.java 0000000 generic-all +tools/javac/annotations/neg/8022765/VerifyErroneousAnnotationsAttributed.java 0000000 generic-all +tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest1.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest3.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/referenceinfos/ClassExtends.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/referenceinfos/ClassTypeParam.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/referenceinfos/Fields.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/referenceinfos/MethodParameters.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/referenceinfos/MethodReturns.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/referenceinfos/MethodTypeParam.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/referenceinfos/NewObjects.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/referenceinfos/TypeCasts.java 0000000 generic-all +tools/javac/annotations/typeAnnotations/referenceinfos/TypeTests.java 0000000 generic-all +tools/javac/api/T6501502.java 0000000 generic-all +tools/javac/api/TestContainTypes.java 0000000 generic-all +tools/javac/api/TestGetElement.java 0000000 generic-all +tools/javac/cast/intersection/IntersectionTypeCastTest.java 0000000 generic-all +tools/javac/classfiles/ClassVersionChecker.java 0000000 generic-all +tools/javac/classfiles/attributes/LineNumberTable/LineNumberTest.java 0000000 generic-all +tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForGenericMethodTest.java 0000000 generic-all +tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerAnnotationTest.java 0000000 generic-all +tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerClassTest.java 0000000 generic-all +tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerEnumTest.java 0000000 generic-all +tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerInterfaceTest.java 0000000 generic-all +tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForTopLevelClassTest.java 0000000 generic-all +tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForGenericMethodTest.java 0000000 generic-all +tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java 0000000 generic-all +tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTest.java 0000000 generic-all +tools/javac/classfiles/attributes/innerclasses/InnerClassesInLocalClassTest.java 0000000 generic-all +tools/javac/classreader/TruncatedClassFileTest.java 0000000 generic-all +tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java 0000000 generic-all +tools/javac/defaultMethods/super/TestDefaultSuperCall.java 0000000 generic-all +tools/javac/defaultMethods/syntax/TestDefaultMethodsSyntax.java 0000000 generic-all +tools/javac/diags/CheckExamples.java 0000000 generic-all +tools/javac/diags/RunExamples.java 0000000 generic-all +tools/javac/expswitch/ExpSwitchNestingTest.java 0000000 generic-all +tools/javac/failover/CheckAttributedTree.java 0000000 generic-all +tools/javac/generics/diamond/7030150/GenericConstructorAndDiamondTest.java 0000000 generic-all +tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java 0000000 generic-all +tools/javac/generics/inference/7086601/T7086601b.java 0000000 generic-all +tools/javac/generics/inference/8048838/T8048838.java 0000000 generic-all +tools/javac/generics/inference/8176534/TestUncheckedCalls.java 0000000 generic-all +tools/javac/importscope/ImportDependenciesTest.java 0000000 generic-all +tools/javac/importscope/NegativeCyclicDependencyTest.java 0000000 generic-all +tools/javac/importscope/TestDuplicateImport.java 0000000 generic-all +tools/javac/lambda/LambdaParserTest.java 0000000 generic-all +tools/javac/lambda/ManyLambdasSerialization.java 0000000 generic-all +tools/javac/lambda/MethodReferenceParserTest.java 0000000 generic-all +tools/javac/lambda/T8031967.java 0000000 generic-all +tools/javac/lambda/TestSelfRef.java 0000000 generic-all +tools/javac/lambda/bridge/TestMetafactoryBridges.java 0000000 generic-all +tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java 0000000 generic-all +tools/javac/lambda/intersection/IntersectionTargetTypeTest.java 0000000 generic-all +tools/javac/lambda/lambdaExpression/SamConversionComboTest.java 0000000 generic-all +tools/javac/lambda/methodReference/SamConversionComboTest.java 0000000 generic-all +tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java 0000000 generic-all +tools/javac/lambdaShapes/org/openjdk/tests/javac/FDTest.java 0000000 generic-all +tools/javac/lambdaShapes/org/openjdk/tests/vm/DefaultMethodsTest.java 0000000 generic-all +tools/javac/modules/AnnotationProcessing.java 0000000 generic-all +tools/javac/options/modes/InfoOptsTest.java 0000000 generic-all +tools/javac/patterns/Exhaustiveness.java 0000000 generic-all +tools/javac/patterns/ExhaustivenessConvenientErrors.java 0000000 generic-all +tools/javac/patterns/PrimitiveInstanceOfComboTest.java 0000000 generic-all +tools/javac/patterns/SOEDeeplyNestedBlocksTest.java 0000000 generic-all +tools/javac/platform/CanHandleClassFilesTest.java 0000000 generic-all +tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java 0000000 generic-all +tools/javac/processing/TestWarnErrorCount.java 0000000 generic-all +tools/javac/processing/model/completionfailure/MissingClassFile.java 0000000 generic-all +tools/javac/processing/model/testgetallmembers/Main.java 0000000 generic-all +tools/javac/records/RecordCompilationTests.java 0000000 generic-all +tools/javac/recovery/AnnotationRecovery.java 0000000 generic-all +tools/javac/sealed/SealedCompilationTests.java 0000000 generic-all +tools/javac/switchnull/SwitchNull.java 0000000 generic-all +tools/javac/tree/JavacTreeScannerTest.java 0000000 generic-all +tools/javac/tree/SourceDocTreeScannerTest.java 0000000 generic-all +tools/javac/tree/SourceTreeScannerTest.java 0000000 generic-all +tools/javac/tree/TreePosTest.java 0000000 generic-all +tools/javac/types/TestComparisons.java 0000000 generic-all +tools/javac/valhalla/value-objects/IdentityExceptionTest.java 0000000 generic-all +tools/javac/valhalla/value-objects/ValueObjectCompilationTests.java 0000000 generic-all +tools/javac/varargs/6199075/T6199075.java 0000000 generic-all +tools/javac/varargs/7043922/T7043922.java 0000000 generic-all +tools/javac/varargs/warning/Warn4.java 0000000 generic-all +tools/javac/varargs/warning/Warn5.java 0000000 generic-all +tools/javac/versions/Versions.java 0000000 generic-all +tools/jdeprscan/tests/jdk/jdeprscan/TestRelease.java 0000000 generic-all +tools/jdeps/MultiReleaseJar.java 0000000 generic-all +tools/jdeps/Options.java 0000000 generic-all +tools/jdeps/listdeps/ListModuleDeps.java 0000000 generic-all +tools/jdeps/missingDeps/MissingDepsTest.java 0000000 generic-all +tools/jdeps/modules/CheckModuleTest.java 0000000 generic-all +tools/jdeps/modules/TransitiveDeps.java 0000000 generic-all +# jaxp +javax/xml/jaxp/unittest/validation/tck/Bug6989956Test.java 0000000 generic-all diff -Nru openjdk-25-25.0.4.1+1/debian/tests/problems.csv openjdk-25-25.0.5+8/debian/tests/problems.csv --- openjdk-25-25.0.4.1+1/debian/tests/problems.csv 2026-08-13 11:28:41.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/tests/problems.csv 2026-10-22 00:58:09.000000000 +0000 @@ -85,20 +85,6 @@ FAILED: sun/security/util/Debug/DebugOptions.java,JDK-8339713,Stack overflow error on 32-bit platforms,:openjdk-17:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:armhf:i386:s390x,:release-all Error: jdk/jshell/TerminalNoExecTest.java,,BackingStoreException: Couldn't get file lock - possibly because the LP (non-root) container has no home directory,:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:arch-all,:release-all FAILED: applications/ctw/modules/jdk_jfr.java,JDK-8352567, Unimplemented SharedRuntime:generate_jfr_write_checkpoint for S390x, :openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:s390x,:release-all -Error: serviceability/jvmti/thread/SuspendThreadList/suspendthrdlst01/suspendthrdlst01.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: serviceability/jvmti/thread/ResumeThreadList/resumethrdlst02/resumethrdlst02.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: serviceability/jvmti/thread/SuspendThread/suspendthrd01/suspendthrd01.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: serviceability/jvmti/thread/ResumeThreadList/resumethrdlst01/resumethrdlst01.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: serviceability/jvmti/thread/ResumeThread/resumethrd02/resumethrd02.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: serviceability/jvmti/thread/ResumeThread/resumethrd01/resumethrd01.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: serviceability/jvmti/thread/GetThreadState/thrstat02/thrstat02.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: serviceability/jvmti/thread/GetCurrentContendedMonitor/contmon02/contmon02.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: serviceability/jvmti/thread/GetCurrentContendedMonitor/contmon01/contmon01.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: serviceability/jvmti/SuspendWithCurrentThread/SuspendWithCurrentThread.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: runtime/NMT/SummaryDiffThreadCount.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: runtime/lockStack/TestStackWalk.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: compiler/loopopts/TestRemoveEmptyLoop.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all -Error: jdk/internal/shellsupport/doc/JavadocHelperTest.java,,Takes too long on loong64,:openjdk-21:openjdk-25:openjdk-26:openjdk-27:openjdk-28:,:loong64,:release-all FAILED: tools/javac/tree/SourceDocTreeScannerTest.java,JDK-8332619,Test runs out of stack space on 32-bit platforms,:openjdk-21,:armhf:i386,:release-all FAILED: tools/javac/tree/SourceTreeScannerTest.java,JDK-8332619,Test runs out of stack space on 32-bit platforms,:openjdk-21,:armhf:i386,:release-all FAILED: tools/javac/tree/JavacTreeScannerTest.java,JDK-8332619,Test runs out of stack space on 32-bit platforms,:openjdk-21,:armhf:i386,:release-all diff -Nru openjdk-25-25.0.4.1+1/debian/tests/write-problems.in openjdk-25-25.0.5+8/debian/tests/write-problems.in --- openjdk-25-25.0.4.1+1/debian/tests/write-problems.in 2026-03-30 08:49:17.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/tests/write-problems.in 2026-10-22 00:58:09.000000000 +0000 @@ -11,3 +11,9 @@ grep -e ${distrel} -e "release-all" | \ grep -e "@basename@" | \ awk -F',|:' '{gsub(/ /, "", $2); print $2" 000000 generic-all" }' >> ${problem_list} + +if [ "${host_arch}" == "loong64" ]; then + cat debian/tests/problems-loong-hotspot.txt >> ${problem_list} + cat debian/tests/problems-loong-jdk.txt >> ${problem_list} + cat debian/tests/problems-loong-other.txt >> ${problem_list} +fi diff -Nru openjdk-25-25.0.4.1+1/debian/tests/write-problems.sh openjdk-25-25.0.5+8/debian/tests/write-problems.sh --- openjdk-25-25.0.4.1+1/debian/tests/write-problems.sh 2026-08-18 21:50:36.000000000 +0000 +++ openjdk-25-25.0.5+8/debian/tests/write-problems.sh 2026-10-22 00:58:09.000000000 +0000 @@ -11,3 +11,9 @@ grep -e ${distrel} -e "release-all" | \ grep -e "openjdk-25" | \ awk -F',|:' '{gsub(/ /, "", $2); print $2" 000000 generic-all" }' >> ${problem_list} + +if [ "${host_arch}" == "loong64" ]; then + cat debian/tests/problems-loong-hotspot.txt >> ${problem_list} + cat debian/tests/problems-loong-jdk.txt >> ${problem_list} + cat debian/tests/problems-loong-other.txt >> ${problem_list} +fi diff -Nru openjdk-25-25.0.4.1+1/doc/testing.html openjdk-25-25.0.5+8/doc/testing.html --- openjdk-25-25.0.4.1+1/doc/testing.html 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/doc/testing.html 2026-10-19 12:10:20.000000000 +0000 @@ -523,6 +523,8 @@

REPORT

Use this report style when reporting test results (sent to JTReg as -report). Defaults to files.

+

MANUAL

+

Set to true to execute manual tests only.

Gtest keywords

REPEAT

The number of times to repeat the tests diff -Nru openjdk-25-25.0.4.1+1/doc/testing.md openjdk-25-25.0.5+8/doc/testing.md --- openjdk-25-25.0.4.1+1/doc/testing.md 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/doc/testing.md 2026-10-19 12:10:20.000000000 +0000 @@ -499,6 +499,10 @@ Use this report style when reporting test results (sent to JTReg as `-report`). Defaults to `files`. +#### MANUAL + +Set to `true` to execute manual tests only. + ### Gtest keywords #### REPEAT diff -Nru openjdk-25-25.0.4.1+1/make/Bundles.gmk openjdk-25-25.0.5+8/make/Bundles.gmk --- openjdk-25-25.0.4.1+1/make/Bundles.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/Bundles.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -125,13 +125,6 @@ && $(TAR) cf - -$(TAR_INCLUDE_PARAM) $$($1_$$d_LIST_FILE) \ $(TAR_IGNORE_EXIT_VALUE) ) \ | ( $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) && $(TAR) xf - )$$(NEWLINE) ) - # Rename stripped pdb files - ifeq ($(call isTargetOs, windows)+$(SHIP_DEBUG_SYMBOLS), true+public) - for f in `$(FIND) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) -name "*.stripped.pdb"`; do \ - $(ECHO) Renaming $$$${f} to $$$${f%stripped.pdb}pdb $(LOG_INFO); \ - $(MV) $$$${f} $$$${f%stripped.pdb}pdb; \ - done - endif # Unzip any zipped debuginfo files ifeq ($$($1_UNZIP_DEBUGINFO), true) for f in `$(FIND) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) -name "*.diz"`; do \ @@ -192,96 +185,30 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) - SYMBOLS_EXCLUDE_PATTERN := %.debuginfo %.diz %.map - - # There may be files with spaces in the names, so use ShellFindFiles - # explicitly. + # There may be files with spaces in the names, so use ShellFindFiles explicitly. ALL_JDK_FILES := $(call ShellFindFiles, $(JDK_IMAGE_DIR)) - ifneq ($(JDK_IMAGE_DIR), $(JDK_SYMBOLS_IMAGE_DIR)) - ALL_JDK_SYMBOLS_FILES := $(call ShellFindFiles, $(JDK_SYMBOLS_IMAGE_DIR)) - else - ALL_JDK_SYMBOLS_FILES := $(ALL_JDK_FILES) - endif ifneq ($(JDK_IMAGE_DIR), $(JDK_DEMOS_IMAGE_DIR)) ALL_JDK_DEMOS_FILES := $(call ShellFindFiles, $(JDK_DEMOS_IMAGE_DIR)) else ALL_JDK_DEMOS_FILES := $(ALL_JDK_FILES) endif - # Create special filter rules when dealing with unzipped .dSYM directories on - # macosx - ifeq ($(call isTargetOs, macosx), true) - ifeq ($(ZIP_EXTERNAL_DEBUG_SYMBOLS), false) - JDK_SYMBOLS_EXCLUDE_PATTERN := $(addprefix %, \ - $(call containing, .dSYM/, $(patsubst $(JDK_IMAGE_DIR)/%, %, \ - $(ALL_JDK_SYMBOLS_FILES)))) - endif - endif - - # Create special filter rules when dealing with debug symbols on windows - ifeq ($(call isTargetOs, windows), true) - ifeq ($(SHIP_DEBUG_SYMBOLS), ) - JDK_SYMBOLS_EXCLUDE_PATTERN := %.pdb - else - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - JDK_SYMBOLS_EXCLUDE_PATTERN := \ - $(filter-out \ - %.stripped.pdb, \ - $(filter %.pdb, $(ALL_JDK_FILES)) \ - ) - endif - endif - endif - JDK_BUNDLE_FILES := \ $(filter-out \ - $(JDK_SYMBOLS_EXCLUDE_PATTERN) \ $(JDK_EXTRA_EXCLUDES) \ - $(SYMBOLS_EXCLUDE_PATTERN) \ $(JDK_IMAGE_HOMEDIR)/demo/% \ , \ $(ALL_JDK_FILES) \ ) - JDK_SYMBOLS_BUNDLE_FILES := \ - $(filter-out \ - %.stripped.pdb, \ - $(call FindFiles, $(SYMBOLS_IMAGE_DIR)) \ - ) + JDK_SYMBOLS_BUNDLE_FILES := $(call FindFiles, $(SYMBOLS_IMAGE_DIR)) TEST_DEMOS_BUNDLE_FILES := $(filter $(JDK_DEMOS_IMAGE_HOMEDIR)/demo/%, \ $(ALL_JDK_DEMOS_FILES)) ALL_JRE_FILES := $(call ShellFindFiles, $(JRE_IMAGE_DIR)) - # Create special filter rules when dealing with unzipped .dSYM directories on - # macosx - ifeq ($(OPENJDK_TARGET_OS), macosx) - ifeq ($(ZIP_EXTERNAL_DEBUG_SYMBOLS), false) - JRE_SYMBOLS_EXCLUDE_PATTERN := $(addprefix %, \ - $(call containing, .dSYM/, $(patsubst $(JRE_IMAGE_DIR)/%, %, $(ALL_JRE_FILES)))) - endif - endif - - # Create special filter rules when dealing with debug symbols on windows - ifeq ($(call isTargetOs, windows), true) - ifeq ($(SHIP_DEBUG_SYMBOLS), ) - JRE_SYMBOLS_EXCLUDE_PATTERN := %.pdb - else - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - JRE_SYMBOLS_EXCLUDE_PATTERN := \ - $(filter-out \ - %.stripped.pdb, \ - $(filter %.pdb, $(ALL_JRE_FILES)) \ - ) - endif - endif - endif - - JRE_BUNDLE_FILES := $(filter-out \ - $(JRE_SYMBOLS_EXCLUDE_PATTERN) \ - $(SYMBOLS_EXCLUDE_PATTERN), \ - $(ALL_JRE_FILES)) + JRE_BUNDLE_FILES := $(ALL_JRE_FILES) ifeq ($(MACOSX_CODESIGN_MODE), hardened) # Macosx release build and code signing available. diff -Nru openjdk-25-25.0.4.1+1/make/CreateJmods.gmk openjdk-25-25.0.5+8/make/CreateJmods.gmk --- openjdk-25-25.0.4.1+1/make/CreateJmods.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/CreateJmods.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -218,10 +218,14 @@ ifeq ($(SHIP_DEBUG_SYMBOLS), ) JMOD_FLAGS += --exclude '**{_the.*,_*.marker*,*.diz,*.pdb,*.map}' else - JMOD_FLAGS += --exclude '**{_the.*,_*.marker*,*.diz,*.map}' + JMOD_FLAGS += --exclude '**{_the.*,_*.marker*,*.map}' endif else - JMOD_FLAGS += --exclude '**{_the.*,_*.marker*,*.diz,*.debuginfo,*.dSYM/**,*.dSYM}' + ifeq ($(SHIP_DEBUG_SYMBOLS), ) + JMOD_FLAGS += --exclude '**{_the.*,_*.marker*,*.diz,*.debuginfo,*.dSYM/**,*.dSYM}' + else + JMOD_FLAGS += --exclude '**{_the.*,_*.marker*}' + endif endif # Unless we are creating a very large module, use the small tool JVM options diff -Nru openjdk-25-25.0.4.1+1/make/Images.gmk openjdk-25-25.0.5+8/make/Images.gmk --- openjdk-25-25.0.4.1+1/make/Images.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/Images.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -282,29 +282,33 @@ endif CMDS_TARGET_SUBDIR := bin -# Param 1 - either JDK or JRE +# Copy debug info files into symbols bundle. +# In case of Windows and --with-external-symbols-in-bundles=public, take care to remove *.stripped.pdb files SetupCopyDebuginfo = \ $(foreach m, $(ALL_$1_MODULES), \ + $(eval dbgfiles := $(call FindDebuginfoFiles, $(SUPPORT_OUTPUTDIR)/modules_libs/$m)) \ + $(eval dbgfiles := $(if $(filter true+public,$(call isTargetOs,windows)+$(SHIP_DEBUG_SYMBOLS)), \ + $(filter-out %.stripped.pdb,$(dbgfiles)),$(dbgfiles)) \ + ) \ $(eval $(call SetupCopyFiles, COPY_$1_LIBS_DEBUGINFO_$m, \ SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/$m, \ DEST := $($1_IMAGE_DIR)/$(LIBS_TARGET_SUBDIR), \ - FILES := $(call FindDebuginfoFiles, \ - $(SUPPORT_OUTPUTDIR)/modules_libs/$m), \ + FILES := $(dbgfiles), \ )) \ $(eval $1_TARGETS += $$(COPY_$1_LIBS_DEBUGINFO_$m)) \ + $(eval dbgfiles := $(call FindDebuginfoFiles, $(SUPPORT_OUTPUTDIR)/modules_cmds/$m)) \ + $(eval dbgfiles := $(if $(filter true+public,$(call isTargetOs,windows)+$(SHIP_DEBUG_SYMBOLS)), \ + $(filter-out %.stripped.pdb,$(dbgfiles)),$(dbgfiles)) \ + ) \ $(eval $(call SetupCopyFiles, COPY_$1_CMDS_DEBUGINFO_$m, \ SRC := $(SUPPORT_OUTPUTDIR)/modules_cmds/$m, \ DEST := $($1_IMAGE_DIR)/$(CMDS_TARGET_SUBDIR), \ - FILES := $(call FindDebuginfoFiles, \ - $(SUPPORT_OUTPUTDIR)/modules_cmds/$m), \ + FILES := $(dbgfiles), \ )) \ $(eval $1_TARGETS += $$(COPY_$1_CMDS_DEBUGINFO_$m)) \ ) -# No space before argument to avoid having to put $(strip ) everywhere in -# implementation above. -$(call SetupCopyDebuginfo,JDK) -$(call SetupCopyDebuginfo,JRE) +# No space before argument to avoid having to put $(strip ) everywhere in implementation above. $(call SetupCopyDebuginfo,SYMBOLS) ################################################################################ diff -Nru openjdk-25-25.0.4.1+1/make/RunTests.gmk openjdk-25-25.0.5+8/make/RunTests.gmk --- openjdk-25-25.0.4.1+1/make/RunTests.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/RunTests.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -205,7 +205,8 @@ $(eval $(call ParseKeywordVariable, JTREG, \ SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR FAILURE_HANDLER_TIMEOUT \ TEST_MODE ASSERT VERBOSE RETAIN TEST_THREAD_FACTORY MAX_MEM RUN_PROBLEM_LISTS \ - RETRY_COUNT REPEAT_COUNT MAX_OUTPUT REPORT AOT_JDK $(CUSTOM_JTREG_SINGLE_KEYWORDS), \ + RETRY_COUNT REPEAT_COUNT MAX_OUTPUT REPORT AOT_JDK MANUAL \ + $(CUSTOM_JTREG_SINGLE_KEYWORDS), \ STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS KEYWORDS \ EXTRA_PROBLEM_LISTS LAUNCHER_OPTIONS \ $(CUSTOM_JTREG_STRING_KEYWORDS), \ @@ -901,7 +902,13 @@ -vmoption:-Dtest.boot.jdk="$$(BOOT_JDK)" \ -vmoption:-Djava.io.tmpdir="$$($1_TEST_TMP_DIR)" - $1_JTREG_BASIC_OPTIONS += -automatic -ignore:quiet + $1_JTREG_BASIC_OPTIONS += -ignore:quiet + + ifeq ($$(JTREG_MANUAL), true) + $1_JTREG_BASIC_OPTIONS += -manual + else + $1_JTREG_BASIC_OPTIONS += -automatic + endif # Make it possible to specify the JIB_DATA_DIR for tests using the # JIB Artifact resolver diff -Nru openjdk-25-25.0.4.1+1/make/autoconf/flags-cflags.m4 openjdk-25-25.0.5+8/make/autoconf/flags-cflags.m4 --- openjdk-25-25.0.4.1+1/make/autoconf/flags-cflags.m4 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/autoconf/flags-cflags.m4 2026-10-19 12:10:20.000000000 +0000 @@ -531,12 +531,9 @@ 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 -Nru openjdk-25-25.0.4.1+1/make/autoconf/flags-ldflags.m4 openjdk-25-25.0.5+8/make/autoconf/flags-ldflags.m4 --- openjdk-25-25.0.4.1+1/make/autoconf/flags-ldflags.m4 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/autoconf/flags-ldflags.m4 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -51,17 +51,16 @@ # add -z,now ("full relro" - more of the Global Offset Table GOT is marked read only) # add --no-as-needed to disable default --as-needed link flag on some GCC toolchains 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_CXX_PARTIAL_LINKING="$MACHINE_FLAG -r" elif test "x$TOOLCHAIN_TYPE" = xclang; then diff -Nru openjdk-25-25.0.4.1+1/make/autoconf/flags-other.m4 openjdk-25-25.0.5+8/make/autoconf/flags-other.m4 --- openjdk-25-25.0.4.1+1/make/autoconf/flags-other.m4 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/autoconf/flags-other.m4 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -115,7 +115,11 @@ # Force preprocessor to run, just to make sure BASIC_ASFLAGS="-x assembler-with-cpp" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then - BASIC_ASFLAGS="-nologo -c" + if test "x$OPENJDK_TARGET_CPU" = xaarch64; then + BASIC_ASFLAGS="-nologo" + else + BASIC_ASFLAGS="-nologo -c" + fi fi AC_SUBST(BASIC_ASFLAGS) diff -Nru openjdk-25-25.0.4.1+1/make/autoconf/jdk-options.m4 openjdk-25-25.0.5+8/make/autoconf/jdk-options.m4 --- openjdk-25-25.0.4.1+1/make/autoconf/jdk-options.m4 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/autoconf/jdk-options.m4 2026-10-19 12:10:20.000000000 +0000 @@ -327,23 +327,36 @@ AC_MSG_CHECKING([if we should add external native debug symbols to the shipped bundles]) AC_ARG_WITH([external-symbols-in-bundles], [AS_HELP_STRING([--with-external-symbols-in-bundles], - [which type of external native debug symbol information shall be shipped in product bundles (none, public, full) - (e.g. ship full/stripped pdbs on Windows) @<:@none@:>@])]) + [which type of external native debug symbol information shall be shipped with bundles/images (none, public, full). + @<:@none in release builds, full otherwise. --with-native-debug-symbols=external/zipped is a prerequisite. public is only supported on Windows@:>@])], + [], + [with_external_symbols_in_bundles=default]) if test "x$with_external_symbols_in_bundles" = x || test "x$with_external_symbols_in_bundles" = xnone ; then AC_MSG_RESULT([no]) elif test "x$with_external_symbols_in_bundles" = xfull || test "x$with_external_symbols_in_bundles" = xpublic ; then - if test "x$OPENJDK_TARGET_OS" != xwindows ; then - AC_MSG_ERROR([--with-external-symbols-in-bundles currently only works on windows!]) - elif test "x$COPY_DEBUG_SYMBOLS" != xtrue ; then - AC_MSG_ERROR([--with-external-symbols-in-bundles only works when --with-native-debug-symbols=external is used!]) - elif test "x$with_external_symbols_in_bundles" = xfull ; then + if test "x$COPY_DEBUG_SYMBOLS" != xtrue ; then + AC_MSG_ERROR([--with-external-symbols-in-bundles only works when --with-native-debug-symbols=external/zipped is used!]) + elif test "x$with_external_symbols_in_bundles" = xpublic && test "x$OPENJDK_TARGET_OS" != xwindows ; then + AC_MSG_ERROR([--with-external-symbols-in-bundles=public is only supported on Windows!]) + fi + + if test "x$with_external_symbols_in_bundles" = xfull ; then AC_MSG_RESULT([full]) SHIP_DEBUG_SYMBOLS=full else AC_MSG_RESULT([public]) SHIP_DEBUG_SYMBOLS=public fi + elif test "x$with_external_symbols_in_bundles" = xdefault ; then + if test "x$DEBUG_LEVEL" = xrelease ; then + AC_MSG_RESULT([no (default)]) + elif test "x$COPY_DEBUG_SYMBOLS" = xtrue ; then + AC_MSG_RESULT([full (default)]) + SHIP_DEBUG_SYMBOLS=full + else + AC_MSG_RESULT([no (default, native debug symbols are not external/zipped)]) + fi else AC_MSG_ERROR([$with_external_symbols_in_bundles is an unknown value for --with-external-symbols-in-bundles]) fi diff -Nru openjdk-25-25.0.4.1+1/make/autoconf/lib-tests.m4 openjdk-25-25.0.5+8/make/autoconf/lib-tests.m4 --- openjdk-25-25.0.4.1+1/make/autoconf/lib-tests.m4 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/autoconf/lib-tests.m4 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -28,7 +28,7 @@ ################################################################################ # Minimum supported versions -JTREG_MINIMUM_VERSION=8 +JTREG_MINIMUM_VERSION=8.2.1 GTEST_MINIMUM_VERSION=1.14.0 ################################################################################ diff -Nru openjdk-25-25.0.4.1+1/make/autoconf/platform.m4 openjdk-25-25.0.5+8/make/autoconf/platform.m4 --- openjdk-25-25.0.4.1+1/make/autoconf/platform.m4 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/autoconf/platform.m4 2026-10-19 12:10:20.000000000 +0000 @@ -174,18 +174,6 @@ VAR_CPU_BITS=64 VAR_CPU_ENDIAN=big ;; - sparc) - VAR_CPU=sparc - VAR_CPU_ARCH=sparc - VAR_CPU_BITS=32 - VAR_CPU_ENDIAN=big - ;; - sparcv9|sparc64) - VAR_CPU=sparcv9 - VAR_CPU_ARCH=sparc - VAR_CPU_BITS=64 - VAR_CPU_ENDIAN=big - ;; *) AC_MSG_ERROR([unsupported cpu $1]) ;; diff -Nru openjdk-25-25.0.4.1+1/make/autoconf/toolchain.m4 openjdk-25-25.0.5+8/make/autoconf/toolchain.m4 --- openjdk-25-25.0.4.1+1/make/autoconf/toolchain.m4 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/autoconf/toolchain.m4 2026-10-19 12:10:20.000000000 +0000 @@ -655,8 +655,11 @@ if test "x$TOOLCHAIN_TYPE" != xmicrosoft; then AS="$CC -c" else - if test "x$OPENJDK_TARGET_CPU_BITS" = "x64"; then - # On 64 bit windows, the assembler is "ml64.exe" + if test "x$OPENJDK_TARGET_CPU" = "xaarch64"; then + # On Windows aarch64, the assembler is "armasm64.exe" + UTIL_LOOKUP_TOOLCHAIN_PROGS(AS, armasm64) + elif test "x$OPENJDK_TARGET_CPU_BITS" = "x64"; then + # On Windows x64, the assembler is "ml64.exe" UTIL_LOOKUP_TOOLCHAIN_PROGS(AS, ml64) else # otherwise, the assembler is "ml.exe" diff -Nru openjdk-25-25.0.4.1+1/make/common/native/CompileFile.gmk openjdk-25-25.0.5+8/make/common/native/CompileFile.gmk --- openjdk-25-25.0.4.1+1/make/common/native/CompileFile.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/common/native/CompileFile.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -155,6 +155,12 @@ endif $1_FLAGS := $$($1_FLAGS) -DASSEMBLY_SRC_FILE='"$$($1_REL_ASM_SRC)"' \ -include $(TOPDIR)/make/data/autoheaders/assemblyprefix.h + else ifeq ($(TOOLCHAIN_TYPE), microsoft) + ifeq ($(OPENJDK_TARGET_CPU), aarch64) + $1_NON_ASM_EXTENSION_FLAG := + else + $1_NON_ASM_EXTENSION_FLAG := "-Ta" + endif endif else ifneq ($$(filter %.cpp %.cc %.mm, $$($1_FILENAME)), ) # Compile as a C++ or Objective-C++ file @@ -236,7 +242,7 @@ # For assembler calls just create empty dependency lists $$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \ $$($1_COMPILER) $$($1_FLAGS) \ - $(CC_OUT_OPTION)$$($1_OBJ) -Ta $$($1_SRC_FILE))) \ + $(CC_OUT_OPTION)$$($1_OBJ) $$($1_NON_ASM_EXTENSION_FLAG) $$($1_SRC_FILE))) \ | $(TR) -d '\r' | $(GREP) -v -e "Assembling:" || test "$$$$?" = "1" ; \ $(ECHO) > $$($1_DEPS_FILE) ; \ $(ECHO) > $$($1_DEPS_TARGETS_FILE) diff -Nru openjdk-25-25.0.4.1+1/make/conf/github-actions.conf openjdk-25-25.0.5+8/make/conf/github-actions.conf --- openjdk-25-25.0.4.1+1/make/conf/github-actions.conf 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/conf/github-actions.conf 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -26,7 +26,7 @@ # Versions and download locations for dependencies used by GitHub Actions (GHA) GTEST_VERSION=1.14.0 -JTREG_VERSION=8+2 +JTREG_VERSION=8.2.1+1 LINUX_X64_BOOT_JDK_EXT=tar.gz LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.3%2B9/OpenJDK25U-jdk_x64_linux_hotspot_25.0.3_9.tar.gz diff -Nru openjdk-25-25.0.4.1+1/make/conf/jib-profiles.js openjdk-25-25.0.5+8/make/conf/jib-profiles.js --- openjdk-25-25.0.4.1+1/make/conf/jib-profiles.js 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/conf/jib-profiles.js 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -1174,9 +1174,9 @@ jtreg: { server: "jpg", product: "jtreg", - version: "8", - build_number: "2", - file: "bundles/jtreg-8+2.zip", + version: "8.2.1", + build_number: "1", + file: "bundles/jtreg-8.2.1+1.zip", environment_name: "JT_HOME", environment_path: input.get("jtreg", "home_path") + "/bin", configure_args: "--with-jtreg=" + input.get("jtreg", "home_path"), diff -Nru openjdk-25-25.0.4.1+1/make/conf/version-numbers.conf openjdk-25-25.0.5+8/make/conf/version-numbers.conf --- openjdk-25-25.0.4.1+1/make/conf/version-numbers.conf 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/conf/version-numbers.conf 2026-10-19 12:10:20.000000000 +0000 @@ -28,12 +28,12 @@ DEFAULT_VERSION_FEATURE=25 DEFAULT_VERSION_INTERIM=0 -DEFAULT_VERSION_UPDATE=4 -DEFAULT_VERSION_PATCH=1 +DEFAULT_VERSION_UPDATE=5 +DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2026-08-18 +DEFAULT_VERSION_DATE=2026-10-20 DEFAULT_VERSION_CLASSFILE_MAJOR=69 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 diff -Nru openjdk-25-25.0.4.1+1/make/data/cldr/common/bcp47/timezone.xml openjdk-25-25.0.5+8/make/data/cldr/common/bcp47/timezone.xml --- openjdk-25-25.0.4.1+1/make/data/cldr/common/bcp47/timezone.xml 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/data/cldr/common/bcp47/timezone.xml 2026-10-19 12:10:20.000000000 +0000 @@ -141,7 +141,7 @@ - + @@ -164,7 +164,7 @@ - + @@ -273,7 +273,7 @@ - + @@ -321,7 +321,7 @@ - + @@ -408,15 +408,15 @@ - - + + - + @@ -424,7 +424,7 @@ - + diff -Nru openjdk-25-25.0.4.1+1/make/data/cldr/common/dtd/ldmlSupplemental.dtd openjdk-25-25.0.5+8/make/data/cldr/common/dtd/ldmlSupplemental.dtd --- openjdk-25-25.0.4.1+1/make/data/cldr/common/dtd/ldmlSupplemental.dtd 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/data/cldr/common/dtd/ldmlSupplemental.dtd 2026-10-19 12:10:20.000000000 +0000 @@ -996,6 +996,12 @@ + + + + + + diff -Nru openjdk-25-25.0.4.1+1/make/data/cldr/common/dtd/ldmlSupplemental.xsd openjdk-25-25.0.5+8/make/data/cldr/common/dtd/ldmlSupplemental.xsd --- openjdk-25-25.0.4.1+1/make/data/cldr/common/dtd/ldmlSupplemental.xsd 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/data/cldr/common/dtd/ldmlSupplemental.xsd 2026-10-19 12:10:20.000000000 +0000 @@ -2183,6 +2183,8 @@ + + diff -Nru openjdk-25-25.0.4.1+1/make/data/cldr/common/supplemental/metaZones.xml openjdk-25-25.0.5+8/make/data/cldr/common/supplemental/metaZones.xml --- openjdk-25-25.0.4.1+1/make/data/cldr/common/supplemental/metaZones.xml 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/data/cldr/common/supplemental/metaZones.xml 2026-10-19 12:10:20.000000000 +0000 @@ -57,6 +57,7 @@ + @@ -80,6 +81,7 @@ + @@ -187,7 +189,7 @@ - + @@ -382,7 +384,7 @@ - + @@ -478,7 +480,7 @@ - + @@ -731,14 +733,14 @@ - + - + @@ -1213,8 +1215,8 @@ - - + + diff -Nru openjdk-25-25.0.4.1+1/make/hotspot/lib/CompileJvm.gmk openjdk-25-25.0.5+8/make/hotspot/lib/CompileJvm.gmk --- openjdk-25-25.0.4.1+1/make/hotspot/lib/CompileJvm.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/hotspot/lib/CompileJvm.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -149,6 +149,12 @@ # This source set is reused so save in cache. $(call FillFindCache, $(JVM_SRC_DIRS)) +ifeq ($(SHIP_DEBUG_SYMBOLS), full) + CFLAGS_SHIP_DEBUGINFO := -DSHIP_DEBUGINFO_FULL +else ifeq ($(SHIP_DEBUG_SYMBOLS), public) + CFLAGS_SHIP_DEBUGINFO := -DSHIP_DEBUGINFO_PUBLIC +endif + ifeq ($(call isTargetOs, windows), true) ifeq ($(STATIC_LIBS), true) WIN_EXPORT_FILE := $(JVM_OUTPUTDIR)/static-win-exports.def @@ -156,10 +162,6 @@ WIN_EXPORT_FILE := $(JVM_OUTPUTDIR)/win-exports.def endif - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - CFLAGS_STRIPPED_DEBUGINFO := -DHAS_STRIPPED_DEBUGINFO - endif - JVM_LDFLAGS += -def:$(WIN_EXPORT_FILE) endif @@ -185,7 +187,7 @@ CFLAGS := $(JVM_CFLAGS), \ abstract_vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ arguments.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ - whitebox.cpp_CXXFLAGS := $(CFLAGS_STRIPPED_DEBUGINFO), \ + whitebox.cpp_CXXFLAGS := $(CFLAGS_SHIP_DEBUGINFO), \ DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc), \ DISABLED_WARNINGS_gcc_ad_$(HOTSPOT_TARGET_CPU_ARCH).cpp := nonnull, \ DISABLED_WARNINGS_gcc_bytecodeInterpreter.cpp := unused-label, \ @@ -206,6 +208,7 @@ DISABLED_WARNINGS_gcc_postaloc.cpp := address, \ DISABLED_WARNINGS_gcc_safepointMechanism.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_shenandoahGenerationalHeap.cpp := stringop-overflow, \ + DISABLED_WARNINGS_gcc_shenandoahHeap.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_shenandoahLock.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_stubGenerator_s390.cpp := unused-const-variable, \ DISABLED_WARNINGS_gcc_synchronizer.cpp := stringop-overflow, \ diff -Nru openjdk-25-25.0.4.1+1/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java openjdk-25-25.0.5+8/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java --- openjdk-25-25.0.4.1+1/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java 2026-10-19 12:10:20.000000000 +0000 @@ -87,6 +87,7 @@ static final String EXEMPLAR_CITY_PREFIX = "timezone.excity."; static final String ZONE_NAME_PREFIX = "timezone.displayname."; static final String METAZONE_ID_PREFIX = "metazone.id."; + static final String METAZONE_DSTOFFSET_PREFIX = "metazone.dstoffset."; static final String PARENT_LOCALE_PREFIX = "parentLocale."; static final String LIKELY_SCRIPT_PREFIX = "likelyScript."; static final String META_EMPTY_ZONE_NAME = "EMPTY_ZONE"; @@ -139,6 +140,11 @@ private static final Map tzdbSubstLetters = HashMap.newHashMap(512); private static final Map tzdbLinks = HashMap.newHashMap(512); + // Map of explicit dst offsets for metazones + // key: time zone ID + // value: explicit dstOffset for the corresponding metazone name + static final Map explicitDstOffsets = HashMap.newHashMap(32); + static enum DraftType { UNCONFIRMED, PROVISIONAL, @@ -855,6 +861,12 @@ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); names.putAll(exCities); + // Explicit metazone offsets + if (id.equals("root")) { + explicitDstOffsets.forEach((k, v) -> + names.put(METAZONE_DSTOFFSET_PREFIX + k, v)); + } + // If there's no UTC entry at this point, add an empty one if (!names.isEmpty() && !names.containsKey("UTC")) { names.putIfAbsent(METAZONE_ID_PREFIX + META_EMPTY_ZONE_NAME, EMPTY_ZONE); diff -Nru openjdk-25-25.0.4.1+1/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java openjdk-25-25.0.5+8/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java --- openjdk-25-25.0.4.1+1/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,7 +84,15 @@ if (fromLDT.isBefore(now) && toLDT.isAfter(now)) { metazone = attributes.getValue("mzone"); + + // Explicit metazone DST offsets. Only the "dst" offset is needed, + // as "std" is used by default when it doesn't match. + String dstOffset = attributes.getValue("dstOffset"); + if (dstOffset != null) { + CLDRConverter.explicitDstOffsets.put(tzid, dstOffset); + } } + pushIgnoredContainer(qName); break; diff -Nru openjdk-25-25.0.4.1+1/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java openjdk-25-25.0.5+8/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java --- openjdk-25-25.0.4.1+1/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -198,7 +198,8 @@ } else if (value instanceof String) { String valStr = (String)value; if (type == BundleType.TIMEZONE && - !key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) || + !(key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) || + key.startsWith(CLDRConverter.METAZONE_DSTOFFSET_PREFIX)) || valStr.startsWith(META_VALUE_PREFIX)) { out.printf(" { \"%s\", %s },\n", key, CLDRConverter.saveConvert(valStr, useJava)); } else { diff -Nru openjdk-25-25.0.4.1+1/make/modules/java.desktop/lib/ClientLibraries.gmk openjdk-25-25.0.5+8/make/modules/java.desktop/lib/ClientLibraries.gmk --- openjdk-25-25.0.4.1+1/make/modules/java.desktop/lib/ClientLibraries.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/modules/java.desktop/lib/ClientLibraries.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -397,6 +397,8 @@ AccelGlyphCache.c, \ CFLAGS := $(LIBFONTMANAGER_CFLAGS), \ CXXFLAGS := $(LIBFONTMANAGER_CFLAGS), \ + CXXFLAGS_gcc := -fno-rtti -fno-exceptions, \ + CXXFLAGS_clang := -fno-rtti -fno-exceptions, \ OPTIMIZATION := HIGHEST, \ CFLAGS_windows = -DCC_NOEX, \ EXTRA_HEADER_DIRS := $(LIBFONTMANAGER_EXTRA_HEADER_DIRS), \ diff -Nru openjdk-25-25.0.4.1+1/make/modules/java.sql.rowset/Java.gmk openjdk-25-25.0.5+8/make/modules/java.sql.rowset/Java.gmk --- openjdk-25-25.0.4.1+1/make/modules/java.sql.rowset/Java.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/modules/java.sql.rowset/Java.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -29,6 +29,7 @@ DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' +COPY += .xsd CLEAN_FILES += $(wildcard \ $(TOPDIR)/src/java.sql.rowset/share/classes/com/sun/rowset/*.properties \ $(TOPDIR)/src/java.sql.rowset/share/classes/javax/sql/rowset/*.properties) diff -Nru openjdk-25-25.0.4.1+1/make/modules/jdk.crypto.cryptoki/Lib.gmk openjdk-25-25.0.5+8/make/modules/jdk.crypto.cryptoki/Lib.gmk --- openjdk-25-25.0.4.1+1/make/modules/jdk.crypto.cryptoki/Lib.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/modules/jdk.crypto.cryptoki/Lib.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -35,8 +35,6 @@ NAME := j2pkcs11, \ OPTIMIZATION := LOW, \ EXTRA_HEADER_DIRS := java.base:libjava, \ - DISABLED_WARNINGS_gcc_p11_md.c := unused-variable, \ - DISABLED_WARNINGS_clang_p11_md.c := unused-variable, \ DISABLED_WARNINGS_clang_p11_util.c := format-nonliteral, \ LIBS_unix := $(LIBDL), \ )) diff -Nru openjdk-25-25.0.4.1+1/make/modules/jdk.jconsole/Launcher.gmk openjdk-25-25.0.5+8/make/modules/jdk.jconsole/Launcher.gmk --- openjdk-25-25.0.4.1+1/make/modules/jdk.jconsole/Launcher.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/modules/jdk.jconsole/Launcher.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -30,15 +30,15 @@ ################################################################################ ## Build jconsole ################################################################################ - -$(eval $(call SetupBuildLauncher, jconsole, \ - MAIN_CLASS := sun.tools.jconsole.JConsole, \ - JAVA_ARGS := \ - --add-opens java.base/java.io=jdk.jconsole \ - --add-modules ALL-DEFAULT \ - -Djconsole.showOutputViewer \ - -Djdk.attach.allowAttachSelf=true, \ - WINDOWS_JAVAW := true, \ -)) - +ifneq ($(ENABLE_HEADLESS_ONLY), true) + $(eval $(call SetupBuildLauncher, jconsole, \ + MAIN_CLASS := sun.tools.jconsole.JConsole, \ + JAVA_ARGS := \ + --add-opens java.base/java.io=jdk.jconsole \ + --add-modules ALL-DEFAULT \ + -Djconsole.showOutputViewer \ + -Djdk.attach.allowAttachSelf=true, \ + WINDOWS_JAVAW := true, \ + )) +endif ################################################################################ diff -Nru openjdk-25-25.0.4.1+1/make/modules/jdk.jpackage/Lib.gmk openjdk-25-25.0.5+8/make/modules/jdk.jpackage/Lib.gmk --- openjdk-25-25.0.4.1+1/make/modules/jdk.jpackage/Lib.gmk 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/make/modules/jdk.jpackage/Lib.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -56,8 +56,8 @@ EXTRA_SRC := common, \ INCLUDE_FILES := $(JPACKAGEAPPLAUNCHER_INCLUDE_FILES), \ OPTIMIZATION := LOW, \ + DISABLED_WARNINGS_clang_ExecCommand.c := format-nonliteral, \ DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \ - DISABLED_WARNINGS_clang_LinuxPackage.c := format-nonliteral, \ DISABLED_WARNINGS_clang_Log.cpp := unused-const-variable, \ CFLAGS_FILTER_OUT := -MD, \ CXXFLAGS_FILTER_OUT := -MD, \ @@ -94,6 +94,7 @@ LINK_TYPE := C++, \ OPTIMIZATION := LOW, \ DISABLED_WARNINGS_gcc_Log.cpp := unused-const-variable, \ + DISABLED_WARNINGS_clang_ExecCommand.c := format-nonliteral, \ DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \ DISABLED_WARNINGS_clang_tstrings.cpp := format-nonliteral, \ LD_SET_ORIGIN := false, \ diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/aarch64.ad openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/aarch64.ad --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/aarch64.ad 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/aarch64.ad 2026-10-19 12:10:20.000000000 +0000 @@ -3339,28 +3339,28 @@ // aarch64_enc_cmpxchg_acq is that we use load-acquire in the // CompareAndSwap sequence to serve as a barrier on acquiring a // lock. - enc_class aarch64_enc_cmpxchg_acq(memory mem, iRegLNoSp oldval, iRegLNoSp newval) %{ + enc_class aarch64_enc_cmpxchg_acq(memory mem, iRegL oldval, iRegL newval) %{ guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ false, noreg); %} - enc_class aarch64_enc_cmpxchgw_acq(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ + enc_class aarch64_enc_cmpxchgw_acq(memory mem, iRegI oldval, iRegI newval) %{ guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ true, /*release*/ true, /*weak*/ false, noreg); %} - enc_class aarch64_enc_cmpxchgs_acq(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ + enc_class aarch64_enc_cmpxchgs_acq(memory mem, iRegI oldval, iRegI newval) %{ guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::halfword, /*acquire*/ true, /*release*/ true, /*weak*/ false, noreg); %} - enc_class aarch64_enc_cmpxchgb_acq(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ + enc_class aarch64_enc_cmpxchgb_acq(memory mem, iRegI oldval, iRegI newval) %{ guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::byte, /*acquire*/ true, /*release*/ true, @@ -3368,7 +3368,7 @@ %} // auxiliary used for CompareAndSwapX to set result register - enc_class aarch64_enc_cset_eq(iRegINoSp res) %{ + enc_class aarch64_enc_cset_eq(iRegI res) %{ Register res_reg = as_Register($res$$reg); __ cset(res_reg, Assembler::EQ); %} @@ -8267,7 +8267,7 @@ // XXX No flag versions for CompareAndSwap{I,L,P,N} because matcher // can't match them -instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ +instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapB mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); @@ -8285,7 +8285,7 @@ ins_pipe(pipe_slow); %} -instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ +instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapS mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); @@ -8303,7 +8303,7 @@ ins_pipe(pipe_slow); %} -instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ +instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapI mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); @@ -8321,7 +8321,7 @@ ins_pipe(pipe_slow); %} -instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{ +instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapL mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); @@ -8358,7 +8358,7 @@ ins_pipe(pipe_slow); %} -instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ +instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapN mem (Binary oldval newval))); predicate(n->as_LoadStore()->barrier_data() == 0); @@ -8379,7 +8379,7 @@ // alternative CompareAndSwapX when we are eliding barriers -instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ +instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndSwapB mem (Binary oldval newval))); @@ -8398,7 +8398,7 @@ ins_pipe(pipe_slow); %} -instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ +instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndSwapS mem (Binary oldval newval))); @@ -8417,7 +8417,7 @@ ins_pipe(pipe_slow); %} -instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ +instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndSwapI mem (Binary oldval newval))); @@ -8436,7 +8436,7 @@ ins_pipe(pipe_slow); %} -instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{ +instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndSwapL mem (Binary oldval newval))); @@ -8474,7 +8474,7 @@ ins_pipe(pipe_slow); %} -instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ +instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndSwapN mem (Binary oldval newval))); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/aarch64_vector.ad openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/aarch64_vector.ad --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/aarch64_vector.ad 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/aarch64_vector.ad 2026-10-19 12:10:20.000000000 +0000 @@ -169,7 +169,9 @@ case Op_VectorMaskGen: case Op_LoadVectorMasked: case Op_StoreVectorMasked: + case Op_LoadVectorGather: case Op_StoreVectorScatter: + case Op_LoadVectorGatherMasked: case Op_StoreVectorScatterMasked: case Op_PopulateIndex: case Op_CompressM: @@ -178,12 +180,6 @@ return false; } break; - case Op_LoadVectorGather: - case Op_LoadVectorGatherMasked: - if (UseSVE == 0 || is_subword_type(bt)) { - return false; - } - break; case Op_MulAddVS2VI: if (length_in_bytes != 16) { return false; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -56,6 +56,8 @@ __ cbz(count, done); // Is GC active? + assert(!saved_regs.contains(rscratch1), "Sanity: about to clobber rscratch1"); + assert(!saved_regs.contains(rscratch2), "Sanity: about to clobber rscratch2"); Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); __ ldrb(rscratch1, gc_state); if (ShenandoahSATBBarrier && dest_uninitialized) { @@ -66,13 +68,26 @@ __ br(Assembler::EQ, done); } - __ push(saved_regs, sp); + __ push_call_clobbered_registers(); + // If arguments are not in proper places, shuffle them. + // Doing this via the stack is the most straight-forward way to avoid + // accidentally smashing any register. + if (c_rarg0 != src || c_rarg1 != dst || c_rarg2 != count) { + __ push(RegSet::of(src), sp); + __ push(RegSet::of(dst), sp); + __ push(RegSet::of(count), sp); + __ pop(RegSet::of(c_rarg2), sp); + __ pop(RegSet::of(c_rarg1), sp); + __ pop(RegSet::of(c_rarg0), sp); + } + address target = nullptr; if (UseCompressedOops) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop), src, dst, count); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop), src, dst, count); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop); } - __ pop(saved_regs, sp); + __ call_VM_leaf(target, 3); + __ pop_call_clobbered_registers(); __ bind(done); } } @@ -85,30 +100,13 @@ } } -void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp, - bool tosca_live, - bool expand_call) { - if (ShenandoahSATBBarrier) { - satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, rscratch1, tosca_live, expand_call); - } -} - -void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp1, - Register tmp2, - bool tosca_live, - bool expand_call) { - // If expand_call is true then we expand the call_VM_leaf macro - // directly to skip generating the check by - // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. - +void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2) { + assert(ShenandoahSATBBarrier, "Should be checked by caller"); assert(thread == rthread, "must be"); Label done; @@ -127,7 +125,12 @@ // Do we need to load the previous value? if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + if (UseCompressedOops) { + __ ldrw(pre_val, Address(obj, 0)); + __ decode_heap_oop(pre_val); + } else { + __ ldr(pre_val, Address(obj, 0)); + } } // Is the previous value null? @@ -151,33 +154,17 @@ __ b(done); __ bind(runtime); - // save the live input values - RegSet saved = RegSet::of(pre_val); - if (tosca_live) saved += RegSet::of(r0); - if (obj != noreg) saved += RegSet::of(obj); - - __ push(saved, sp); - - // Calling the runtime using the regular call_VM_leaf mechanism generates - // code (generated by InterpreterMacroAssember::call_VM_leaf_base) - // that checks that the *(rfp+frame::interpreter_frame_last_sp) == nullptr. - // - // If we care generating the pre-barrier without a frame (e.g. in the - // intrinsified Reference.get() routine) then rfp might be pointing to - // the caller frame and so this check will most likely fail at runtime. - // - // Expanding the call directly bypasses the generation of the check. - // So when we do not have have a full interpreter frame on the stack - // expand_call should be passed true. - - if (expand_call) { - assert(pre_val != c_rarg1, "smashed arg"); - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); - } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); - } - __ pop(saved, sp); + // Slow-path call + __ enter(/* strip_ret_addr = */ true); + __ push_call_clobbered_registers(); + if (c_rarg0 != pre_val) { + __ mov(c_rarg0, pre_val); + } + // Calling with super_call_VM_leaf with c_rarg0 bypasses interpreter checks and avoids any moves. + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), c_rarg0); + __ pop_call_clobbered_registers(); + __ leave(); __ bind(done); } @@ -241,7 +228,6 @@ bool is_narrow = UseCompressedOops && !is_native; Label heap_stable, not_cset; - __ enter(/*strip_ret_addr*/true); Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); __ ldrb(rscratch2, gc_state); @@ -276,29 +262,33 @@ __ tbz(rscratch2, 0, not_cset); } + // Slow-path call + __ enter(/* strip_ret_addr = */ true); __ push_call_clobbered_registers(); + address target = nullptr; if (is_strong) { if (is_narrow) { - __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow)); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow); } else { - __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong)); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); } } else if (is_weak) { if (is_narrow) { - __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow)); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow); } else { - __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak); } } else { assert(is_phantom, "only remaining strength"); assert(!is_narrow, "phantom access cannot be narrow"); - // AOT saved adapters need relocation for this call. - __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom))); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom); } - __ blr(lr); + // Calling with super_call_VM_leaf with c_rarg0/1 bypasses interpreter checks and avoids any moves. + __ super_call_VM_leaf(target, c_rarg0, c_rarg1); __ mov(rscratch1, r0); __ pop_call_clobbered_registers(); __ mov(r0, rscratch1); + __ leave(); __ bind(not_cset); @@ -306,7 +296,6 @@ __ pop(to_save, sp); __ bind(heap_stable); - __ leave(); } // @@ -356,22 +345,16 @@ // 3: apply keep-alive barrier if needed if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { - __ enter(/*strip_ret_addr*/true); - __ push_call_clobbered_registers(); - satb_write_barrier_pre(masm /* masm */, - noreg /* obj */, - dst /* pre_val */, - rthread /* thread */, - tmp1 /* tmp1 */, - tmp2 /* tmp2 */, - true /* tosca_live */, - true /* expand_call */); - __ pop_call_clobbered_registers(); - __ leave(); + satb_barrier(masm /* masm */, + noreg /* obj */, + dst /* pre_val */, + rthread /* thread */, + tmp1 /* tmp1 */, + tmp2 /* tmp2 */); } } -void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj) { +void ShenandoahBarrierSetAssembler::card_barrier(MacroAssembler* masm, Register obj) { assert(ShenandoahCardBarrier, "Should have been checked by caller"); __ lsr(obj, obj, CardTable::card_shift()); @@ -394,13 +377,13 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { - bool on_oop = is_reference_type(type); - if (!on_oop) { + // 1: non-reference types require no barriers + if (!is_reference_type(type)) { BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); return; } - // flatten object address if needed + // Flatten object address right away for simplicity: likely needed by barriers if (dst.index() == noreg && dst.offset() == 0) { if (dst.base() != tmp3) { __ mov(tmp3, dst.base()); @@ -409,20 +392,23 @@ __ lea(tmp3, dst); } - shenandoah_write_barrier_pre(masm, - tmp3 /* obj */, - tmp2 /* pre_val */, - rthread /* thread */, - tmp1 /* tmp */, - val != noreg /* tosca_live */, - false /* expand_call */); + // 2: pre-barrier: SATB needs the previous value + if (ShenandoahBarrierSet::need_satb_barrier(decorators, type)) { + satb_barrier(masm, + tmp3 /* obj */, + tmp2 /* pre_val */, + rthread /* thread */, + tmp1 /* tmp */, + rscratch1 /* tmp2 */); + } + // Store! BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg); - bool in_heap = (decorators & IN_HEAP) != 0; - bool needs_post_barrier = (val != noreg) && in_heap && ShenandoahCardBarrier; - if (needs_post_barrier) { - store_check(masm, tmp3); + // 3: post-barrier: card barrier needs store address + bool storing_non_null = (val != noreg); + if (ShenandoahBarrierSet::need_card_barrier(decorators, type) && storing_non_null) { + card_barrier(masm, tmp3); } } @@ -753,7 +739,7 @@ __ bind(runtime); __ push_call_clobbered_registers(); __ load_parameter(0, pre_val); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val); __ pop_call_clobbered_registers(); __ bind(done); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -40,23 +40,14 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: - void satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp1, - Register tmp2, - bool tosca_live, - bool expand_call); - void shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp, - bool tosca_live, - bool expand_call); + void satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2); - void store_check(MacroAssembler* masm, Register obj); + void card_barrier(MacroAssembler* masm, Register obj); void resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp = noreg); void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/matcher_aarch64.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/matcher_aarch64.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/matcher_aarch64.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/matcher_aarch64.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -130,11 +130,6 @@ return true; } - // Does target support predicated operation emulation. - static bool supports_vector_predicate_op_emulation(int vopc, int vlen, BasicType bt) { - return false; - } - // Does the CPU supports vector variable rotate instructions? static constexpr bool supports_vector_variable_rotates(void) { return false; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -6024,14 +6024,18 @@ // static int implKyber12To16( // byte[] condensed, int index, short[] parsed, int parsedLength) {} // - // (parsedLength or (parsedLength - 48) must be divisible by 64.) + // we assume that parsed and condensed are allocated such that for + // n = (parsedLength + 63) / 64 + // n blocks of 96 bytes of input can be processed, i.e. + // index + n * 96 <= condensed.length and + // n * 64 <= parsed.length // // condensed (byte[]) = c_rarg0 // condensedIndex = c_rarg1 - // parsed (short[112 or 256]) = c_rarg2 - // parsedLength (112 or 256) = c_rarg3 + // parsed (short[]) = c_rarg2 + // parsedLength = c_rarg3 address generate_kyber12To16() { - Label L_F00, L_loop, L_end; + Label L_F00, L_loop; __ BIND(L_F00); __ emit_int64(0x0f000f000f000f00); @@ -6156,75 +6160,8 @@ vs_st2_post(vs_front(vb), __ T8H, parsed); __ sub(parsedLength, parsedLength, 64); - __ cmp(parsedLength, (u1)64); - __ br(Assembler::GE, L_loop); - __ cbz(parsedLength, L_end); - - // if anything is left it should be a final 72 bytes of input - // i.e. a final 48 12-bit values. so we handle this by loading - // 48 bytes into all 16B lanes of front(vin) and only 24 - // bytes into the lower 8B lane of back(vin) - vs_ld3_post(vs_front(vin), __ T16B, condensed); - vs_ld3(vs_back(vin), __ T8B, condensed); - - // Expand vin[0] into va[0:1], and vin[1] into va[2:3] and va[4:5] - // n.b. target elements 2 and 3 of va duplicate elements 4 and - // 5 and target element 2 of vb duplicates element 4. - __ ushll(va[0], __ T8H, vin[0], __ T8B, 0); - __ ushll2(va[1], __ T8H, vin[0], __ T16B, 0); - __ ushll(va[2], __ T8H, vin[1], __ T8B, 0); - __ ushll2(va[3], __ T8H, vin[1], __ T16B, 0); - __ ushll(va[4], __ T8H, vin[1], __ T8B, 0); - __ ushll2(va[5], __ T8H, vin[1], __ T16B, 0); - - // This time expand just the lower 8 lanes - __ ushll(vb[0], __ T8H, vin[3], __ T8B, 0); - __ ushll(vb[2], __ T8H, vin[4], __ T8B, 0); - __ ushll(vb[4], __ T8H, vin[4], __ T8B, 0); - - // shift lo byte of copy 1 of the middle stripe into the high byte - __ shl(va[2], __ T8H, va[2], 8); - __ shl(va[3], __ T8H, va[3], 8); - __ shl(vb[2], __ T8H, vb[2], 8); - - // expand vin[2] into va[6:7] and lower 8 lanes of vin[5] into - // vb[6] pre-shifted by 4 to ensure top bits of the input 12-bit - // int are in bit positions [4..11]. - __ ushll(va[6], __ T8H, vin[2], __ T8B, 4); - __ ushll2(va[7], __ T8H, vin[2], __ T16B, 4); - __ ushll(vb[6], __ T8H, vin[5], __ T8B, 4); - - // mask hi 4 bits of each 1st 12-bit int in pair from copy1 and - // shift lo 4 bits of each 2nd 12-bit int in pair to bottom of - // copy2 - __ andr(va[2], __ T16B, va[2], v31); - __ andr(va[3], __ T16B, va[3], v31); - __ ushr(va[4], __ T8H, va[4], 4); - __ ushr(va[5], __ T8H, va[5], 4); - __ andr(vb[2], __ T16B, vb[2], v31); - __ ushr(vb[4], __ T8H, vb[4], 4); - - - - // sum hi 4 bits and lo 8 bits of each 1st 12-bit int in pair and - // hi 8 bits plus lo 4 bits of each 2nd 12-bit int in pair - - // n.b. ordering ensures: i) inputs are consumed before they are - // overwritten ii) order of 16-bit results across succsessive - // pairs of vectors in va and then lower half of vb reflects order - // of corresponding 12-bit inputs - __ addv(va[0], __ T8H, va[0], va[2]); - __ addv(va[2], __ T8H, va[1], va[3]); - __ addv(va[1], __ T8H, va[4], va[6]); - __ addv(va[3], __ T8H, va[5], va[7]); - __ addv(vb[0], __ T8H, vb[0], vb[2]); - __ addv(vb[1], __ T8H, vb[4], vb[6]); - - // store 48 results interleaved as shorts - vs_st2_post(vs_front(va), __ T8H, parsed); - vs_st2_post(vs_front(vs_front(vb)), __ T8H, parsed); - - __ BIND(L_end); + __ cmp(parsedLength, (u1)0); + __ br(Assembler::GT, L_loop); __ leave(); // required for proper stackwalking of RuntimeStub frame __ mov(r0, zr); // return 0 diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,6 +1,7 @@ /* * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2020, Red Hat Inc. All rights reserved. + * Copyright 2025 Arm Limited and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -223,10 +224,13 @@ // Neoverse // N1: 0xd0c // N2: 0xd49 + // N3: 0xd8e // V1: 0xd40 // V2: 0xd4f + // V3: 0xd84 if (_cpu == CPU_ARM && (model_is(0xd0c) || model_is(0xd49) || - model_is(0xd40) || model_is(0xd4f))) { + model_is(0xd40) || model_is(0xd4f) || + model_is(0xd8e) || model_is(0xd84))) { if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) { FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true); } @@ -261,7 +265,9 @@ // Neoverse // V1: 0xd40 // V2: 0xd4f - if (_cpu == CPU_ARM && (model_is(0xd40) || model_is(0xd4f))) { + // V3: 0xd84 + if (_cpu == CPU_ARM && + (model_is(0xd40) || model_is(0xd4f) || model_is(0xd84))) { if (FLAG_IS_DEFAULT(UseCryptoPmullForCRC32)) { FLAG_SET_DEFAULT(UseCryptoPmullForCRC32, true); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/arm/matcher_arm.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/arm/matcher_arm.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/arm/matcher_arm.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/arm/matcher_arm.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -123,11 +123,6 @@ return VM_Version::has_simd(); } - // Does target support predicated operation emulation. - static bool supports_vector_predicate_op_emulation(int vopc, int vlen, BasicType bt) { - return false; - } - // Does the CPU supports vector variable rotate instructions? static constexpr bool supports_vector_variable_rotates(void) { return false; // not supported diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2025 SAP SE. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -442,15 +442,13 @@ return; // CodeCache is full } - bool success = ce->emit_trampoline_stub_for_call(SharedRuntime::get_resolve_static_call_stub()); - if (!success) { return; } - - __ relocate(relocInfo::static_call_type); - // Note: At this point we do not have the address of the trampoline - // stub, and the entry point might be too far away for bl, so __ pc() - // serves as dummy and the bl will be patched later. - __ code()->set_insts_mark(); - __ bl(__ pc()); + AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(), + relocInfo::static_call_type); + address call_pc = __ trampoline_call(resolve); + if (call_pc == nullptr) { + ce->bailout("const/stub overflow in call with trampoline"); + return; + } ce->add_call_info_here(info()); ce->verify_oop_map(info()); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2025 SAP SE. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -610,67 +610,25 @@ // do nothing since all instructions are word aligned on ppc } - -bool LIR_Assembler::emit_trampoline_stub_for_call(address target, Register Rtoc) { - int start_offset = __ offset(); - // Put the entry point as a constant into the constant pool. - const address entry_point_toc_addr = __ address_constant(target, RelocationHolder::none); - if (entry_point_toc_addr == nullptr) { - bailout("const section overflow"); - return false; - } - const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); - - // Emit the trampoline stub which will be related to the branch-and-link below. - address stub = __ emit_trampoline_stub(entry_point_toc_offset, start_offset, Rtoc); - if (!stub) { - bailout("no space for trampoline stub"); - return false; - } - return true; -} - - void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { assert(rtype==relocInfo::opt_virtual_call_type || rtype==relocInfo::static_call_type, "unexpected rtype"); - bool success = emit_trampoline_stub_for_call(op->addr()); - if (!success) { return; } - - __ relocate(rtype); - // Note: At this point we do not have the address of the trampoline - // stub, and the entry point might be too far away for bl, so __ pc() - // serves as dummy and the bl will be patched later. - __ code()->set_insts_mark(); - __ bl(__ pc()); + address call_pc = __ trampoline_call(AddressLiteral(op->addr(), rtype)); + if (call_pc == nullptr) { + bailout("const/stub overflow in call with trampoline"); + return; + } add_call_info(code_offset(), op->info()); __ post_call_nop(); } - void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { __ calculate_address_from_global_toc(R2_TOC, __ method_toc()); - - // Virtual call relocation will point to ic load. - address virtual_call_meta_addr = __ pc(); - // Load a clear inline cache. - AddressLiteral empty_ic((address) Universe::non_oop_word()); - bool success = __ load_const_from_method_toc(R19_inline_cache_reg, empty_ic, R2_TOC); + bool success = __ ic_call(R2_TOC, op->addr()); if (!success) { - bailout("const section overflow"); + bailout("const/stub overflow in ic_call with trampoline"); return; } - // Call to fixup routine. Fixup routine uses ScopeDesc info - // to determine who we intended to call. - __ relocate(virtual_call_Relocation::spec(virtual_call_meta_addr)); - - success = emit_trampoline_stub_for_call(op->addr(), R2_TOC); - if (!success) { return; } - - // Note: At this point we do not have the address of the trampoline - // stub, and the entry point might be too far away for bl, so __ pc() - // serves as dummy and the bl will be patched later. - __ bl(__ pc()); add_call_info(code_offset(), op->info()); __ post_call_nop(); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,9 @@ #ifndef CPU_PPC_C1_LIRASSEMBLER_PPC_HPP #define CPU_PPC_C1_LIRASSEMBLER_PPC_HPP +// ArrayCopyStub needs access to bailout +friend class ArrayCopyStub; + private: ////////////////////////////////////////////////////////////////////////////// @@ -56,9 +59,6 @@ public: static const ConditionRegister BOOL_RESULT; - // Emit trampoline stub for call. Call bailout() if failed. Return true on success. - bool emit_trampoline_stub_for_call(address target, Register Rtoc = noreg); - enum { _static_call_stub_size = 4 * BytesPerInstWord + MacroAssembler::b64_patchable_size, // or smaller _call_stub_size = _static_call_stub_size + MacroAssembler::trampoline_stub_size, // or smaller diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -50,14 +50,14 @@ #define __ masm-> -void ShenandoahBarrierSetAssembler::satb_write_barrier(MacroAssembler *masm, - Register base, RegisterOrConstant ind_or_offs, - Register tmp1, Register tmp2, Register tmp3, - MacroAssembler::PreservationLevel preservation_level) { +void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler *masm, + Register base, RegisterOrConstant ind_or_offs, + Register tmp1, Register tmp2, Register tmp3, + MacroAssembler::PreservationLevel preservation_level) { if (ShenandoahSATBBarrier) { - __ block_comment("satb_write_barrier (shenandoahgc) {"); - satb_write_barrier_impl(masm, 0, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); - __ block_comment("} satb_write_barrier (shenandoahgc)"); + __ block_comment("satb_barrier (shenandoahgc) {"); + satb_barrier_impl(masm, 0, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); + __ block_comment("} satb_barrier (shenandoahgc)"); } } @@ -198,11 +198,12 @@ // In "load mode", this register acts as a temporary register and must // thus not be 'noreg'. In "preloaded mode", its content will be sustained. // tmp1/tmp2: Temporary registers, one of which must be non-volatile in "preloaded mode". -void ShenandoahBarrierSetAssembler::satb_write_barrier_impl(MacroAssembler *masm, DecoratorSet decorators, - Register base, RegisterOrConstant ind_or_offs, - Register pre_val, - Register tmp1, Register tmp2, - MacroAssembler::PreservationLevel preservation_level) { +void ShenandoahBarrierSetAssembler::satb_barrier_impl(MacroAssembler *masm, DecoratorSet decorators, + Register base, RegisterOrConstant ind_or_offs, + Register pre_val, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level) { + assert(ShenandoahSATBBarrier, "Should be checked by caller"); assert_different_registers(tmp1, tmp2, pre_val, noreg); Label skip_barrier; @@ -311,7 +312,7 @@ } // Invoke runtime. - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, R16_thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val); // Restore to-be-preserved registers. if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) { @@ -574,13 +575,13 @@ if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { if (ShenandoahSATBBarrier) { __ block_comment("keep_alive_barrier (shenandoahgc) {"); - satb_write_barrier_impl(masm, 0, noreg, noreg, dst, tmp1, tmp2, preservation_level); + satb_barrier_impl(masm, 0, noreg, noreg, dst, tmp1, tmp2, preservation_level); __ block_comment("} keep_alive_barrier (shenandoahgc)"); } } } -void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register base, RegisterOrConstant ind_or_offs, Register tmp) { +void ShenandoahBarrierSetAssembler::card_barrier(MacroAssembler* masm, Register base, RegisterOrConstant ind_or_offs, Register tmp) { assert(ShenandoahCardBarrier, "Should have been checked by caller"); assert_different_registers(base, tmp, R0); @@ -603,21 +604,33 @@ Register base, RegisterOrConstant ind_or_offs, Register val, Register tmp1, Register tmp2, Register tmp3, MacroAssembler::PreservationLevel preservation_level) { - if (is_reference_type(type)) { - if (ShenandoahSATBBarrier) { - satb_write_barrier(masm, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); - } + // 1: non-reference types require no barriers + if (!is_reference_type(type)) { + BarrierSetAssembler::store_at(masm, decorators, type, + base, ind_or_offs, + val, + tmp1, tmp2, tmp3, + preservation_level); + return; + } + + bool storing_non_null = (val != noreg); + + // 2: pre-barrier: SATB needs the previous value + if (ShenandoahBarrierSet::need_satb_barrier(decorators, type)) { + satb_barrier(masm, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); } + // Store! BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, preservation_level); - // No need for post barrier if storing null - if (ShenandoahCardBarrier && is_reference_type(type) && val != noreg) { - store_check(masm, base, ind_or_offs, tmp1); + // 3: post-barrier: card barrier needs store address + if (ShenandoahBarrierSet::need_card_barrier(decorators, type) && storing_non_null) { + card_barrier(masm, base, ind_or_offs, tmp1); } } @@ -855,13 +868,11 @@ Register tmp2 = stub->tmp2()->as_register(); assert_different_registers(addr, res, tmp1, tmp2); -#ifdef ASSERT - // Ensure that 'res' is 'R3_ARG1' and contains the same value as 'obj' to reduce the number of required - // copy instructions. assert(R3_RET == res, "res must be r3"); - __ cmpd(CR0, res, obj); - __ asm_assert_eq("result register must contain the reference stored in obj"); -#endif + + if (res != obj) { + __ mr(res, obj); + } DecoratorSet decorators = stub->decorators(); @@ -966,7 +977,7 @@ __ push_frame_reg_args(nbytes_save, R11_tmp1); // Invoke runtime. - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), R0_pre_val, R16_thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), R0_pre_val); // Restore to-be-preserved registers. __ pop_frame(); @@ -996,7 +1007,7 @@ __ save_volatile_gprs(R1_SP, -nbytes_save, true, false); // Load arguments from stack. - // No load required, as assured by assertions in 'ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub'. + // No load required, as caller has already loaded obj into R3. Register R3_obj = R3_ARG1; Register R4_load_addr = R4_ARG2; __ ld(R4_load_addr, -8, R1_SP); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -45,15 +45,15 @@ private: /* ==== Actual barrier implementations ==== */ - void satb_write_barrier_impl(MacroAssembler* masm, DecoratorSet decorators, - Register base, RegisterOrConstant ind_or_offs, - Register pre_val, - Register tmp1, Register tmp2, - MacroAssembler::PreservationLevel preservation_level); - - void store_check(MacroAssembler* masm, - Register base, RegisterOrConstant ind_or_offs, - Register tmp); + void satb_barrier_impl(MacroAssembler* masm, DecoratorSet decorators, + Register base, RegisterOrConstant ind_or_offs, + Register pre_val, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level); + + void card_barrier(MacroAssembler* masm, + Register base, RegisterOrConstant ind_or_offs, + Register tmp); void load_reference_barrier_impl(MacroAssembler* masm, DecoratorSet decorators, Register base, RegisterOrConstant ind_or_offs, @@ -85,10 +85,10 @@ #endif /* ==== Available barriers (facades of the actual implementations) ==== */ - void satb_write_barrier(MacroAssembler* masm, - Register base, RegisterOrConstant ind_or_offs, - Register tmp1, Register tmp2, Register tmp3, - MacroAssembler::PreservationLevel preservation_level); + void satb_barrier(MacroAssembler* masm, + Register base, RegisterOrConstant ind_or_offs, + Register tmp1, Register tmp2, Register tmp3, + MacroAssembler::PreservationLevel preservation_level); void load_reference_barrier(MacroAssembler* masm, DecoratorSet decorators, Register base, RegisterOrConstant ind_or_offs, diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1210,6 +1210,75 @@ } #endif // ABI_ELFv2 +bool MacroAssembler::ic_call(Register Rmethod_toc, + address target, + jint method_index, + bool scratch_emit, + bool fixed_size) { + AddressLiteral target_al(target, virtual_call_Relocation::spec(pc(), method_index)); + DEBUG_ONLY(int ic_load_offset = offset()); + + // Load a clear inline cache. + AddressLiteral empty_ic((address) Universe::non_oop_word()); + bool success = load_const_from_method_toc(R19_inline_cache_reg, empty_ic, Rmethod_toc, fixed_size); + if (!success) return false; + + assert(MacroAssembler::is_load_const_from_method_toc_at(addr_at(ic_load_offset)), + "should be load from TOC"); + + address call_pc = trampoline_call(target_al, Rmethod_toc, scratch_emit); + return call_pc != nullptr; +} + +address MacroAssembler::trampoline_call(AddressLiteral target, + Register Rmethod_toc, + bool scratch_emit) { + // First, emit the trampoline stub + if (!scratch_emit) { + RelocationHolder rh = trampoline_stub_Relocation::spec(pc() /* of the bl below */); + + // Put the target's entry point as a constant into the constant pool. + const address target_toc_addr = address_constant((address)target.value()); + if (target_toc_addr == nullptr) return nullptr; + + const int target_toc_offset = offset_to_method_toc(target_toc_addr); + address stub = start_a_stub(64); + if (stub == nullptr) return nullptr; + + // Annotate the stub with a relocation that points to the owning call instruction. + relocate(rh); + DEBUG_ONLY(int stub_start_offset = offset()); + + // For java_to_interp stubs we use R11_scratch1 as scratch register + // and in call trampoline stubs we use R12_scratch2. This way we + // can distinguish them (see is_NativeCallTrampolineStub_at()). + Register reg_scratch = R12_scratch2; + + if (Rmethod_toc == noreg) { + calculate_address_from_global_toc(reg_scratch, method_toc()); + Rmethod_toc = reg_scratch; + } + + ld_largeoffset_unchecked(reg_scratch, target_toc_offset, Rmethod_toc, false); + mtctr(reg_scratch); + bctr(); + + assert(target_toc_offset == NativeCallTrampolineStub_at(addr_at(stub_start_offset))->destination_toc_offset(), + "encoded offset into the constant pool must match"); + assert((uint)(offset() - stub_start_offset) <= trampoline_stub_size, "should be good size"); + assert(is_NativeCallTrampolineStub_at(addr_at(stub_start_offset)), "doesn't look like a trampoline"); + + // End the stub. + end_a_stub(); + } + + // The call will be resolved / patched later. + address call_pc = pc(); + relocate(target.rspec()); + bl(call_pc); + return call_pc; +} + void MacroAssembler::post_call_nop() { // Make inline again when loom is always enabled. if (!Continuations::enabled()) { @@ -2626,50 +2695,6 @@ //verify_tlab(); not implemented } -address MacroAssembler::emit_trampoline_stub(int destination_toc_offset, - int insts_call_instruction_offset, Register Rtoc) { - // Start the stub. - address stub = start_a_stub(64); - if (stub == nullptr) { return nullptr; } // CodeCache full: bail out - - // Create a trampoline stub relocation which relates this trampoline stub - // with the call instruction at insts_call_instruction_offset in the - // instructions code-section. - relocate(trampoline_stub_Relocation::spec(code()->insts()->start() + insts_call_instruction_offset)); - const int stub_start_offset = offset(); - - // For java_to_interp stubs we use R11_scratch1 as scratch register - // and in call trampoline stubs we use R12_scratch2. This way we - // can distinguish them (see is_NativeCallTrampolineStub_at()). - Register reg_scratch = R12_scratch2; - - // Now, create the trampoline stub's code: - // - load the TOC - // - load the call target from the constant pool - // - call - if (Rtoc == noreg) { - calculate_address_from_global_toc(reg_scratch, method_toc()); - Rtoc = reg_scratch; - } - - ld_largeoffset_unchecked(reg_scratch, destination_toc_offset, Rtoc, false); - mtctr(reg_scratch); - bctr(); - - const address stub_start_addr = addr_at(stub_start_offset); - - // Assert that the encoded destination_toc_offset can be identified and that it is correct. - assert(destination_toc_offset == NativeCallTrampolineStub_at(stub_start_addr)->destination_toc_offset(), - "encoded offset into the constant pool must match"); - // Trampoline_stub_size should be good. - assert((uint)(offset() - stub_start_offset) <= trampoline_stub_size, "should be good size"); - assert(is_NativeCallTrampolineStub_at(stub_start_addr), "doesn't look like a trampoline"); - - // End the stub. - end_a_stub(); - return stub; -} - // "The box" is the space on the stack where we copy the object mark. void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register oop, Register box, Register temp, Register displaced_header, Register current_header) { @@ -3436,24 +3461,6 @@ } } -int MacroAssembler::instr_size_for_load_klass() { - static int computed_size = -1; - - // Not yet computed? - if (computed_size == -1) { - - // Determine by scratch emit. - ResourceMark rm; - int code_size = 16 * BytesPerInstWord; - CodeBuffer cb("load_klass scratch buffer", code_size, 0); - MacroAssembler* a = new MacroAssembler(&cb); - a->load_klass(R11_scratch1, R11_scratch1); - computed_size = a->offset(); - } - - return computed_size; -} - void MacroAssembler::decode_klass_not_null(Register dst, Register src) { assert(dst != R0, "Dst reg may not be R0, as R0 is used here."); if (src == noreg) src = dst; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -380,9 +380,20 @@ Register toc); #endif + // CompiledIC call + bool ic_call(Register Rmethod_toc, + address target, + jint method_index = 0, + bool scratch_emit = false, + bool fixed_size = false); static int ic_check_size(); int ic_check(int end_alignment); + enum { trampoline_stub_size = 6 * 4 }; + address trampoline_call(AddressLiteral target, + Register Rmethod_toc = noreg, + bool scratch_emit = false); + protected: // It is imperative that all calls into the VM are handled via the @@ -704,9 +715,6 @@ Label& slow_case // continuation point if fast allocation fails ); - enum { trampoline_stub_size = 6 * 4 }; - address emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc = noreg); - void compiler_fast_lock_object(ConditionRegister flag, Register oop, Register box, Register tmp1, Register tmp2, Register tmp3); @@ -810,7 +818,6 @@ MacroAssembler::PreservationLevel preservation_level); void load_method_holder(Register holder, Register method); - static int instr_size_for_load_klass(); void decode_klass_not_null(Register dst, Register src = noreg); Register encode_klass_not_null(Register dst, Register src = noreg); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/matcher_ppc.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/matcher_ppc.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/matcher_ppc.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/matcher_ppc.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -132,11 +132,6 @@ return false; } - // Does target support predicated operation emulation. - static bool supports_vector_predicate_op_emulation(int vopc, int vlen, BasicType bt) { - return false; - } - // Does the CPU supports vector variable rotate instructions? static constexpr bool supports_vector_variable_rotates(void) { return false; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/ppc.ad openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/ppc.ad --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/ppc.ad 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/ppc.ad 2026-10-19 12:10:20.000000000 +0000 @@ -1177,18 +1177,7 @@ } int MachCallDynamicJavaNode::ret_addr_offset() { - // Offset is 4 with postalloc expanded calls (bl is one instruction). We use - // postalloc expanded calls if we use inline caches and do not update method data. - if (UseInlineCaches) return 4; - - int vtable_index = this->_vtable_index; - if (vtable_index < 0) { - // Must be invalid_vtable_index, not nonvirtual_vtable_index. - assert(vtable_index == Method::invalid_vtable_index, "correct sentinel value"); - return 12; - } else { - return 20 + MacroAssembler::instr_size_for_load_klass(); - } + return 12; } int MachCallRuntimeNode::ret_addr_offset() { @@ -1311,9 +1300,6 @@ public: - // Emit call stub, compiled java to interpreter. - static void emit_trampoline_stub(C2_MacroAssembler *masm, int destination_toc_offset, int insts_call_instruction_offset); - // Size of call trampoline stub. // This doesn't need to be accurate to the byte, but it // must be larger than or equal to the real size of the stub. @@ -1332,81 +1318,6 @@ source %{ -// Emit a trampoline stub for a call to a target which is too far away. -// -// code sequences: -// -// call-site: -// branch-and-link to or -// -// Related trampoline stub for this call-site in the stub section: -// load the call target from the constant pool -// branch via CTR (LR/link still points to the call-site above) - -void CallStubImpl::emit_trampoline_stub(C2_MacroAssembler *masm, int destination_toc_offset, int insts_call_instruction_offset) { - address stub = __ emit_trampoline_stub(destination_toc_offset, insts_call_instruction_offset); - if (stub == nullptr) { - ciEnv::current()->record_out_of_memory_failure(); - } -} - -//============================================================================= - -// Emit an inline branch-and-link call and a related trampoline stub. -// -// code sequences: -// -// call-site: -// branch-and-link to or -// -// Related trampoline stub for this call-site in the stub section: -// load the call target from the constant pool -// branch via CTR (LR/link still points to the call-site above) -// - -typedef struct { - int insts_call_instruction_offset; - int ret_addr_offset; -} EmitCallOffsets; - -// Emit a branch-and-link instruction that branches to a trampoline. -// - Remember the offset of the branch-and-link instruction. -// - Add a relocation at the branch-and-link instruction. -// - Emit a branch-and-link. -// - Remember the return pc offset. -EmitCallOffsets emit_call_with_trampoline_stub(C2_MacroAssembler *masm, address entry_point, relocInfo::relocType rtype) { - EmitCallOffsets offsets = { -1, -1 }; - const int start_offset = __ offset(); - offsets.insts_call_instruction_offset = __ offset(); - - // No entry point given, use the current pc. - if (entry_point == nullptr) entry_point = __ pc(); - - // Put the entry point as a constant into the constant pool. - const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none); - if (entry_point_toc_addr == nullptr) { - ciEnv::current()->record_out_of_memory_failure(); - return offsets; - } - const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); - - // Emit the trampoline stub which will be related to the branch-and-link below. - CallStubImpl::emit_trampoline_stub(masm, entry_point_toc_offset, offsets.insts_call_instruction_offset); - if (ciEnv::current()->failing()) { return offsets; } // Code cache may be full. - __ relocate(rtype); - - // Note: At this point we do not have the address of the trampoline - // stub, and the entry point might be too far away for bl, so __ pc() - // serves as dummy and the bl will be patched later. - __ bl((address) __ pc()); - - offsets.ret_addr_offset = __ offset() - start_offset; - - return offsets; -} - -//============================================================================= - // Factory for creating loadConL* nodes for large/small constant pool. static inline jlong replicate_immF(float con) { @@ -3337,205 +3248,50 @@ // Usage of r1 and r2 in the stubs allows to distinguish them. enc_class enc_java_static_call(method meth) %{ address entry_point = (address)$meth$$method; + address call_pc; if (!_method) { // A call to a runtime wrapper, e.g. new, new_typeArray_Java, uncommon_trap. - emit_call_with_trampoline_stub(masm, entry_point, relocInfo::runtime_call_type); - if (ciEnv::current()->failing()) { return; } // Code cache may be full. - } else { - // Remember the offset not the address. - const int start_offset = __ offset(); - - // The trampoline stub. - // No entry point given, use the current pc. - // Make sure branch fits into - if (entry_point == nullptr) entry_point = __ pc(); - - // Put the entry point as a constant into the constant pool. - const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none); - if (entry_point_toc_addr == nullptr) { - ciEnv::current()->record_out_of_memory_failure(); + call_pc = __ trampoline_call(AddressLiteral(entry_point, relocInfo::runtime_call_type)); + if (call_pc == nullptr) { + ciEnv::current()->record_failure("CodeCache is full"); return; } - const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); - - // Emit the trampoline stub which will be related to the branch-and-link below. - CallStubImpl::emit_trampoline_stub(masm, entry_point_toc_offset, start_offset); - if (ciEnv::current()->failing()) { return; } // Code cache may be full. + } else { int method_index = resolved_method_index(masm); - __ relocate(_optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) - : static_call_Relocation::spec(method_index)); - - // The real call. - // Note: At this point we do not have the address of the trampoline - // stub, and the entry point might be too far away for bl, so __ pc() - // serves as dummy and the bl will be patched later. - __ set_inst_mark(); - __ bl(__ pc()); // Emits a relocation. - - // The stub for call to interpreter. - address stub = CompiledDirectCall::emit_to_interp_stub(masm); - __ clear_inst_mark(); - if (stub == nullptr) { + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); + call_pc = __ trampoline_call(AddressLiteral(entry_point, rspec)); + if (call_pc == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } - } - __ post_call_nop(); - %} - // Second node of expanded dynamic call - the call. - enc_class enc_java_dynamic_call_sched(method meth) %{ - if (!ra_->C->output()->in_scratch_emit_size()) { - // Create a call trampoline stub for the given method. - const address entry_point = !($meth$$method) ? nullptr : (address)$meth$$method; - const address entry_point_const = __ address_constant(entry_point, RelocationHolder::none); - if (entry_point_const == nullptr) { - ciEnv::current()->record_out_of_memory_failure(); + // Emit stub for static call + address stub = CompiledDirectCall::emit_to_interp_stub(masm, call_pc); + if (stub == nullptr) { + ciEnv::current()->record_failure("CodeCache is full"); return; } - const int entry_point_const_toc_offset = __ offset_to_method_toc(entry_point_const); - CallStubImpl::emit_trampoline_stub(masm, entry_point_const_toc_offset, __ offset()); - if (ra_->C->env()->failing()) { return; } // Code cache may be full. - - // Build relocation at call site with ic position as data. - assert((_load_ic_hi_node != nullptr && _load_ic_node == nullptr) || - (_load_ic_hi_node == nullptr && _load_ic_node != nullptr), - "must have one, but can't have both"); - assert((_load_ic_hi_node != nullptr && _load_ic_hi_node->_cbuf_insts_offset != -1) || - (_load_ic_node != nullptr && _load_ic_node->_cbuf_insts_offset != -1), - "must contain instruction offset"); - const int virtual_call_oop_addr_offset = _load_ic_hi_node != nullptr - ? _load_ic_hi_node->_cbuf_insts_offset - : _load_ic_node->_cbuf_insts_offset; - const address virtual_call_oop_addr = __ addr_at(virtual_call_oop_addr_offset); - assert(MacroAssembler::is_load_const_from_method_toc_at(virtual_call_oop_addr), - "should be load from TOC"); - int method_index = resolved_method_index(masm); - __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr, method_index)); } - - // At this point I do not have the address of the trampoline stub, - // and the entry point might be too far away for bl. Pc() serves - // as dummy and bl will be patched later. - __ bl((address) __ pc()); __ post_call_nop(); %} - // postalloc expand emitter for virtual calls. - enc_class postalloc_expand_java_dynamic_call_sched(method meth, iRegLdst toc) %{ - - // Create the nodes for loading the IC from the TOC. - loadConLNodesTuple loadConLNodes_IC = - loadConLNodesTuple_create(ra_, n_toc, new immLOper((jlong) Universe::non_oop_word()), - OptoReg::Name(R19_H_num), OptoReg::Name(R19_num)); - - // Create the call node. - CallDynamicJavaDirectSchedNode *call = new CallDynamicJavaDirectSchedNode(); - call->_method_handle_invoke = _method_handle_invoke; - call->_vtable_index = _vtable_index; - call->_method = _method; - call->_optimized_virtual = _optimized_virtual; - call->_tf = _tf; - call->_entry_point = _entry_point; - call->_cnt = _cnt; - call->_guaranteed_safepoint = true; - call->_oop_map = _oop_map; - call->_jvms = _jvms; - call->_jvmadj = _jvmadj; - call->_has_ea_local_in_scope = _has_ea_local_in_scope; - call->_in_rms = _in_rms; - call->_nesting = _nesting; - call->_override_symbolic_info = _override_symbolic_info; - call->_arg_escape = _arg_escape; - - // New call needs all inputs of old call. - // Req... - for (uint i = 0; i < req(); ++i) { - // The expanded node does not need toc any more. - // Add the inline cache constant here instead. This expresses the - // register of the inline cache must be live at the call. - // Else we would have to adapt JVMState by -1. - if (i == mach_constant_base_node_input()) { - call->add_req(loadConLNodes_IC._last); - } else { - call->add_req(in(i)); - } - } - // ...as well as prec - for (uint i = req(); i < len(); ++i) { - call->add_prec(in(i)); - } - - // Remember nodes loading the inline cache into r19. - call->_load_ic_hi_node = loadConLNodes_IC._large_hi; - call->_load_ic_node = loadConLNodes_IC._small; - - // Operands for new nodes. - call->_opnds[0] = _opnds[0]; - call->_opnds[1] = _opnds[1]; - - // Only the inline cache is associated with a register. - assert(Matcher::inline_cache_reg() == OptoReg::Name(R19_num), "ic reg should be R19"); - - // Push new nodes. - if (loadConLNodes_IC._large_hi) nodes->push(loadConLNodes_IC._large_hi); - if (loadConLNodes_IC._last) nodes->push(loadConLNodes_IC._last); - nodes->push(call); - %} - // Compound version of call dynamic // Toc is only passed so that it can be used in ins_encode statement. // In the code we have to use $constanttablebase. enc_class enc_java_dynamic_call(method meth, iRegLdst toc) %{ int start_offset = __ offset(); - - Register Rtoc = (ra_) ? $constanttablebase : R2_TOC; - - int vtable_index = this->_vtable_index; - if (vtable_index < 0) { - // Must be invalid_vtable_index, not nonvirtual_vtable_index. - assert(vtable_index == Method::invalid_vtable_index, "correct sentinel value"); - Register ic_reg = as_Register(Matcher::inline_cache_reg_encode()); - - // Virtual call relocation will point to ic load. - address virtual_call_meta_addr = __ pc(); - // Load a clear inline cache. - AddressLiteral empty_ic((address) Universe::non_oop_word()); - bool success = __ load_const_from_method_toc(ic_reg, empty_ic, Rtoc, /*fixed_size*/ true); - if (!success) { - ciEnv::current()->record_out_of_memory_failure(); - return; - } - // CALL to fixup routine. Fixup routine uses ScopeDesc info - // to determine who we intended to call. - __ relocate(virtual_call_Relocation::spec(virtual_call_meta_addr)); - emit_call_with_trampoline_stub(masm, (address)$meth$$method, relocInfo::none); - if (ciEnv::current()->failing()) { return; } // Code cache may be full. - assert(((MachCallDynamicJavaNode*)this)->ret_addr_offset() == __ offset() - start_offset, - "Fix constant in ret_addr_offset(), expected %d", __ offset() - start_offset); - } else { - assert(!UseInlineCaches, "expect vtable calls only if not using ICs"); - // Go thru the vtable. Get receiver klass. Receiver already - // checked for non-null. If we'll go thru a C2I adapter, the - // interpreter expects method in R19_method. - - __ load_klass(R11_scratch1, R3); - - int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index * vtableEntry::size_in_bytes(); - int v_off = entry_offset + in_bytes(vtableEntry::method_offset()); - __ li(R19_method, v_off); - __ ldx(R19_method/*method*/, R19_method/*method offset*/, R11_scratch1/*class*/); - // NOTE: for vtable dispatches, the vtable entry will never be - // null. However it may very well end up in handle_wrong_method - // if the method is abstract for the particular class. - __ ld(R11_scratch1, in_bytes(Method::from_compiled_offset()), R19_method); - // Call target. Either compiled code or C2I adapter. - __ mtctr(R11_scratch1); - __ bctrl(); - assert(((MachCallDynamicJavaNode*)this)->ret_addr_offset() == __ offset() - start_offset, - "Fix constant in ret_addr_offset(), expected %d", __ offset() - start_offset); + int method_index = resolved_method_index(masm); + bool scratch_emit = ra_ == nullptr; + Register Rtoc = scratch_emit ? R2_TOC : $constanttablebase; + bool success = __ ic_call(Rtoc, (address)$meth$$method, method_index, scratch_emit, true /*fixed_size*/); + if (!success) { + ciEnv::current()->record_failure("CodeCache is full"); + return; } + assert(((MachCallDynamicJavaNode*)this)->ret_addr_offset() == __ offset() - start_offset, + "Fix constant in ret_addr_offset(), expected %d", __ offset() - start_offset); __ post_call_nop(); %} @@ -3736,30 +3492,34 @@ // 4 what apparently works and saves us some spills. return_addr(STACK 4); - // Location of native (C/C++) and interpreter return values. This - // is specified to be the same as Java. In the 32-bit VM, long - // values are actually returned from native calls in O0:O1 and - // returned to the interpreter in I0:I1. The copying to and from - // the register pairs is done by the appropriate call and epilog - // opcodes. This simplifies the register allocator. - c_return_value %{ - assert((ideal_reg >= Op_RegI && ideal_reg <= Op_RegL) || - (ideal_reg == Op_RegN && CompressedOops::base() == nullptr && CompressedOops::shift() == 0), - "only return normal values"); - // enum names from opcodes.hpp: Op_Node Op_Set Op_RegN Op_RegI Op_RegP Op_RegF Op_RegD Op_RegL - static int typeToRegLo[Op_RegL+1] = { 0, 0, R3_num, R3_num, R3_num, F1_num, F1_num, R3_num }; - static int typeToRegHi[Op_RegL+1] = { 0, 0, OptoReg::Bad, R3_H_num, R3_H_num, OptoReg::Bad, F1_H_num, R3_H_num }; - return OptoRegPair(typeToRegHi[ideal_reg], typeToRegLo[ideal_reg]); - %} - // Location of compiled Java return values. Same as C return_value %{ assert((ideal_reg >= Op_RegI && ideal_reg <= Op_RegL) || (ideal_reg == Op_RegN && CompressedOops::base() == nullptr && CompressedOops::shift() == 0), "only return normal values"); - // enum names from opcodes.hpp: Op_Node Op_Set Op_RegN Op_RegI Op_RegP Op_RegF Op_RegD Op_RegL - static int typeToRegLo[Op_RegL+1] = { 0, 0, R3_num, R3_num, R3_num, F1_num, F1_num, R3_num }; - static int typeToRegHi[Op_RegL+1] = { 0, 0, OptoReg::Bad, R3_H_num, R3_H_num, OptoReg::Bad, F1_H_num, R3_H_num }; + // enum names from opcodes.hpp + static int typeToRegLo[Op_RegL+1] = { + 0, // Op_Node + 0, // Op_Set + R3_num, // Op_RegN + R3_num, // Op_RegI + R3_num, // Op_RegP + F1_num, // Op_RegF + F1_num, // Op_RegD + R3_num, // Op_RegL + }; + + static int typeToRegHi[Op_RegL+1] = { + 0, // Op_Node + 0, // Op_Set + OptoReg::Bad, // Op_RegN + OptoReg::Bad, // Op_RegI + R3_H_num, // Op_RegP + OptoReg::Bad, // Op_RegF + F1_H_num, // Op_RegD + R3_H_num // Op_RegL + }; + return OptoRegPair(typeToRegHi[ideal_reg], typeToRegLo[ideal_reg]); %} %} @@ -13928,15 +13688,14 @@ // ============================================================================ // Call Instructions -// Call Java Static Instruction - source %{ #include "runtime/continuation.hpp" %} -// Schedulable version of call static node. +// Call Java Static Instruction + instruct CallStaticJavaDirect(method meth) %{ match(CallStaticJava); effect(USE meth); @@ -13952,51 +13711,9 @@ // Call Java Dynamic Instruction -// Used by postalloc expand of CallDynamicJavaDirectSchedEx (actual call). -// Loading of IC was postalloc expanded. The nodes loading the IC are reachable -// via fields ins_field_load_ic_hi_node and ins_field_load_ic_node. -// The call destination must still be placed in the constant pool. -instruct CallDynamicJavaDirectSched(method meth) %{ - match(CallDynamicJava); // To get all the data fields we need ... - effect(USE meth); - predicate(false); // ... but never match. - - ins_field_load_ic_hi_node(loadConL_hiNode*); - ins_field_load_ic_node(loadConLNode*); - ins_num_consts(1 /* 1 patchable constant: call destination */); - - format %{ "BL \t// dynamic $meth ==> " %} - size((Continuations::enabled() ? 8 : 4)); - ins_encode( enc_java_dynamic_call_sched(meth) ); - ins_pipe(pipe_class_call); -%} - -// Schedulable (i.e. postalloc expanded) version of call dynamic java. -// We use postalloc expanded calls if we use inline caches -// and do not update method data. -// -// This instruction has two constants: inline cache (IC) and call destination. -// Loading the inline cache will be postalloc expanded, thus leaving a call with -// one constant. -instruct CallDynamicJavaDirectSched_Ex(method meth) %{ - match(CallDynamicJava); - effect(USE meth); - predicate(UseInlineCaches); - ins_cost(CALL_COST); - - ins_num_consts(2 /* 2 patchable constants: inline cache, call destination. */); - - format %{ "CALL,dynamic $meth \t// postalloc expanded" %} - postalloc_expand( postalloc_expand_java_dynamic_call_sched(meth, constanttablebase) ); -%} - -// Compound version of call dynamic java -// We use postalloc expanded calls if we use inline caches -// and do not update method data. instruct CallDynamicJavaDirect(method meth) %{ match(CallDynamicJava); effect(USE meth); - predicate(!UseInlineCaches); ins_cost(CALL_COST); // Enc_java_to_runtime_call needs up to 4 constants (method data oop). diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1794,10 +1794,8 @@ check_continuation_enter_argument(regs[pos_is_cont].first(), reg_is_cont, "isContinue"); check_continuation_enter_argument(regs[pos_is_virtual].first(), reg_is_virtual, "isVirtualThread"); - address resolve_static_call = SharedRuntime::get_resolve_static_call_stub(); - + AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(), relocInfo::static_call_type); address start = __ pc(); - Label L_thaw, L_exit; // i2i entry used at interp_only_mode only @@ -1834,33 +1832,17 @@ // Emit compiled static call. The call will be always resolved to the c2i // entry of Continuation.enter(Continuation c, boolean isContinue). - // There are special cases in SharedRuntime::resolve_static_call_C() and - // SharedRuntime::resolve_sub_helper_internal() to achieve this - // See also corresponding call below. - address c2i_call_pc = __ pc(); - int start_offset = __ offset(); - // Put the entry point as a constant into the constant pool. - const address entry_point_toc_addr = __ address_constant(resolve_static_call, RelocationHolder::none); - const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); - guarantee(entry_point_toc_addr != nullptr, "const section overflow"); - - // Emit the trampoline stub which will be related to the branch-and-link below. - address stub = __ emit_trampoline_stub(entry_point_toc_offset, start_offset); - guarantee(stub != nullptr, "no space for trampoline stub"); - - __ relocate(relocInfo::static_call_type); - // Note: At this point we do not have the address of the trampoline - // stub, and the entry point might be too far away for bl, so __ pc() - // serves as dummy and the bl will be patched later. - __ bl(__ pc()); + address c2i_call_pc = __ trampoline_call(resolve); + guarantee(c2i_call_pc != nullptr, "CodeCache is full at gen_continuation_enter"); + + // Emit stub for static call + address stub = CompiledDirectCall::emit_to_interp_stub(masm, c2i_call_pc); + guarantee(stub != nullptr, "CodeCache is full at gen_continuation_enter"); + oop_maps->add_gc_map(__ pc() - start, map); __ post_call_nop(); __ b(L_exit); - - // static stub for the call above - stub = CompiledDirectCall::emit_to_interp_stub(masm, c2i_call_pc); - guarantee(stub != nullptr, "no space for static stub"); } // compiled entry @@ -1885,22 +1867,9 @@ // SharedRuntime::find_callee_info_helper() which calls // LinkResolver::resolve_continuation_enter() which resolves the call to // Continuation.enter(Continuation c, boolean isContinue). - address call_pc = __ pc(); - int start_offset = __ offset(); - // Put the entry point as a constant into the constant pool. - const address entry_point_toc_addr = __ address_constant(resolve_static_call, RelocationHolder::none); - const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); - guarantee(entry_point_toc_addr != nullptr, "const section overflow"); - - // Emit the trampoline stub which will be related to the branch-and-link below. - address stub = __ emit_trampoline_stub(entry_point_toc_offset, start_offset); - guarantee(stub != nullptr, "no space for trampoline stub"); - - __ relocate(relocInfo::static_call_type); - // Note: At this point we do not have the address of the trampoline - // stub, and the entry point might be too far away for bl, so __ pc() - // serves as dummy and the bl will be patched later. - __ bl(__ pc()); + address call_pc = __ trampoline_call(resolve); + guarantee(call_pc != nullptr, "CodeCache is full at gen_continuation_enter"); + oop_maps->add_gc_map(__ pc() - start, map); __ post_call_nop(); @@ -1953,8 +1922,8 @@ __ blr(); // static stub for the call above - stub = CompiledDirectCall::emit_to_interp_stub(masm, call_pc); - guarantee(stub != nullptr, "no space for static stub"); + address stub = CompiledDirectCall::emit_to_interp_stub(masm, call_pc); + guarantee(stub != nullptr, "CodeCache is full at gen_continuation_enter"); } static void gen_continuation_yield(MacroAssembler* masm, diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -59,6 +59,8 @@ Address gc_state(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); assert_different_registers(src, dst, count, t0); + assert(!saved_regs.contains(t0), "Sanity: about to clobber t0"); + __ lbu(t0, gc_state); if (ShenandoahSATBBarrier && dest_uninitialized) { __ test_bit(t0, t0, ShenandoahHeap::HAS_FORWARDED_BITPOS); @@ -68,14 +70,26 @@ __ beqz(t0, done); } - __ push_reg(saved_regs, sp); + __ push_call_clobbered_registers(); + // If arguments are not in proper places, shuffle them. + // Doing this via the stack is the most straight-forward way to avoid + // accidentally smashing any register. + if (c_rarg0 != src || c_rarg1 != dst || c_rarg2 != count) { + __ push_reg(RegSet::of(src), sp); + __ push_reg(RegSet::of(dst), sp); + __ push_reg(RegSet::of(count), sp); + __ pop_reg(RegSet::of(c_rarg2), sp); + __ pop_reg(RegSet::of(c_rarg1), sp); + __ pop_reg(RegSet::of(c_rarg0), sp); + } + address target = nullptr; if (UseCompressedOops) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop), - src, dst, count); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop), src, dst, count); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop); } - __ pop_reg(saved_regs, sp); + __ call_VM_leaf(target, 3); + __ pop_call_clobbered_registers(); __ bind(done); } } @@ -88,29 +102,13 @@ } } -void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp, - bool tosca_live, - bool expand_call) { - if (ShenandoahSATBBarrier) { - satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, t0, tosca_live, expand_call); - } -} - -void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp1, - Register tmp2, - bool tosca_live, - bool expand_call) { - // If expand_call is true then we expand the call_VM_leaf macro - // directly to skip generating the check by - // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. +void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2) { + assert(ShenandoahSATBBarrier, "Should be checked by caller"); assert(thread == xthread, "must be"); Label done; @@ -130,7 +128,12 @@ // Do we need to load the previous value? if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + if (UseCompressedOops) { + __ lwu(pre_val, Address(obj, 0)); + __ decode_heap_oop(pre_val); + } else { + __ ld(pre_val, Address(obj, 0)); + } } // Is the previous value null? @@ -151,33 +154,17 @@ __ sd(pre_val, Address(tmp1, 0)); __ j(done); + // Slow-path call. __ bind(runtime); - // save the live input values - RegSet saved = RegSet::of(pre_val); - if (tosca_live) saved += RegSet::of(x10); - if (obj != noreg) saved += RegSet::of(obj); - - __ push_reg(saved, sp); - - // Calling the runtime using the regular call_VM_leaf mechanism generates - // code (generated by InterpreterMacroAssember::call_VM_leaf_base) - // that checks that the *(rfp+frame::interpreter_frame_last_sp) is null. - // - // If we care generating the pre-barrier without a frame (e.g. in the - // intrinsified Reference.get() routine) then ebp might be pointing to - // the caller frame and so this check will most likely fail at runtime. - // - // Expanding the call directly bypasses the generation of the check. - // So when we do not have have a full interpreter frame on the stack - // expand_call should be passed true. - if (expand_call) { - assert(pre_val != c_rarg1, "smashed arg"); - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); - } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); + __ enter(); + __ push_call_clobbered_registers(); + if (c_rarg0 != pre_val) { + __ mv(c_rarg0, pre_val); } - - __ pop_reg(saved, sp); + // Calling with super_call_VM_leaf with c_rarg0 bypasses interpreter checks and avoids any moves. + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), c_rarg0); + __ pop_call_clobbered_registers(); + __ leave(); __ bind(done); } @@ -244,7 +231,6 @@ bool is_narrow = UseCompressedOops && !is_native; Label heap_stable, not_cset; - __ enter(); Address gc_state(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); __ lbu(t1, gc_state); @@ -284,6 +270,8 @@ __ beqz(t0, not_cset); } + // Slow-path call + __ enter(); __ push_call_clobbered_registers(); address target = nullptr; if (is_strong) { @@ -303,16 +291,18 @@ assert(!is_narrow, "phantom access cannot be narrow"); target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom); } - __ rt_call(target); + // Calling with super_call_VM_leaf with c_rarg0/1 bypasses interpreter checks and avoids any moves. + __ super_call_VM_leaf(target, c_rarg0, c_rarg1); __ mv(t0, x10); __ pop_call_clobbered_registers(); __ mv(x10, t0); + __ leave(); + __ bind(not_cset); __ mv(result_dst, x10); __ pop_reg(saved_regs, sp); __ bind(heap_stable); - __ leave(); } // @@ -374,23 +364,17 @@ // 3: apply keep-alive barrier if needed if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { - __ enter(); - __ push_call_clobbered_registers(); - satb_write_barrier_pre(masm /* masm */, - noreg /* obj */, - dst /* pre_val */, - xthread /* thread */, - tmp1 /* tmp1 */, - tmp2 /* tmp2 */, - true /* tosca_live */, - true /* expand_call */); - __ pop_call_clobbered_registers(); - __ leave(); + satb_barrier(masm /* masm */, + noreg /* obj */, + dst /* pre_val */, + xthread /* thread */, + tmp1 /* tmp1 */, + tmp2 /* tmp2 */); } } -void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj) { - assert(ShenandoahCardBarrier, "Did you mean to enable ShenandoahCardBarrier?"); +void ShenandoahBarrierSetAssembler::card_barrier(MacroAssembler* masm, Register obj) { + assert(ShenandoahCardBarrier, "Should have been checked by caller"); __ srli(obj, obj, CardTable::card_shift()); @@ -413,13 +397,13 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { - bool on_oop = is_reference_type(type); - if (!on_oop) { + // 1: non-reference types require no barriers + if (!is_reference_type(type)) { BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); return; } - // flatten object address if needed + // Flatten object address right away for simplicity: likely needed by barriers if (dst.offset() == 0) { if (dst.base() != tmp3) { __ mv(tmp3, dst.base()); @@ -428,20 +412,23 @@ __ la(tmp3, dst); } - shenandoah_write_barrier_pre(masm, - tmp3 /* obj */, - tmp2 /* pre_val */, - xthread /* thread */, - tmp1 /* tmp */, - val != noreg /* tosca_live */, - false /* expand_call */); + // 2: pre-barrier: SATB needs the previous value + if (ShenandoahBarrierSet::need_satb_barrier(decorators, type)) { + satb_barrier(masm, + tmp3 /* obj */, + tmp2 /* pre_val */, + xthread /* thread */, + tmp1 /* tmp */, + t0 /* tmp2 */); + } + // Store! BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg); - bool in_heap = (decorators & IN_HEAP) != 0; - bool needs_post_barrier = (val != noreg) && in_heap && ShenandoahCardBarrier; - if (needs_post_barrier) { - store_check(masm, tmp3); + // 3: post-barrier: card barrier needs store address + bool storing_non_null = (val != noreg); + if (ShenandoahBarrierSet::need_card_barrier(decorators, type) && storing_non_null) { + card_barrier(masm, tmp3); } } @@ -702,7 +689,7 @@ __ bind(runtime); __ push_call_clobbered_registers(); __ load_parameter(0, pre_val); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val); __ pop_call_clobbered_registers(); __ bind(done); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -41,23 +41,14 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: - void satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp1, - Register tmp2, - bool tosca_live, - bool expand_call); - void shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp, - bool tosca_live, - bool expand_call); + void satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2); - void store_check(MacroAssembler* masm, Register obj); + void card_barrier(MacroAssembler* masm, Register obj); void resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp = noreg); void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1784,12 +1784,12 @@ mv(tmp5, 0xff); if (MaxVectorSize == 16) { - vsetivli(zr, N, Assembler::e32, Assembler::m4, Assembler::ma, Assembler::ta); + vsetivli(zr, N, Assembler::e32, Assembler::m4, Assembler::mu, Assembler::tu); } else if (MaxVectorSize == 32) { - vsetivli(zr, N, Assembler::e32, Assembler::m2, Assembler::ma, Assembler::ta); + vsetivli(zr, N, Assembler::e32, Assembler::m2, Assembler::mu, Assembler::tu); } else { assert(MaxVectorSize > 32, "sanity"); - vsetivli(zr, N, Assembler::e32, Assembler::m1, Assembler::ma, Assembler::ta); + vsetivli(zr, N, Assembler::e32, Assembler::m1, Assembler::mu, Assembler::tu); } vmv_v_x(vcrc, zr); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/riscv/matcher_riscv.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/matcher_riscv.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/riscv/matcher_riscv.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/matcher_riscv.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -129,11 +129,6 @@ return UseRVV; } - // Does target support predicated operation emulation. - static bool supports_vector_predicate_op_emulation(int vopc, int vlen, BasicType bt) { - return false; - } - // Does the CPU supports vector variable rotate instructions? static bool supports_vector_variable_rotates(void) { return UseZvbb; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/riscv/riscv.ad openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/riscv.ad --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/riscv/riscv.ad 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/riscv/riscv.ad 2026-10-19 12:10:20.000000000 +0000 @@ -1608,6 +1608,27 @@ int src_offset = ra_->reg2offset(src_lo); int dst_offset = ra_->reg2offset(dst_lo); + // Stack-to-stack copies use t0 for the value. Bail out if a destination + // address also needs t0 to materialize an offset outside the 12-bit range. + if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { + int last_dst_offset = dst_offset; + if (bottom_type()->isa_vectmask()) { + int vmask_size_in_bytes = Matcher::scalable_predicate_reg_slots() * 32 / 8; + last_dst_offset += vmask_size_in_bytes - 4; + } else if (ideal_reg() == Op_VecA) { + int vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); + last_dst_offset += vector_reg_size_in_bytes - 8; + } + + if (masm != nullptr && !Assembler::is_simm12(last_dst_offset)) { + // size() emits into a scratch buffer where recording a failure is not allowed. + if (!C->output()->in_scratch_emit_size()) { + C->record_method_not_compilable("unsupported large stack-to-stack spill copy"); + } + return 0; + } + } + if (bottom_type()->isa_vect() != nullptr) { uint ireg = ideal_reg(); if (ireg == Op_VecA && masm) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/s390/matcher_s390.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/s390/matcher_s390.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/s390/matcher_s390.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/s390/matcher_s390.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -126,11 +126,6 @@ return false; } - // Does target support predicated operation emulation. - static bool supports_vector_predicate_op_emulation(int vopc, int vlen, BasicType bt) { - return false; - } - // Does the CPU supports vector variable rotate instructions? static constexpr bool supports_vector_variable_rotates(void) { return false; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/assembler_x86.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/assembler_x86.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/assembler_x86.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/assembler_x86.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -2225,6 +2225,44 @@ emit_int16(0x2C, (0xC0 | encode)); } +void Assembler::evcvttss2sisl(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttss2sisl(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + +void Assembler::evcvttss2sisq(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttss2sisq(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::cvttpd2dq(XMMRegister dst, XMMRegister src) { int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_128bit; InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2310,6 +2348,25 @@ emit_int16(0x5B, (0xC0 | encode)); } +void Assembler::evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttps2dqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) { assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2317,6 +2374,25 @@ emit_int16((unsigned char)0xE6, (0xC0 | encode)); } +void Assembler::evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttpd2dqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len) { assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2332,6 +2408,25 @@ emit_int16(0x7A, (0xC0 | encode)); } +void Assembler::evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttps2qqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_HV, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2356,6 +2451,25 @@ emit_int16(0x7A, (0xC0 | encode)); } +void Assembler::evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttpd2qqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::evcvtqq2pd(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -8222,6 +8336,14 @@ emit_int16(0x5F, (0xC0 | encode)); } +void Assembler::eminmaxsh(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x53, (0xC0 | encode), imm8); +} + void Assembler::vminsh(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); @@ -8736,12 +8858,68 @@ emit_int16(0x5F, (0xC0 | encode)); } +void Assembler::evminmaxps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x52, (0xC0 | encode), imm8); +} + +void Assembler::evminmaxps(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x52); + emit_operand(dst, src, 0); + emit_int8(imm8); +} + void Assembler::maxpd(XMMRegister dst, XMMRegister src) { InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int16(0x5F, (0xC0 | encode)); } +void Assembler::evminmaxpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x52, (0xC0 | encode), imm8); +} + +void Assembler::evminmaxpd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x52); + emit_operand(dst, src, 0); + emit_int8(imm8); +} + void Assembler::vmaxpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(vector_len >= AVX_512bit ? VM_Version::supports_evex() : VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -13130,6 +13308,14 @@ emit_int16(0x5D, (0xC0 | encode)); } +void Assembler::eminmaxss(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x53, (0xC0 | encode), imm8); +} + void Assembler::vminsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); @@ -13138,6 +13324,14 @@ emit_int16(0x5D, (0xC0 | encode)); } +void Assembler::eminmaxsd(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x53, (0xC0 | encode), imm8); +} + void Assembler::vcmppd(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop, int vector_len) { assert(VM_Version::supports_avx(), ""); assert(vector_len <= AVX_256bit, ""); @@ -14908,6 +15102,44 @@ emit_operand(dst, src, 0); } +void Assembler::evcvttsd2sisl(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttsd2sisl(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + +void Assembler::evcvttsd2sisq(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttsd2sisq(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::cvttsd2siq(Register dst, XMMRegister src) { InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); @@ -16506,6 +16738,34 @@ emit_operand(dst, src, 0); } +void Assembler::evminmaxph(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x52, (0xC0 | encode), imm8); +} + +void Assembler::evminmaxph(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x52); + emit_operand(dst, src, 0); + emit_int8(imm8); +} + void Assembler::evmaxph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/assembler_x86.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/assembler_x86.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/assembler_x86.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/assembler_x86.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -441,6 +441,17 @@ // See fxsave and xsave(EVEX enabled) documentation for layout const int FPUStateSizeInWords = 2688 / wordSize; + +// AVX10 new minmax instruction control mask encoding. +// +// imm8[4] = 0 (please refer to Table 11.1 of section 11.2 of AVX10 manual[1] for details) +// imm8[3:2] (sign control) = 01 (select sign, please refer to Table 11.5 of section 11.2 of AVX10 manual[1] for details) +// imm8[1:0] = 00 (min) / 01 (max) +// +// [1] https://www.intel.com/content/www/us/en/content-details/856721/intel-advanced-vector-extensions-10-2-intel-avx10-2-architecture-specification.html?wapkw=AVX10 +const int AVX10_MINMAX_MAX_COMPARE_SIGN = 0x5; +const int AVX10_MINMAX_MIN_COMPARE_SIGN = 0x4; + // The Intel x86/Amd64 Assembler: Pure assembler doing NO optimizations on the instruction // level (e.g. mov rax, 0 is not translated into xor rax, rax!); i.e., what you write // is what you get. The Assembler is generating code into a CodeBuffer. @@ -1305,11 +1316,19 @@ void cvttsd2sil(Register dst, XMMRegister src); void cvttsd2siq(Register dst, Address src); void cvttsd2siq(Register dst, XMMRegister src); + void evcvttsd2sisl(Register dst, XMMRegister src); + void evcvttsd2sisl(Register dst, Address src); + void evcvttsd2sisq(Register dst, XMMRegister src); + void evcvttsd2sisq(Register dst, Address src); // Convert with Truncation Scalar Single-Precision Floating-Point Value to Doubleword Integer void cvttss2sil(Register dst, XMMRegister src); void cvttss2siq(Register dst, XMMRegister src); void cvtss2sil(Register dst, XMMRegister src); + void evcvttss2sisl(Register dst, XMMRegister src); + void evcvttss2sisl(Register dst, Address src); + void evcvttss2sisq(Register dst, XMMRegister src); + void evcvttss2sisq(Register dst, Address src); // Convert vector double to int void cvttpd2dq(XMMRegister dst, XMMRegister src); @@ -1321,7 +1340,11 @@ // Convert vector float to int/long void vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len); void vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2dqs(XMMRegister dst, Address src, int vector_len); void evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2qqs(XMMRegister dst, Address src, int vector_len); // Convert vector long to vector FP void evcvtqq2ps(XMMRegister dst, XMMRegister src, int vector_len); @@ -1330,9 +1353,13 @@ // Convert vector double to long void evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len); void evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2qqs(XMMRegister dst, Address src, int vector_len); // Convert vector double to int void vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2dqs(XMMRegister dst, Address src, int vector_len); // Evex casts with truncation void evpmovwb(XMMRegister dst, XMMRegister src, int vector_len); @@ -2752,6 +2779,17 @@ void minpd(XMMRegister dst, XMMRegister src); void vminpd(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); + // AVX10.2 floating point minmax instructions + void eminmaxsh(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8); + void eminmaxss(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8); + void eminmaxsd(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8); + void evminmaxph(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len); + void evminmaxph(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len); + void evminmaxps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len); + void evminmaxps(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len); + void evminmaxpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len); + void evminmaxpd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len); + // Maximum of packed integers void pmaxsb(XMMRegister dst, XMMRegister src); void vpmaxsb(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1238,6 +1238,21 @@ } } +void C2_MacroAssembler::vminmax_fp(int opc, BasicType elem_bt, XMMRegister dst, KRegister mask, + XMMRegister src1, XMMRegister src2, int vlen_enc) { + assert(opc == Op_MinV || opc == Op_MinReductionV || + opc == Op_MaxV || opc == Op_MaxReductionV, "sanity"); + + int imm8 = (opc == Op_MinV || opc == Op_MinReductionV) ? AVX10_MINMAX_MIN_COMPARE_SIGN + : AVX10_MINMAX_MAX_COMPARE_SIGN; + if (elem_bt == T_FLOAT) { + evminmaxps(dst, mask, src1, src2, true, imm8, vlen_enc); + } else { + assert(elem_bt == T_DOUBLE, ""); + evminmaxpd(dst, mask, src1, src2, true, imm8, vlen_enc); + } +} + // Float/Double signum void C2_MacroAssembler::signum_fp(int opcode, XMMRegister dst, XMMRegister zero, XMMRegister one) { assert(opcode == Op_SignumF || opcode == Op_SignumD, "sanity"); @@ -1591,128 +1606,6 @@ } } -void C2_MacroAssembler::vgather8b_masked_offset(BasicType elem_bt, - XMMRegister dst, Register base, - Register idx_base, - Register offset, Register mask, - Register mask_idx, Register rtmp, - int vlen_enc) { - vpxor(dst, dst, dst, vlen_enc); - if (elem_bt == T_SHORT) { - for (int i = 0; i < 4; i++) { - // dst[i] = mask[i] ? src[offset + idx_base[i]] : 0 - Label skip_load; - btq(mask, mask_idx); - jccb(Assembler::carryClear, skip_load); - movl(rtmp, Address(idx_base, i * 4)); - if (offset != noreg) { - addl(rtmp, offset); - } - pinsrw(dst, Address(base, rtmp, Address::times_2), i); - bind(skip_load); - incq(mask_idx); - } - } else { - assert(elem_bt == T_BYTE, ""); - for (int i = 0; i < 8; i++) { - // dst[i] = mask[i] ? src[offset + idx_base[i]] : 0 - Label skip_load; - btq(mask, mask_idx); - jccb(Assembler::carryClear, skip_load); - movl(rtmp, Address(idx_base, i * 4)); - if (offset != noreg) { - addl(rtmp, offset); - } - pinsrb(dst, Address(base, rtmp), i); - bind(skip_load); - incq(mask_idx); - } - } -} - -void C2_MacroAssembler::vgather8b_offset(BasicType elem_bt, XMMRegister dst, - Register base, Register idx_base, - Register offset, Register rtmp, - int vlen_enc) { - vpxor(dst, dst, dst, vlen_enc); - if (elem_bt == T_SHORT) { - for (int i = 0; i < 4; i++) { - // dst[i] = src[offset + idx_base[i]] - movl(rtmp, Address(idx_base, i * 4)); - if (offset != noreg) { - addl(rtmp, offset); - } - pinsrw(dst, Address(base, rtmp, Address::times_2), i); - } - } else { - assert(elem_bt == T_BYTE, ""); - for (int i = 0; i < 8; i++) { - // dst[i] = src[offset + idx_base[i]] - movl(rtmp, Address(idx_base, i * 4)); - if (offset != noreg) { - addl(rtmp, offset); - } - pinsrb(dst, Address(base, rtmp), i); - } - } -} - -/* - * Gather using hybrid algorithm, first partially unroll scalar loop - * to accumulate values from gather indices into a quad-word(64bit) slice. - * A slice may hold 8 bytes or 4 short values. This is followed by a vector - * permutation to place the slice into appropriate vector lane - * locations in destination vector. Following pseudo code describes the - * algorithm in detail: - * - * DST_VEC = ZERO_VEC - * PERM_INDEX = {0, 1, 2, 3, 4, 5, 6, 7, 8..} - * TWO_VEC = {2, 2, 2, 2, 2, 2, 2, 2, 2..} - * FOREACH_ITER: - * TMP_VEC_64 = PICK_SUB_WORDS_FROM_GATHER_INDICES - * TEMP_PERM_VEC = PERMUTE TMP_VEC_64 PERM_INDEX - * DST_VEC = DST_VEC OR TEMP_PERM_VEC - * PERM_INDEX = PERM_INDEX - TWO_VEC - * - * With each iteration, doubleword permute indices (0,1) corresponding - * to gathered quadword gets right shifted by two lane positions. - * - */ -void C2_MacroAssembler::vgather_subword(BasicType elem_ty, XMMRegister dst, - Register base, Register idx_base, - Register offset, Register mask, - XMMRegister xtmp1, XMMRegister xtmp2, - XMMRegister temp_dst, Register rtmp, - Register mask_idx, Register length, - int vector_len, int vlen_enc) { - Label GATHER8_LOOP; - assert(is_subword_type(elem_ty), ""); - movl(length, vector_len); - vpxor(xtmp1, xtmp1, xtmp1, vlen_enc); // xtmp1 = {0, ...} - vpxor(dst, dst, dst, vlen_enc); // dst = {0, ...} - vallones(xtmp2, vlen_enc); - vpsubd(xtmp2, xtmp1, xtmp2, vlen_enc); - vpslld(xtmp2, xtmp2, 1, vlen_enc); // xtmp2 = {2, 2, ...} - load_iota_indices(xtmp1, vector_len * type2aelembytes(elem_ty), T_INT); // xtmp1 = {0, 1, 2, ...} - - bind(GATHER8_LOOP); - // TMP_VEC_64(temp_dst) = PICK_SUB_WORDS_FROM_GATHER_INDICES - if (mask == noreg) { - vgather8b_offset(elem_ty, temp_dst, base, idx_base, offset, rtmp, vlen_enc); - } else { - vgather8b_masked_offset(elem_ty, temp_dst, base, idx_base, offset, mask, mask_idx, rtmp, vlen_enc); - } - // TEMP_PERM_VEC(temp_dst) = PERMUTE TMP_VEC_64(temp_dst) PERM_INDEX(xtmp1) - vpermd(temp_dst, xtmp1, temp_dst, vlen_enc == Assembler::AVX_512bit ? vlen_enc : Assembler::AVX_256bit); - // PERM_INDEX(xtmp1) = PERM_INDEX(xtmp1) - TWO_VEC(xtmp2) - vpsubd(xtmp1, xtmp1, xtmp2, vlen_enc); - // DST_VEC = DST_VEC OR TEMP_PERM_VEC - vpor(dst, dst, temp_dst, vlen_enc); - addptr(idx_base, 32 >> (type2aelembytes(elem_ty) - 1)); - subl(length, 8 >> (type2aelembytes(elem_ty) - 1)); - jcc(Assembler::notEqual, GATHER8_LOOP); -} - void C2_MacroAssembler::vgather(BasicType typ, XMMRegister dst, Register base, XMMRegister idx, XMMRegister mask, int vector_len) { switch(typ) { case T_INT: @@ -2545,12 +2438,21 @@ } else { // i = [0,1] vpermilps(wtmp, wsrc, permconst[i], vlen_enc); } - vminmax_fp(opcode, T_FLOAT, wdst, wtmp, wsrc, tmp, atmp, btmp, vlen_enc); + + if (VM_Version::supports_avx10_2()) { + vminmax_fp(opcode, T_FLOAT, wdst, k0, wtmp, wsrc, vlen_enc); + } else { + vminmax_fp(opcode, T_FLOAT, wdst, wtmp, wsrc, tmp, atmp, btmp, vlen_enc); + } wsrc = wdst; vlen_enc = Assembler::AVX_128bit; } if (is_dst_valid) { - vminmax_fp(opcode, T_FLOAT, dst, wdst, dst, tmp, atmp, btmp, Assembler::AVX_128bit); + if (VM_Version::supports_avx10_2()) { + vminmax_fp(opcode, T_FLOAT, dst, k0, wdst, dst, Assembler::AVX_128bit); + } else { + vminmax_fp(opcode, T_FLOAT, dst, wdst, dst, tmp, atmp, btmp, Assembler::AVX_128bit); + } } } @@ -2576,12 +2478,23 @@ assert(i == 0, "%d", i); vpermilpd(wtmp, wsrc, 1, vlen_enc); } - vminmax_fp(opcode, T_DOUBLE, wdst, wtmp, wsrc, tmp, atmp, btmp, vlen_enc); + + if (VM_Version::supports_avx10_2()) { + vminmax_fp(opcode, T_DOUBLE, wdst, k0, wtmp, wsrc, vlen_enc); + } else { + vminmax_fp(opcode, T_DOUBLE, wdst, wtmp, wsrc, tmp, atmp, btmp, vlen_enc); + } + wsrc = wdst; vlen_enc = Assembler::AVX_128bit; } + if (is_dst_valid) { - vminmax_fp(opcode, T_DOUBLE, dst, wdst, dst, tmp, atmp, btmp, Assembler::AVX_128bit); + if (VM_Version::supports_avx10_2()) { + vminmax_fp(opcode, T_DOUBLE, dst, k0, wdst, dst, Assembler::AVX_128bit); + } else { + vminmax_fp(opcode, T_DOUBLE, dst, wdst, dst, tmp, atmp, btmp, Assembler::AVX_128bit); + } } } @@ -5244,12 +5157,12 @@ } vpackuswb(dst, dst, zero, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector cast int to subword: %s", type2name(to_elem_bt)); } } /* - * Algorithm for vector D2L and F2I conversions:- + * Algorithm for vector D2L and F2I conversions (AVX 10.2 unsupported):- * a) Perform vector D2L/F2I cast. * b) Choose fast path if none of the result vector lane contains 0x80000000 value. * It signifies that source value could be any of the special floating point @@ -5287,7 +5200,7 @@ case T_BYTE: evpmovdb(dst, dst, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector castF2X EVEX: %s", type2name(to_elem_bt)); } } @@ -5334,7 +5247,7 @@ evpmovsqd(dst, dst, vec_enc); evpmovdb(dst, dst, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector castD2X AVX512DQ EVEX: %s", type2name(to_elem_bt)); } } else { assert(type2aelembytes(to_elem_bt) <= 4, ""); @@ -5349,11 +5262,91 @@ case T_BYTE: evpmovdb(dst, dst, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector castD2X EVEX: %s", type2name(to_elem_bt)); } } } +void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttps2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttps2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttps2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttps2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (reg src): %s", type2name(to_elem_bt)); + } +} + +void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttps2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttps2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttps2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttps2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (mem src): %s", type2name(to_elem_bt)); + } +} + +void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttpd2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttpd2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (reg src): %s", type2name(to_elem_bt)); + } +} + +void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttpd2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttpd2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (mem src): %s", type2name(to_elem_bt)); + } +} + void C2_MacroAssembler::vector_round_double_evex(XMMRegister dst, XMMRegister src, AddressLiteral double_sign_flip, AddressLiteral new_mxcsr, int vec_enc, Register tmp, XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp1, KRegister ktmp2) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -72,6 +72,9 @@ XMMRegister tmp, XMMRegister atmp, XMMRegister btmp, int vlen_enc); + void vminmax_fp(int opc, BasicType elem_bt, XMMRegister dst, KRegister mask, + XMMRegister src1, XMMRegister src2, int vlen_enc); + void vpuminmaxq(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc); void evminmax_fp(int opcode, BasicType elem_bt, @@ -349,6 +352,13 @@ XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5, AddressLiteral float_sign_flip, Register rscratch, int vec_enc); + void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc); + + void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc); + + void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc); + + void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc); void vector_cast_double_to_int_special_cases_avx(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5, Register rscratch, @@ -492,16 +502,6 @@ void efp16sh(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2); - void vgather_subword(BasicType elem_ty, XMMRegister dst, Register base, Register idx_base, Register offset, - Register mask, XMMRegister xtmp1, XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, - Register midx, Register length, int vector_len, int vlen_enc); - - void vgather8b_masked_offset(BasicType elem_bt, XMMRegister dst, Register base, Register idx_base, - Register offset, Register mask, Register midx, Register rtmp, int vlen_enc); - - void vgather8b_offset(BasicType elem_bt, XMMRegister dst, Register base, Register idx_base, - Register offset, Register rtmp, int vlen_enc); - void vector_saturating_op(int opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, bool is_unsigned, int vlen_enc); void vector_saturating_op(int opc, BasicType elem_bt, XMMRegister dst, XMMRegister src1, Address src2, bool is_unsigned, int vlen_enc); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -44,47 +44,6 @@ #define __ masm-> -static void save_machine_state(MacroAssembler* masm, bool handle_gpr, bool handle_fp) { - if (handle_gpr) { - __ push_IU_state(); - } - - if (handle_fp) { - // Some paths can be reached from the c2i adapter with live fp arguments in registers. - assert(Argument::n_float_register_parameters_j == 8, "8 fp registers to save at java call"); - - const int xmm_size = wordSize * 2; - __ subptr(rsp, xmm_size * 8); - __ movdbl(Address(rsp, xmm_size * 0), xmm0); - __ movdbl(Address(rsp, xmm_size * 1), xmm1); - __ movdbl(Address(rsp, xmm_size * 2), xmm2); - __ movdbl(Address(rsp, xmm_size * 3), xmm3); - __ movdbl(Address(rsp, xmm_size * 4), xmm4); - __ movdbl(Address(rsp, xmm_size * 5), xmm5); - __ movdbl(Address(rsp, xmm_size * 6), xmm6); - __ movdbl(Address(rsp, xmm_size * 7), xmm7); - } -} - -static void restore_machine_state(MacroAssembler* masm, bool handle_gpr, bool handle_fp) { - if (handle_fp) { - const int xmm_size = wordSize * 2; - __ movdbl(xmm0, Address(rsp, xmm_size * 0)); - __ movdbl(xmm1, Address(rsp, xmm_size * 1)); - __ movdbl(xmm2, Address(rsp, xmm_size * 2)); - __ movdbl(xmm3, Address(rsp, xmm_size * 3)); - __ movdbl(xmm4, Address(rsp, xmm_size * 4)); - __ movdbl(xmm5, Address(rsp, xmm_size * 5)); - __ movdbl(xmm6, Address(rsp, xmm_size * 6)); - __ movdbl(xmm7, Address(rsp, xmm_size * 7)); - __ addptr(rsp, xmm_size * 8); - } - - if (handle_gpr) { - __ pop_IU_state(); - } -} - void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count) { @@ -129,20 +88,27 @@ __ testb(gc_state, flags); __ jcc(Assembler::zero, L_done); - save_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ false); - - assert(src == rdi, "expected"); - assert(dst == rsi, "expected"); - assert(count == rdx, "expected"); + __ push_call_clobbered_registers(/* save_fpu = */ false); + // If arguments are not in proper places, shuffle them. + // Doing this via the stack is the most straight-forward way to avoid + // accidentally smashing any register. + if (c_rarg0 != src || c_rarg1 != dst || c_rarg2 != count) { + __ push(src); + __ push(dst); + __ push(count); + __ pop(c_rarg2); + __ pop(c_rarg1); + __ pop(c_rarg0); + } + address target = nullptr; if (UseCompressedOops) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop), - src, dst, count); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop), - src, dst, count); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop); } + __ call_VM_leaf(target, 3); - restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ false); + __ pop_call_clobbered_registers(/* restore_fpu = */ false); __ bind(L_done); } @@ -174,28 +140,11 @@ } } -void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register tmp, - bool tosca_live, - bool expand_call) { - - if (ShenandoahSATBBarrier) { - satb_write_barrier_pre(masm, obj, pre_val, tmp, tosca_live, expand_call); - } -} - -void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register tmp, - bool tosca_live, - bool expand_call) { - // If expand_call is true then we expand the call_VM_leaf macro - // directly to skip generating the check by - // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. - +void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register tmp) { + assert(ShenandoahSATBBarrier, "Should be checked by caller"); const Register thread = r15_thread; Label done; @@ -217,7 +166,12 @@ // Do we need to load the previous value? if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, AS_RAW); + if (UseCompressedOops) { + __ movl(pre_val, Address(obj, 0)); + __ decode_heap_oop(pre_val); + } else { + __ movq(pre_val, Address(obj, 0)); + } } // Is the previous value null? @@ -241,54 +195,22 @@ __ jmp(done); __ bind(runtime); - // save the live input values - if(tosca_live) __ push(rax); - - if (obj != noreg && obj != rax) - __ push(obj); - if (pre_val != rax) - __ push(pre_val); + // Slow-path call. + // Some paths can be reached from the c2i adapter with live fp arguments in registers. + __ enter(); + __ push_call_clobbered_registers(/* save_fpu = */ true); - // Calling the runtime using the regular call_VM_leaf mechanism generates - // code (generated by InterpreterMacroAssember::call_VM_leaf_base) - // that checks that the *(ebp+frame::interpreter_frame_last_sp) == nullptr. - // - // If we care generating the pre-barrier without a frame (e.g. in the - // intrinsified Reference.get() routine) then ebp might be pointing to - // the caller frame and so this check will most likely fail at runtime. - // - // Expanding the call directly bypasses the generation of the check. - // So when we do not have have a full interpreter frame on the stack - // expand_call should be passed true. - - // We move pre_val into c_rarg0 early, in order to avoid smashing it, should - // pre_val be c_rarg1 (where the call prologue would copy thread argument). - // Note: this should not accidentally smash thread, because thread is always r15. assert(thread != c_rarg0, "smashed arg"); if (c_rarg0 != pre_val) { __ mov(c_rarg0, pre_val); } - if (expand_call) { - assert(pre_val != c_rarg1, "smashed arg"); - if (c_rarg1 != thread) { - __ mov(c_rarg1, thread); - } - // Already moved pre_val into c_rarg0 above - __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), 2); - } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), c_rarg0, thread); - } - - // save the live input values - if (pre_val != rax) - __ pop(pre_val); + // Calling with super_call_VM_leaf with c_rarg0 bypasses interpreter checks and avoids any moves. + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), c_rarg0); - if (obj != noreg && obj != rax) - __ pop(obj); - - if(tosca_live) __ pop(rax); + __ pop_call_clobbered_registers(/* restore_fpu = */ true); + __ leave(); __ bind(done); } @@ -349,111 +271,51 @@ __ jcc(Assembler::zero, not_cset); } - save_machine_state(masm, /* handle_gpr = */ false, /* handle_fp = */ true); - - // The rest is saved with the optimized path - - uint num_saved_regs = 4 + (dst != rax ? 1 : 0) + 4 + (UseAPX ? 16 : 0); - __ subptr(rsp, num_saved_regs * wordSize); - uint slot = num_saved_regs; + // Slow-path call. + // Save registers that can be clobbered by call. + // Some paths can be reached from the c2i adapter with live fp arguments in registers. + __ enter(); if (dst != rax) { - __ movptr(Address(rsp, (--slot) * wordSize), rax); + __ push(rax); } - __ movptr(Address(rsp, (--slot) * wordSize), rcx); - __ movptr(Address(rsp, (--slot) * wordSize), rdx); - __ movptr(Address(rsp, (--slot) * wordSize), rdi); - __ movptr(Address(rsp, (--slot) * wordSize), rsi); - __ movptr(Address(rsp, (--slot) * wordSize), r8); - __ movptr(Address(rsp, (--slot) * wordSize), r9); - __ movptr(Address(rsp, (--slot) * wordSize), r10); - __ movptr(Address(rsp, (--slot) * wordSize), r11); - // Save APX extended registers r16–r31 if enabled - if (UseAPX) { - __ movptr(Address(rsp, (--slot) * wordSize), r16); - __ movptr(Address(rsp, (--slot) * wordSize), r17); - __ movptr(Address(rsp, (--slot) * wordSize), r18); - __ movptr(Address(rsp, (--slot) * wordSize), r19); - __ movptr(Address(rsp, (--slot) * wordSize), r20); - __ movptr(Address(rsp, (--slot) * wordSize), r21); - __ movptr(Address(rsp, (--slot) * wordSize), r22); - __ movptr(Address(rsp, (--slot) * wordSize), r23); - __ movptr(Address(rsp, (--slot) * wordSize), r24); - __ movptr(Address(rsp, (--slot) * wordSize), r25); - __ movptr(Address(rsp, (--slot) * wordSize), r26); - __ movptr(Address(rsp, (--slot) * wordSize), r27); - __ movptr(Address(rsp, (--slot) * wordSize), r28); - __ movptr(Address(rsp, (--slot) * wordSize), r29); - __ movptr(Address(rsp, (--slot) * wordSize), r30); - __ movptr(Address(rsp, (--slot) * wordSize), r31); - } - // r12-r15 are callee saved in all calling conventions - assert(slot == 0, "must use all slots"); + __ push_call_clobbered_registers_except(rax, /* save_fpu = */ true); // Shuffle registers such that dst is in c_rarg0 and addr in c_rarg1. - Register arg0 = c_rarg0, arg1 = c_rarg1; - if (dst == arg1) { - __ lea(arg0, src); - __ xchgptr(arg1, arg0); + if (dst == c_rarg1) { + __ lea(c_rarg0, src); + __ xchgptr(c_rarg1, c_rarg0); } else { - __ lea(arg1, src); - __ movptr(arg0, dst); + __ lea(c_rarg1, src); + __ movptr(c_rarg0, dst); } + address target = nullptr; if (is_strong) { if (is_narrow) { - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow), arg0, arg1); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow); } else { - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong), arg0, arg1); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); } } else if (is_weak) { if (is_narrow) { - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow), arg0, arg1); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow); } else { - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak), arg0, arg1); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak); } } else { assert(is_phantom, "only remaining strength"); assert(!is_narrow, "phantom access cannot be narrow"); - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom), arg0, arg1); + target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom); } - // Restore APX extended registers r31–r16 if previously saved - if (UseAPX) { - __ movptr(r31, Address(rsp, (slot++) * wordSize)); - __ movptr(r30, Address(rsp, (slot++) * wordSize)); - __ movptr(r29, Address(rsp, (slot++) * wordSize)); - __ movptr(r28, Address(rsp, (slot++) * wordSize)); - __ movptr(r27, Address(rsp, (slot++) * wordSize)); - __ movptr(r26, Address(rsp, (slot++) * wordSize)); - __ movptr(r25, Address(rsp, (slot++) * wordSize)); - __ movptr(r24, Address(rsp, (slot++) * wordSize)); - __ movptr(r23, Address(rsp, (slot++) * wordSize)); - __ movptr(r22, Address(rsp, (slot++) * wordSize)); - __ movptr(r21, Address(rsp, (slot++) * wordSize)); - __ movptr(r20, Address(rsp, (slot++) * wordSize)); - __ movptr(r19, Address(rsp, (slot++) * wordSize)); - __ movptr(r18, Address(rsp, (slot++) * wordSize)); - __ movptr(r17, Address(rsp, (slot++) * wordSize)); - __ movptr(r16, Address(rsp, (slot++) * wordSize)); - } - __ movptr(r11, Address(rsp, (slot++) * wordSize)); - __ movptr(r10, Address(rsp, (slot++) * wordSize)); - __ movptr(r9, Address(rsp, (slot++) * wordSize)); - __ movptr(r8, Address(rsp, (slot++) * wordSize)); - __ movptr(rsi, Address(rsp, (slot++) * wordSize)); - __ movptr(rdi, Address(rsp, (slot++) * wordSize)); - __ movptr(rdx, Address(rsp, (slot++) * wordSize)); - __ movptr(rcx, Address(rsp, (slot++) * wordSize)); - + // Calling with super_call_VM_leaf with c_rarg0/1 bypasses interpreter checks and avoids any moves. + __ super_call_VM_leaf(target, c_rarg0, c_rarg1); + __ pop_call_clobbered_registers_except(rax, /* restore_fpu = */ true); if (dst != rax) { __ movptr(dst, rax); - __ movptr(rax, Address(rsp, (slot++) * wordSize)); + __ pop(rax); } - - assert(slot == num_saved_regs, "must use all slots"); - __ addptr(rsp, num_saved_regs * wordSize); - - restore_machine_state(masm, /* handle_gpr = */ false, /* handle_fp = */ true); + __ leave(); __ bind(not_cset); @@ -528,23 +390,14 @@ // 3: apply keep-alive barrier if needed if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { - save_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true); - - assert_different_registers(dst, tmp1, r15_thread); - // Generate the SATB pre-barrier code to log the value of - // the referent field in an SATB buffer. - shenandoah_write_barrier_pre(masm /* masm */, - noreg /* obj */, - dst /* pre_val */, - tmp1 /* tmp */, - true /* tosca_live */, - true /* expand_call */); - - restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true); + satb_barrier(masm /* masm */, + noreg /* obj */, + dst /* pre_val */, + tmp1 /* tmp */); } } -void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj) { +void ShenandoahBarrierSetAssembler::card_barrier(MacroAssembler* masm, Register obj) { assert(ShenandoahCardBarrier, "Should have been checked by caller"); // Does a store check for the oop in register obj. The content of @@ -575,41 +428,37 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { - bool on_oop = is_reference_type(type); - bool in_heap = (decorators & IN_HEAP) != 0; - bool as_normal = (decorators & AS_NORMAL) != 0; - if (on_oop && in_heap) { - bool needs_pre_barrier = as_normal; - - // flatten object address if needed - // We do it regardless of precise because we need the registers - if (dst.index() == noreg && dst.disp() == 0) { - if (dst.base() != tmp1) { - __ movptr(tmp1, dst.base()); - } - } else { - __ lea(tmp1, dst); + // 1: non-reference types require no barriers + if (!is_reference_type(type)) { + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); + return; + } + + // Flatten object address right away for simplicity: likely needed by barriers + assert_different_registers(val, tmp1, tmp2, tmp3, r15_thread); + if (dst.index() == noreg && dst.disp() == 0) { + if (dst.base() != tmp1) { + __ movptr(tmp1, dst.base()); } + } else { + __ lea(tmp1, dst); + } - assert_different_registers(val, tmp1, tmp2, tmp3, r15_thread); + // 2: pre-barrier: SATB needs the previous value + if (ShenandoahBarrierSet::need_satb_barrier(decorators, type)) { + satb_barrier(masm, + tmp1 /* obj */, + tmp2 /* pre_val */, + tmp3 /* tmp */); + } - if (needs_pre_barrier) { - shenandoah_write_barrier_pre(masm /*masm*/, - tmp1 /* obj */, - tmp2 /* pre_val */, - tmp3 /* tmp */, - val != noreg /* tosca_live */, - false /* expand_call */); - } + // Store! + BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); - BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); - if (val != noreg) { - if (ShenandoahCardBarrier) { - store_check(masm, tmp1); - } - } - } else { - BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); + // 3: post-barrier: card barrier needs store address + bool storing_non_null = (val != noreg); + if (ShenandoahBarrierSet::need_card_barrier(decorators, type) && storing_non_null) { + card_barrier(masm, tmp1); } } @@ -946,7 +795,7 @@ // load the pre-value __ load_parameter(0, rcx); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), rcx, thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), rcx); __ restore_live_registers(true); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -41,21 +41,12 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: - void satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register tmp, - bool tosca_live, - bool expand_call); + void satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register tmp); - void shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register tmp, - bool tosca_live, - bool expand_call); - - void store_check(MacroAssembler* masm, Register obj); + void card_barrier(MacroAssembler* masm, Register obj); void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/macroAssembler_x86.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/macroAssembler_x86.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/macroAssembler_x86.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/macroAssembler_x86.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -8866,6 +8866,10 @@ evpminsd(dst, mask, nds, src, merge, vector_len); break; case T_LONG: evpminsq(dst, mask, nds, src, merge, vector_len); break; + case T_FLOAT: + evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break; + case T_DOUBLE: + evminmaxpd(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break; default: fatal("Unexpected type argument %s", type2name(type)); break; } @@ -8881,6 +8885,10 @@ evpmaxsd(dst, mask, nds, src, merge, vector_len); break; case T_LONG: evpmaxsq(dst, mask, nds, src, merge, vector_len); break; + case T_FLOAT: + evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break; + case T_DOUBLE: + evminmaxpd(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break; default: fatal("Unexpected type argument %s", type2name(type)); break; } @@ -8896,6 +8904,10 @@ evpminsd(dst, mask, nds, src, merge, vector_len); break; case T_LONG: evpminsq(dst, mask, nds, src, merge, vector_len); break; + case T_FLOAT: + evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break; + case T_DOUBLE: + evminmaxpd(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break; default: fatal("Unexpected type argument %s", type2name(type)); break; } @@ -8911,6 +8923,10 @@ evpmaxsd(dst, mask, nds, src, merge, vector_len); break; case T_LONG: evpmaxsq(dst, mask, nds, src, merge, vector_len); break; + case T_FLOAT: + evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break; + case T_DOUBLE: + evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break; default: fatal("Unexpected type argument %s", type2name(type)); break; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/matcher_x86.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/matcher_x86.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/matcher_x86.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/matcher_x86.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -116,16 +116,6 @@ return (UseAVX >= 2); } - // Does target support predicated operation emulation. - static bool supports_vector_predicate_op_emulation(int vopc, int vlen, BasicType bt) { - switch(vopc) { - case Op_LoadVectorGatherMasked: - return is_subword_type(bt) && VM_Version::supports_avx2(); - default: - return false; - } - } - // Does the CPU supports vector variable rotate instructions? static constexpr bool supports_vector_variable_rotates(void) { return true; @@ -186,9 +176,6 @@ return 7; case Op_MulVL: return VM_Version::supports_avx512vldq() ? 0 : 6; - case Op_LoadVectorGather: - case Op_LoadVectorGatherMasked: - return is_subword_type(ety) ? 50 : 0; case Op_VectorCastF2X: // fall through case Op_VectorCastD2X: return is_floating_point_type(ety) ? 0 : (is_subword_type(ety) ? 35 : 30); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/methodHandles_x86.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/methodHandles_x86.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/methodHandles_x86.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/methodHandles_x86.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -27,7 +27,7 @@ // Adapters enum /* platform_dependent_constants */ { - adapter_code_size = 4000 DEBUG_ONLY(+ 6000) + adapter_code_size = 6000 DEBUG_ONLY(+ 6000) }; // Additional helper methods for MethodHandles code generation: diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -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,6 +64,39 @@ const Register scratch = r10; +ATTRIBUTE_ALIGNED(64) static const uint8_t kyberAvx512_12To16Dup[] = { +// 0 - 63 + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11, 12, 13, 13, 14, 15, 16, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23, 24, 25, 25, 26, 27, 28, 28, 29, 30, + 31, 31, 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40, 40, 41, 42, 43, 43, 44, + 45, 46, 46, 47 + }; + +static address kyberAvx512_12To16DupAddr() { + return (address) kyberAvx512_12To16Dup; +} + +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512_12To16Shift[] = { +// 0 - 31 + 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, + 4, 0, 4, 0, 4, 0, 4 + }; + +static address kyberAvx512_12To16ShiftAddr() { + return (address) kyberAvx512_12To16Shift; +} + +ATTRIBUTE_ALIGNED(64) static const uint64_t kyberAvx512_12To16And[] = { +// 0 - 7 + 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, + 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, + 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF + }; + +static address kyberAvx512_12To16AndAddr() { + return (address) kyberAvx512_12To16And; +} + ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512NttPerms[] = { // 0 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, @@ -822,10 +855,65 @@ const Register perms = r11; - Label Loop; + Label Loop, VBMILoop; __ addptr(condensed, condensedOffs); + if (VM_Version::supports_avx512_vbmi()) { + // mask load for the first 48 bytes of each vector + __ mov64(rax, 0x0000FFFFFFFFFFFF); + __ kmovql(k1, rax); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16DupAddr())); + __ evmovdqub(xmm20, Address(perms), Assembler::AVX_512bit); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16ShiftAddr())); + __ evmovdquw(xmm21, Address(perms), Assembler::AVX_512bit); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16AndAddr())); + __ evmovdquq(xmm22, Address(perms), Assembler::AVX_512bit); + + __ align(OptoLoopAlignment); + __ BIND(VBMILoop); + + __ evmovdqub(xmm0, k1, Address(condensed, 0), false, + Assembler::AVX_512bit); + __ evmovdqub(xmm1, k1, Address(condensed, 48), false, + Assembler::AVX_512bit); + __ evmovdqub(xmm2, k1, Address(condensed, 96), false, + Assembler::AVX_512bit); + __ evmovdqub(xmm3, k1, Address(condensed, 144), false, + Assembler::AVX_512bit); + + __ evpermb(xmm4, k0, xmm20, xmm0, false, Assembler::AVX_512bit); + __ evpermb(xmm5, k0, xmm20, xmm1, false, Assembler::AVX_512bit); + __ evpermb(xmm6, k0, xmm20, xmm2, false, Assembler::AVX_512bit); + __ evpermb(xmm7, k0, xmm20, xmm3, false, Assembler::AVX_512bit); + + __ evpsrlvw(xmm4, xmm4, xmm21, Assembler::AVX_512bit); + __ evpsrlvw(xmm5, xmm5, xmm21, Assembler::AVX_512bit); + __ evpsrlvw(xmm6, xmm6, xmm21, Assembler::AVX_512bit); + __ evpsrlvw(xmm7, xmm7, xmm21, Assembler::AVX_512bit); + + __ evpandq(xmm0, xmm22, xmm4, Assembler::AVX_512bit); + __ evpandq(xmm1, xmm22, xmm5, Assembler::AVX_512bit); + __ evpandq(xmm2, xmm22, xmm6, Assembler::AVX_512bit); + __ evpandq(xmm3, xmm22, xmm7, Assembler::AVX_512bit); + + store4regs(parsed, 0, xmm0_3, _masm); + + __ addptr(condensed, 192); + __ addptr(parsed, 256); + __ subl(parsedLength, 128); + __ jcc(Assembler::greater, VBMILoop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; + } + __ lea(perms, ExternalAddress(kyberAvx512_12To16PermsAddr())); load4regs(xmm24_27, perms, 0, _masm); @@ -939,14 +1027,12 @@ void StubGenerator::generate_kyber_stubs() { // Generate Kyber intrinsics code if (UseKyberIntrinsics) { - if (VM_Version::supports_evex()) { - StubRoutines::_kyberNtt = generate_kyberNtt_avx512(this, _masm); - StubRoutines::_kyberInverseNtt = generate_kyberInverseNtt_avx512(this, _masm); - StubRoutines::_kyberNttMult = generate_kyberNttMult_avx512(this, _masm); - StubRoutines::_kyberAddPoly_2 = generate_kyberAddPoly_2_avx512(this, _masm); - StubRoutines::_kyberAddPoly_3 = generate_kyberAddPoly_3_avx512(this, _masm); - StubRoutines::_kyber12To16 = generate_kyber12To16_avx512(this, _masm); - StubRoutines::_kyberBarrettReduce = generate_kyberBarrettReduce_avx512(this, _masm); - } + StubRoutines::_kyberNtt = generate_kyberNtt_avx512(this, _masm); + StubRoutines::_kyberInverseNtt = generate_kyberInverseNtt_avx512(this, _masm); + StubRoutines::_kyberNttMult = generate_kyberNttMult_avx512(this, _masm); + StubRoutines::_kyberAddPoly_2 = generate_kyberAddPoly_2_avx512(this, _masm); + StubRoutines::_kyberAddPoly_3 = generate_kyberAddPoly_3_avx512(this, _masm); + StubRoutines::_kyber12To16 = generate_kyber12To16_avx512(this, _masm); + StubRoutines::_kyberBarrettReduce = generate_kyberBarrettReduce_avx512(this, _masm); } } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -484,6 +484,8 @@ __ cmpl(roundsLeft, 0); __ jcc(Assembler::notEqual, rounds24_loop); + __ xorq(rax, rax); // return 0 + // store the states for (int i = 0; i < 5; i++) { __ evmovdquq(Address(state0, i * 40), k5, xmm(i), true, Assembler::AVX_512bit); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/vm_version_x86.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/x86/vm_version_x86.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/vm_version_x86.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/vm_version_x86.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1273,7 +1273,7 @@ // Kyber Intrinsics // Currently we only have them for AVX512 #ifdef _LP64 - if (supports_evex() && supports_avx512bw()) { + if (supports_avx512vlbw()) { if (FLAG_IS_DEFAULT(UseKyberIntrinsics)) { UseKyberIntrinsics = true; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/x86.ad openjdk-25-25.0.5+8/src/hotspot/cpu/x86/x86.ad --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/x86.ad 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/x86.ad 2026-10-19 12:10:20.000000000 +0000 @@ -1500,7 +1500,6 @@ } break; case Op_LoadVectorGather: - case Op_LoadVectorGatherMasked: if (UseAVX < 2) { return false; } @@ -1795,16 +1794,6 @@ } break; case Op_LoadVectorGatherMasked: - if (!is_subword_type(bt) && size_in_bits < 512 && !VM_Version::supports_avx512vl()) { - return false; - } - if (is_subword_type(bt) && - ((size_in_bits > 256 && !VM_Version::supports_avx512bw()) || - (size_in_bits < 64) || - (bt == T_SHORT && !VM_Version::supports_bmi2()))) { - return false; - } - break; case Op_StoreVectorScatterMasked: case Op_StoreVectorScatter: if (is_subword_type(bt)) { @@ -1814,10 +1803,7 @@ } // fallthrough case Op_LoadVectorGather: - if (!is_subword_type(bt) && size_in_bits == 64) { - return false; - } - if (is_subword_type(bt) && size_in_bits < 64) { + if (size_in_bits == 64 ) { return false; } break; @@ -2024,7 +2010,7 @@ if (is_subword_type(bt) && !VM_Version::supports_avx512bw()) { return false; // Implementation limitation } - if (is_floating_point_type(bt)) { + if (is_floating_point_type(bt) && !VM_Version::supports_avx10_2()) { return false; // Implementation limitation } return true; @@ -3966,11 +3952,10 @@ // ---------------------------------------- Gather ------------------------------------ -// Gather BYTE, SHORT, INT, LONG, FLOAT, DOUBLE +// Gather INT, LONG, FLOAT, DOUBLE instruct gather(legVec dst, memory mem, legVec idx, rRegP tmp, legVec mask) %{ - predicate(!VM_Version::supports_avx512vl() && !is_subword_type(Matcher::vector_element_basic_type(n)) && - Matcher::vector_length_in_bytes(n) <= 32); + predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n) <= 32); match(Set dst (LoadVectorGather mem idx)); effect(TEMP dst, TEMP tmp, TEMP mask); format %{ "load_vector_gather $dst, $mem, $idx\t! using $tmp and $mask as TEMP" %} @@ -3987,8 +3972,7 @@ instruct evgather(vec dst, memory mem, vec idx, rRegP tmp, kReg ktmp) %{ - predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n) == 64) && - !is_subword_type(Matcher::vector_element_basic_type(n))); + predicate(VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n) == 64); match(Set dst (LoadVectorGather mem idx)); effect(TEMP dst, TEMP tmp, TEMP ktmp); format %{ "load_vector_gather $dst, $mem, $idx\t! using $tmp and ktmp as TEMP" %} @@ -4003,8 +3987,7 @@ %} instruct evgather_masked(vec dst, memory mem, vec idx, kReg mask, kReg ktmp, rRegP tmp) %{ - predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n) == 64) && - !is_subword_type(Matcher::vector_element_basic_type(n))); + predicate(VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n) == 64); match(Set dst (LoadVectorGatherMasked mem (Binary idx mask))); effect(TEMP_DEF dst, TEMP tmp, TEMP ktmp); format %{ "load_vector_gather_masked $dst, $mem, $idx, $mask\t! using $tmp and ktmp as TEMP" %} @@ -4023,235 +4006,6 @@ ins_pipe( pipe_slow ); %} -instruct vgather_subwordLE8B(vec dst, memory mem, rRegP idx_base, immI_0 offset, rRegP tmp, rRegI rtmp) %{ - predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) <= 8); - match(Set dst (LoadVectorGather mem (Binary idx_base offset))); - effect(TEMP tmp, TEMP rtmp); - format %{ "vector_gatherLE8 $dst, $mem, $idx_base\t! using $tmp and $rtmp as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ lea($tmp$$Register, $mem$$Address); - __ vgather8b_offset(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base$$Register, noreg, $rtmp$$Register, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - -instruct vgather_subwordGT8B(vec dst, memory mem, rRegP idx_base, immI_0 offset, rRegP tmp, rRegP idx_base_temp, - vec xtmp1, vec xtmp2, vec xtmp3, rRegI rtmp, rRegI length, rFlagsReg cr) %{ - predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) > 8); - match(Set dst (LoadVectorGather mem (Binary idx_base offset))); - effect(TEMP_DEF dst, TEMP tmp, TEMP idx_base_temp, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP rtmp, TEMP length, KILL cr); - format %{ "vector_gatherGT8 $dst, $mem, $idx_base\t! using $tmp, $idx_base_temp, $xtmp1, $xtmp2, $xtmp3, $rtmp and $length as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - int vector_len = Matcher::vector_length(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ lea($tmp$$Register, $mem$$Address); - __ movptr($idx_base_temp$$Register, $idx_base$$Register); - __ vgather_subword(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base_temp$$Register, noreg, noreg, $xtmp1$$XMMRegister, - $xtmp2$$XMMRegister, $xtmp3$$XMMRegister, $rtmp$$Register, noreg, $length$$Register, vector_len, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - -instruct vgather_subwordLE8B_off(vec dst, memory mem, rRegP idx_base, rRegI offset, rRegP tmp, rRegI rtmp, rFlagsReg cr) %{ - predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) <= 8); - match(Set dst (LoadVectorGather mem (Binary idx_base offset))); - effect(TEMP tmp, TEMP rtmp, KILL cr); - format %{ "vector_gatherLE8_off $dst, $mem, $idx_base, $offset\t! using $tmp and $rtmp as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ lea($tmp$$Register, $mem$$Address); - __ vgather8b_offset(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base$$Register, $offset$$Register, $rtmp$$Register, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - - -instruct vgather_subwordGT8B_off(vec dst, memory mem, rRegP idx_base, rRegI offset, rRegP tmp, rRegP idx_base_temp, - vec xtmp1, vec xtmp2, vec xtmp3, rRegI rtmp, rRegI length, rFlagsReg cr) %{ - predicate(is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) > 8); - match(Set dst (LoadVectorGather mem (Binary idx_base offset))); - effect(TEMP_DEF dst, TEMP tmp, TEMP idx_base_temp, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP rtmp, TEMP length, KILL cr); - format %{ "vector_gatherGT8_off $dst, $mem, $idx_base, $offset\t! using $tmp, $idx_base_temp, $xtmp1, $xtmp2, $xtmp3, $rtmp and $length as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - int vector_len = Matcher::vector_length(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ lea($tmp$$Register, $mem$$Address); - __ movptr($idx_base_temp$$Register, $idx_base$$Register); - __ vgather_subword(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base_temp$$Register, $offset$$Register, noreg, $xtmp1$$XMMRegister, - $xtmp2$$XMMRegister, $xtmp3$$XMMRegister, $rtmp$$Register, noreg, $length$$Register, vector_len, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - - -instruct vgather_masked_subwordLE8B_avx3(vec dst, memory mem, rRegP idx_base, immI_0 offset, kReg mask, rRegL mask_idx, rRegP tmp, rRegI rtmp, rRegL rtmp2, rFlagsReg cr) %{ - predicate(VM_Version::supports_avx512bw() && is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) <= 8); - match(Set dst (LoadVectorGatherMasked mem (Binary idx_base (Binary mask offset)))); - effect(TEMP mask_idx, TEMP tmp, TEMP rtmp, TEMP rtmp2, KILL cr); - format %{ "vector_masked_gatherLE8 $dst, $mem, $idx_base, $mask\t! using $mask_idx, $tmp, $rtmp and $rtmp2 as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ xorq($mask_idx$$Register, $mask_idx$$Register); - __ lea($tmp$$Register, $mem$$Address); - __ kmovql($rtmp2$$Register, $mask$$KRegister); - __ vgather8b_masked_offset(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base$$Register, noreg, $rtmp2$$Register, $mask_idx$$Register, $rtmp$$Register, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - -instruct vgather_masked_subwordGT8B_avx3(vec dst, memory mem, rRegP idx_base, immI_0 offset, kReg mask, rRegP tmp, rRegP idx_base_temp, - vec xtmp1, vec xtmp2, vec xtmp3, rRegI rtmp, rRegL rtmp2, rRegL mask_idx, rRegI length, rFlagsReg cr) %{ - predicate(VM_Version::supports_avx512bw() && is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) > 8); - match(Set dst (LoadVectorGatherMasked mem (Binary idx_base (Binary mask offset)))); - effect(TEMP_DEF dst, TEMP tmp, TEMP idx_base_temp, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP rtmp, TEMP rtmp2, TEMP mask_idx, TEMP length, KILL cr); - format %{ "vector_gatherGT8_masked $dst, $mem, $idx_base, $mask\t! using $tmp, $idx_base_temp, $xtmp1, $xtmp2, $xtmp3, $rtmp, $rtmp2, $mask_idx and $length as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - int vector_len = Matcher::vector_length(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ xorq($mask_idx$$Register, $mask_idx$$Register); - __ lea($tmp$$Register, $mem$$Address); - __ movptr($idx_base_temp$$Register, $idx_base$$Register); - __ kmovql($rtmp2$$Register, $mask$$KRegister); - __ vgather_subword(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base_temp$$Register, noreg, $rtmp2$$Register, $xtmp1$$XMMRegister, - $xtmp2$$XMMRegister, $xtmp3$$XMMRegister, $rtmp$$Register, $mask_idx$$Register, $length$$Register, vector_len, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - -instruct vgather_masked_subwordLE8B_off_avx3(vec dst, memory mem, rRegP idx_base, rRegI offset, kReg mask, rRegL mask_idx, rRegP tmp, rRegI rtmp, rRegL rtmp2, rFlagsReg cr) %{ - predicate(VM_Version::supports_avx512bw() && is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) <= 8); - match(Set dst (LoadVectorGatherMasked mem (Binary idx_base (Binary mask offset)))); - effect(TEMP mask_idx, TEMP tmp, TEMP rtmp, TEMP rtmp2, KILL cr); - format %{ "vector_masked_gatherLE8_off $dst, $mem, $idx_base, $offset, $mask\t! using $mask_idx, $tmp, $rtmp and $rtmp2 as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ xorq($mask_idx$$Register, $mask_idx$$Register); - __ lea($tmp$$Register, $mem$$Address); - __ kmovql($rtmp2$$Register, $mask$$KRegister); - __ vgather8b_masked_offset(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base$$Register, $offset$$Register, - $rtmp2$$Register, $mask_idx$$Register, $rtmp$$Register, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - -instruct vgather_masked_subwordGT8B_off_avx3(vec dst, memory mem, rRegP idx_base, rRegI offset, kReg mask, rRegP tmp, rRegP idx_base_temp, - vec xtmp1, vec xtmp2, vec xtmp3, rRegI rtmp, rRegL rtmp2, rRegL mask_idx, rRegI length, rFlagsReg cr) %{ - predicate(VM_Version::supports_avx512bw() && is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) > 8); - match(Set dst (LoadVectorGatherMasked mem (Binary idx_base (Binary mask offset)))); - effect(TEMP_DEF dst, TEMP tmp, TEMP idx_base_temp, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP rtmp, TEMP rtmp2, TEMP mask_idx, TEMP length, KILL cr); - format %{ "vector_gatherGT8_masked_off $dst, $mem, $idx_base, $offset, $mask\t! using $tmp, $idx_base_temp, $xtmp1, $xtmp2, $xtmp3, $rtmp, $rtmp2, $mask_idx and $length as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - int vector_len = Matcher::vector_length(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ xorq($mask_idx$$Register, $mask_idx$$Register); - __ lea($tmp$$Register, $mem$$Address); - __ movptr($idx_base_temp$$Register, $idx_base$$Register); - __ kmovql($rtmp2$$Register, $mask$$KRegister); - __ vgather_subword(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base_temp$$Register, $offset$$Register, $rtmp2$$Register, $xtmp1$$XMMRegister, - $xtmp2$$XMMRegister, $xtmp3$$XMMRegister, $rtmp$$Register, $mask_idx$$Register, $length$$Register, vector_len, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - -instruct vgather_masked_subwordLE8B_avx2(vec dst, memory mem, rRegP idx_base, immI_0 offset, vec mask, rRegI mask_idx, rRegP tmp, rRegI rtmp, rRegI rtmp2, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vlbw() && is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) <= 8); - match(Set dst (LoadVectorGatherMasked mem (Binary idx_base (Binary mask offset)))); - effect(TEMP mask_idx, TEMP tmp, TEMP rtmp, TEMP rtmp2, KILL cr); - format %{ "vector_masked_gatherLE8 $dst, $mem, $idx_base, $mask\t! using $mask_idx, $tmp, $rtmp and $rtmp2 as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ lea($tmp$$Register, $mem$$Address); - __ vpmovmskb($rtmp2$$Register, $mask$$XMMRegister, vlen_enc); - if (elem_bt == T_SHORT) { - __ movl($mask_idx$$Register, 0x55555555); - __ pextl($rtmp2$$Register, $rtmp2$$Register, $mask_idx$$Register); - } - __ xorl($mask_idx$$Register, $mask_idx$$Register); - __ vgather8b_masked_offset(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base$$Register, noreg, $rtmp2$$Register, $mask_idx$$Register, $rtmp$$Register, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - -instruct vgather_masked_subwordGT8B_avx2(vec dst, memory mem, rRegP idx_base, immI_0 offset, vec mask, rRegP tmp, rRegP idx_base_temp, - vec xtmp1, vec xtmp2, vec xtmp3, rRegI rtmp, rRegI rtmp2, rRegI mask_idx, rRegI length, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vlbw() && is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) > 8); - match(Set dst (LoadVectorGatherMasked mem (Binary idx_base (Binary mask offset)))); - effect(TEMP_DEF dst, TEMP tmp, TEMP idx_base_temp, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP rtmp, TEMP rtmp2, TEMP mask_idx, TEMP length, KILL cr); - format %{ "vector_gatherGT8_masked $dst, $mem, $idx_base, $mask\t! using $tmp, $idx_base_temp, $xtmp1, $xtmp2, $xtmp3, $rtmp, $rtmp2, $mask_idx and $length as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - int vector_len = Matcher::vector_length(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ lea($tmp$$Register, $mem$$Address); - __ movptr($idx_base_temp$$Register, $idx_base$$Register); - __ vpmovmskb($rtmp2$$Register, $mask$$XMMRegister, vlen_enc); - if (elem_bt == T_SHORT) { - __ movl($mask_idx$$Register, 0x55555555); - __ pextl($rtmp2$$Register, $rtmp2$$Register, $mask_idx$$Register); - } - __ xorl($mask_idx$$Register, $mask_idx$$Register); - __ vgather_subword(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base_temp$$Register, noreg, $rtmp2$$Register, $xtmp1$$XMMRegister, - $xtmp2$$XMMRegister, $xtmp3$$XMMRegister, $rtmp$$Register, $mask_idx$$Register, $length$$Register, vector_len, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - -instruct vgather_masked_subwordLE8B_off_avx2(vec dst, memory mem, rRegP idx_base, rRegI offset, vec mask, rRegI mask_idx, rRegP tmp, rRegI rtmp, rRegI rtmp2, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vlbw() && is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) <= 8); - match(Set dst (LoadVectorGatherMasked mem (Binary idx_base (Binary mask offset)))); - effect(TEMP mask_idx, TEMP tmp, TEMP rtmp, TEMP rtmp2, KILL cr); - format %{ "vector_masked_gatherLE8_off $dst, $mem, $idx_base, $offset, $mask\t! using $mask_idx, $tmp, $rtmp and $rtmp2 as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ lea($tmp$$Register, $mem$$Address); - __ vpmovmskb($rtmp2$$Register, $mask$$XMMRegister, vlen_enc); - if (elem_bt == T_SHORT) { - __ movl($mask_idx$$Register, 0x55555555); - __ pextl($rtmp2$$Register, $rtmp2$$Register, $mask_idx$$Register); - } - __ xorl($mask_idx$$Register, $mask_idx$$Register); - __ vgather8b_masked_offset(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base$$Register, $offset$$Register, - $rtmp2$$Register, $mask_idx$$Register, $rtmp$$Register, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - -instruct vgather_masked_subwordGT8B_off_avx2(vec dst, memory mem, rRegP idx_base, rRegI offset, vec mask, rRegP tmp, rRegP idx_base_temp, - vec xtmp1, vec xtmp2, vec xtmp3, rRegI rtmp, rRegI rtmp2, rRegI mask_idx, rRegI length, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vlbw() && is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) > 8); - match(Set dst (LoadVectorGatherMasked mem (Binary idx_base (Binary mask offset)))); - effect(TEMP_DEF dst, TEMP tmp, TEMP idx_base_temp, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP rtmp, TEMP rtmp2, TEMP mask_idx, TEMP length, KILL cr); - format %{ "vector_gatherGT8_masked_off $dst, $mem, $idx_base, $offset, $mask\t! using $tmp, $idx_base_temp, $xtmp1, $xtmp2, $xtmp3, $rtmp, $rtmp2, $mask_idx and $length as TEMP" %} - ins_encode %{ - int vlen_enc = vector_length_encoding(this); - int vector_len = Matcher::vector_length(this); - BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ xorl($mask_idx$$Register, $mask_idx$$Register); - __ lea($tmp$$Register, $mem$$Address); - __ movptr($idx_base_temp$$Register, $idx_base$$Register); - __ vpmovmskb($rtmp2$$Register, $mask$$XMMRegister, vlen_enc); - if (elem_bt == T_SHORT) { - __ movl($mask_idx$$Register, 0x55555555); - __ pextl($rtmp2$$Register, $rtmp2$$Register, $mask_idx$$Register); - } - __ xorl($mask_idx$$Register, $mask_idx$$Register); - __ vgather_subword(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx_base_temp$$Register, $offset$$Register, $rtmp2$$Register, $xtmp1$$XMMRegister, - $xtmp2$$XMMRegister, $xtmp3$$XMMRegister, $rtmp$$Register, $mask_idx$$Register, $length$$Register, vector_len, vlen_enc); - %} - ins_pipe( pipe_slow ); -%} - // ====================Scatter======================================= // Scatter INT, LONG, FLOAT, DOUBLE @@ -5293,9 +5047,9 @@ //--------------------Min/Max Float Reduction -------------------- // Float Min Reduction -instruct minmax_reduction2F(legRegF dst, immF src1, legVec src2, legVec tmp, - legVec atmp, legVec btmp, legVec xmm_1, rFlagsReg cr) %{ - predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && +instruct minmax_reduction2F(legRegF dst, immF src1, legVec src2, legVec tmp, legVec atmp, + legVec btmp, legVec xmm_1, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeF::POS_INF) || (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeF::NEG_INF)) && Matcher::vector_length(n->in(2)) == 2); @@ -5316,7 +5070,7 @@ instruct minmax_reductionF(legRegF dst, immF src1, legVec src2, legVec tmp, legVec atmp, legVec btmp, legVec xmm_0, legVec xmm_1, rFlagsReg cr) %{ - predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && + predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeF::POS_INF) || (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeF::NEG_INF)) && Matcher::vector_length(n->in(2)) >= 4); @@ -5335,9 +5089,9 @@ ins_pipe( pipe_slow ); %} -instruct minmax_reduction2F_av(legRegF dst, legVec src, legVec tmp, - legVec atmp, legVec btmp, legVec xmm_1, rFlagsReg cr) %{ - predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && +instruct minmax_reduction2F_av(legRegF dst, legVec src, legVec tmp, legVec atmp, + legVec btmp, legVec xmm_1, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && Matcher::vector_length(n->in(2)) == 2); match(Set dst (MinReductionV dst src)); match(Set dst (MaxReductionV dst src)); @@ -5355,9 +5109,9 @@ %} -instruct minmax_reductionF_av(legRegF dst, legVec src, legVec tmp, - legVec atmp, legVec btmp, legVec xmm_0, legVec xmm_1, rFlagsReg cr) %{ - predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && +instruct minmax_reductionF_av(legRegF dst, legVec src, legVec tmp, legVec atmp, legVec btmp, + legVec xmm_0, legVec xmm_1, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && Matcher::vector_length(n->in(2)) >= 4); match(Set dst (MinReductionV dst src)); match(Set dst (MaxReductionV dst src)); @@ -5374,12 +5128,78 @@ ins_pipe( pipe_slow ); %} +instruct minmax_reduction2F_avx10(regF dst, immF src1, vec src2, vec xtmp1) %{ + predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && + ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeF::POS_INF) || + (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeF::NEG_INF)) && + Matcher::vector_length(n->in(2)) == 2); + match(Set dst (MinReductionV src1 src2)); + match(Set dst (MaxReductionV src1 src2)); + effect(TEMP dst, TEMP xtmp1); + format %{ "vector_minmax_reduction $dst, $src1, $src2 \t; using $xtmp1 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ reduceFloatMinMax(opcode, vlen, false, $dst$$XMMRegister, $src2$$XMMRegister, + xnoreg, xnoreg, xnoreg, $xtmp1$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct minmax_reductionF_avx10(regF dst, immF src1, vec src2, vec xtmp1, vec xtmp2) %{ + predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && + ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeF::POS_INF) || + (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeF::NEG_INF)) && + Matcher::vector_length(n->in(2)) >= 4); + match(Set dst (MinReductionV src1 src2)); + match(Set dst (MaxReductionV src1 src2)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2); + format %{ "vector_minmax_reduction $dst, $src1, $src2 \t; using $xtmp1 and $xtmp2 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ reduceFloatMinMax(opcode, vlen, false, $dst$$XMMRegister, $src2$$XMMRegister, xnoreg, xnoreg, + xnoreg, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct minmax_reduction2F_avx10_av(regF dst, vec src, vec xtmp1) %{ + predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && + Matcher::vector_length(n->in(2)) == 2); + match(Set dst (MinReductionV dst src)); + match(Set dst (MaxReductionV dst src)); + effect(TEMP dst, TEMP xtmp1); + format %{ "vector_minmax2F_reduction $dst, $src \t; using $xtmp1 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src); + __ reduceFloatMinMax(opcode, vlen, true, $dst$$XMMRegister, $src$$XMMRegister, xnoreg, xnoreg, xnoreg, + $xtmp1$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct minmax_reductionF_avx10_av(regF dst, vec src, vec xtmp1, vec xtmp2) %{ + predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && + Matcher::vector_length(n->in(2)) >= 4); + match(Set dst (MinReductionV dst src)); + match(Set dst (MaxReductionV dst src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2); + format %{ "vector_minmax2F_reduction $dst, $src \t; using $xtmp1 and $xtmp2 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src); + __ reduceFloatMinMax(opcode, vlen, true, $dst$$XMMRegister, $src$$XMMRegister, xnoreg, xnoreg, xnoreg, + $xtmp1$$XMMRegister, $xtmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} //--------------------Min Double Reduction -------------------- -instruct minmax_reduction2D(legRegD dst, immD src1, legVec src2, - legVec tmp1, legVec tmp2, legVec tmp3, legVec tmp4, // TEMPs - rFlagsReg cr) %{ - predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && +instruct minmax_reduction2D(legRegD dst, immD src1, legVec src2, legVec tmp1, legVec tmp2, + legVec tmp3, legVec tmp4, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeD::POS_INF) || (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeD::NEG_INF)) && Matcher::vector_length(n->in(2)) == 2); @@ -5398,10 +5218,9 @@ ins_pipe( pipe_slow ); %} -instruct minmax_reductionD(legRegD dst, immD src1, legVec src2, - legVec tmp1, legVec tmp2, legVec tmp3, legVec tmp4, legVec tmp5, // TEMPs - rFlagsReg cr) %{ - predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && +instruct minmax_reductionD(legRegD dst, immD src1, legVec src2, legVec tmp1, legVec tmp2, + legVec tmp3, legVec tmp4, legVec tmp5, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeD::POS_INF) || (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeD::NEG_INF)) && Matcher::vector_length(n->in(2)) >= 4); @@ -5421,10 +5240,9 @@ %} -instruct minmax_reduction2D_av(legRegD dst, legVec src, - legVec tmp1, legVec tmp2, legVec tmp3, legVec tmp4, // TEMPs - rFlagsReg cr) %{ - predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && +instruct minmax_reduction2D_av(legRegD dst, legVec src, legVec tmp1, legVec tmp2, + legVec tmp3, legVec tmp4, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && Matcher::vector_length(n->in(2)) == 2); match(Set dst (MinReductionV dst src)); match(Set dst (MaxReductionV dst src)); @@ -5441,10 +5259,9 @@ ins_pipe( pipe_slow ); %} -instruct minmax_reductionD_av(legRegD dst, legVec src, - legVec tmp1, legVec tmp2, legVec tmp3, legVec tmp4, legVec tmp5, // TEMPs - rFlagsReg cr) %{ - predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && +instruct minmax_reductionD_av(legRegD dst, legVec src, legVec tmp1, legVec tmp2, legVec tmp3, + legVec tmp4, legVec tmp5, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && Matcher::vector_length(n->in(2)) >= 4); match(Set dst (MinReductionV dst src)); match(Set dst (MaxReductionV dst src)); @@ -5461,6 +5278,75 @@ ins_pipe( pipe_slow ); %} +instruct minmax_reduction2D_avx10(regD dst, immD src1, vec src2, vec xtmp1) %{ + predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && + ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeD::POS_INF) || + (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeD::NEG_INF)) && + Matcher::vector_length(n->in(2)) == 2); + match(Set dst (MinReductionV src1 src2)); + match(Set dst (MaxReductionV src1 src2)); + effect(TEMP dst, TEMP xtmp1); + format %{ "vector_minmax2D_reduction $dst, $src1, $src2 ; using $xtmp1 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ reduceDoubleMinMax(opcode, vlen, false, $dst$$XMMRegister, $src2$$XMMRegister, xnoreg, + xnoreg, xnoreg, $xtmp1$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct minmax_reductionD_avx10(regD dst, immD src1, vec src2, vec xtmp1, vec xtmp2) %{ + predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && + ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeD::POS_INF) || + (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeD::NEG_INF)) && + Matcher::vector_length(n->in(2)) >= 4); + match(Set dst (MinReductionV src1 src2)); + match(Set dst (MaxReductionV src1 src2)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2); + format %{ "vector_minmaxD_reduction $dst, $src1, $src2 ; using $xtmp1 and $xtmp2 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ reduceDoubleMinMax(opcode, vlen, false, $dst$$XMMRegister, $src2$$XMMRegister, xnoreg, xnoreg, + xnoreg, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + + +instruct minmax_reduction2D_av_avx10(regD dst, vec src, vec xtmp1) %{ + predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && + Matcher::vector_length(n->in(2)) == 2); + match(Set dst (MinReductionV dst src)); + match(Set dst (MaxReductionV dst src)); + effect(TEMP dst, TEMP xtmp1); + format %{ "vector_minmax2D_reduction $dst, $src ; using $xtmp1 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src); + __ reduceDoubleMinMax(opcode, vlen, true, $dst$$XMMRegister, $src$$XMMRegister, + xnoreg, xnoreg, xnoreg, $xtmp1$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct minmax_reductionD_av_avx10(regD dst, vec src, vec xtmp1, vec xtmp2) %{ + predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && + Matcher::vector_length(n->in(2)) >= 4); + match(Set dst (MinReductionV dst src)); + match(Set dst (MaxReductionV dst src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2); + format %{ "vector_minmaxD_reduction $dst, $src ; using $xtmp1 and $xtmp2 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src); + __ reduceDoubleMinMax(opcode, vlen, true, $dst$$XMMRegister, $src$$XMMRegister, + xnoreg, xnoreg, xnoreg, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + // ====================VECTOR ARITHMETIC======================================= // --------------------------------- ADD -------------------------------------- @@ -6348,8 +6234,24 @@ %} // Float/Double vector Min/Max +instruct minmaxFP_avx10_reg(vec dst, vec a, vec b) %{ + predicate(VM_Version::supports_avx10_2() && + is_floating_point_type(Matcher::vector_element_basic_type(n))); // T_FLOAT, T_DOUBLE + match(Set dst (MinV a b)); + match(Set dst (MaxV a b)); + format %{ "vector_minmaxFP $dst, $a, $b" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + int opcode = this->ideal_Opcode(); + BasicType elem_bt = Matcher::vector_element_basic_type(this); + __ vminmax_fp(opcode, elem_bt, $dst$$XMMRegister, k0, $a$$XMMRegister, $b$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +// Float/Double vector Min/Max instruct minmaxFP_reg(legVec dst, legVec a, legVec b, legVec tmp, legVec atmp, legVec btmp) %{ - predicate(Matcher::vector_length_in_bytes(n) <= 32 && + predicate(!VM_Version::supports_avx10_2() && Matcher::vector_length_in_bytes(n) <= 32 && is_floating_point_type(Matcher::vector_element_basic_type(n)) && // T_FLOAT, T_DOUBLE UseAVX > 0); match(Set dst (MinV a b)); @@ -6370,8 +6272,8 @@ ins_pipe( pipe_slow ); %} -instruct evminmaxFP_reg_eavx(vec dst, vec a, vec b, vec atmp, vec btmp, kReg ktmp) %{ - predicate(Matcher::vector_length_in_bytes(n) == 64 && +instruct evminmaxFP_reg_evex(vec dst, vec a, vec b, vec atmp, vec btmp, kReg ktmp) %{ + predicate(!VM_Version::supports_avx10_2() && Matcher::vector_length_in_bytes(n) == 64 && is_floating_point_type(Matcher::vector_element_basic_type(n))); // T_FLOAT, T_DOUBLE match(Set dst (MinV a b)); match(Set dst (MaxV a b)); @@ -7630,8 +7532,11 @@ instruct castFtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n->in(1)) < 64 && - type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4); + predicate(!VM_Version::supports_avx10_2() && + !VM_Version::supports_avx512vl() && + Matcher::vector_length_in_bytes(n->in(1)) < 64 && + type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4 && + is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastF2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, KILL cr); format %{ "vector_cast_f2x $dst,$src\t! using $xtmp1, $xtmp2, $xtmp3 and $xtmp4 as TEMP" %} @@ -7653,7 +7558,8 @@ %} instruct castFtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{ - predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && + predicate(!VM_Version::supports_avx10_2() && + (VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastF2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, KILL cr); @@ -7675,6 +7581,33 @@ ins_pipe( pipe_slow ); %} +instruct castFtoX_reg_avx10(vec dst, vec src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastF2X src)); + format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %} + ins_encode %{ + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(this, $src); + __ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct castFtoX_mem_avx10(vec dst, memory src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastF2X (LoadVector src))); + format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %} + ins_encode %{ + int vlen = Matcher::vector_length(this); + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(vlen * sizeof(jfloat)); + __ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct vcastDtoF_reg(vec dst, vec src) %{ predicate(Matcher::vector_element_basic_type(n) == T_FLOAT); match(Set dst (VectorCastD2X src)); @@ -7687,7 +7620,9 @@ %} instruct castDtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, vec xtmp5, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n->in(1)) < 64 && + predicate(!VM_Version::supports_avx10_2() && + !VM_Version::supports_avx512vl() && + Matcher::vector_length_in_bytes(n->in(1)) < 64 && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastD2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, TEMP xtmp5, KILL cr); @@ -7703,7 +7638,8 @@ %} instruct castDtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{ - predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && + predicate(!VM_Version::supports_avx10_2() && + (VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastD2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, KILL cr); @@ -7719,6 +7655,33 @@ ins_pipe( pipe_slow ); %} +instruct castDtoX_reg_avx10(vec dst, vec src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastD2X src)); + format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this, $src); + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + __ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct castDtoX_mem_avx10(vec dst, memory src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastD2X (LoadVector src))); + format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %} + ins_encode %{ + int vlen = Matcher::vector_length(this); + int vlen_enc = vector_length_encoding(vlen * sizeof(jdouble)); + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + __ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct vucast(vec dst, vec src) %{ match(Set dst (VectorUCastB2X src)); match(Set dst (VectorUCastS2X src)); @@ -10687,8 +10650,22 @@ ins_pipe(pipe_slow); %} +instruct scalar_minmax_HF_avx10_reg(regF dst, regF src1, regF src2) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MaxHF src1 src2)); + match(Set dst (MinHF src1 src2)); + format %{ "scalar_min_max_fp16 $dst, $src1, $src2" %} + ins_encode %{ + int function = this->ideal_Opcode() == Op_MinHF ? AVX10_MINMAX_MIN_COMPARE_SIGN : AVX10_MINMAX_MAX_COMPARE_SIGN; + __ eminmaxsh($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, function); + %} + ins_pipe( pipe_slow ); +%} + instruct scalar_minmax_HF_reg(regF dst, regF src1, regF src2, kReg ktmp, regF xtmp1, regF xtmp2) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (MaxHF src1 src2)); match(Set dst (MinHF src1 src2)); effect(TEMP_DEF dst, TEMP ktmp, TEMP xtmp1, TEMP xtmp2); @@ -10788,8 +10765,37 @@ ins_pipe( pipe_slow ); %} +instruct vector_minmax_HF_avx10_mem(vec dst, vec src1, memory src2) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MinVHF src1 (VectorReinterpret (LoadVector src2)))); + match(Set dst (MaxVHF src1 (VectorReinterpret (LoadVector src2)))); + format %{ "vector_min_max_fp16_mem $dst, $src1, $src2" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + int function = this->ideal_Opcode() == Op_MinVHF ? AVX10_MINMAX_MIN_COMPARE_SIGN : AVX10_MINMAX_MAX_COMPARE_SIGN; + __ evminmaxph($dst$$XMMRegister, k0, $src1$$XMMRegister, $src2$$Address, true, function, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_minmax_HF_avx10_reg(vec dst, vec src1, vec src2) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MinVHF src1 src2)); + match(Set dst (MaxVHF src1 src2)); + format %{ "vector_min_max_fp16 $dst, $src1, $src2" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + int function = this->ideal_Opcode() == Op_MinVHF ? AVX10_MINMAX_MIN_COMPARE_SIGN : AVX10_MINMAX_MAX_COMPARE_SIGN; + __ evminmaxph($dst$$XMMRegister, k0, $src1$$XMMRegister, $src2$$XMMRegister, true, function, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct vector_minmax_HF_reg(vec dst, vec src1, vec src2, kReg ktmp, vec xtmp1, vec xtmp2) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (MinVHF src1 src2)); match(Set dst (MaxVHF src1 src2)); effect(TEMP_DEF dst, TEMP ktmp, TEMP xtmp1, TEMP xtmp2); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/x86_64.ad openjdk-25-25.0.5+8/src/hotspot/cpu/x86/x86_64.ad --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/x86/x86_64.ad 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/x86/x86_64.ad 2026-10-19 12:10:20.000000000 +0000 @@ -4447,8 +4447,19 @@ %} // max = java.lang.Math.max(float a, float b) +instruct maxF_avx10_reg(regF dst, regF a, regF b) %{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MaxF a b)); + format %{ "maxF $dst, $a, $b" %} + ins_encode %{ + __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MAX_COMPARE_SIGN); + %} + ins_pipe( pipe_slow ); +%} + +// max = java.lang.Math.max(float a, float b) instruct maxF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) %{ - predicate(UseAVX > 0 && !VLoopReductions::is_reduction(n)); + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); match(Set dst (MaxF a b)); effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); format %{ "maxF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} @@ -4459,7 +4470,7 @@ %} instruct maxF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) %{ - predicate(UseAVX > 0 && VLoopReductions::is_reduction(n)); + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); match(Set dst (MaxF a b)); effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); @@ -4472,8 +4483,19 @@ %} // max = java.lang.Math.max(double a, double b) +instruct maxD_avx10_reg(regD dst, regD a, regD b) %{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MaxD a b)); + format %{ "maxD $dst, $a, $b" %} + ins_encode %{ + __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MAX_COMPARE_SIGN); + %} + ins_pipe( pipe_slow ); +%} + +// max = java.lang.Math.max(double a, double b) instruct maxD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) %{ - predicate(UseAVX > 0 && !VLoopReductions::is_reduction(n)); + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); match(Set dst (MaxD a b)); effect(USE a, USE b, TEMP atmp, TEMP btmp, TEMP tmp); format %{ "maxD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} @@ -4484,7 +4506,7 @@ %} instruct maxD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) %{ - predicate(UseAVX > 0 && VLoopReductions::is_reduction(n)); + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); match(Set dst (MaxD a b)); effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); @@ -4496,9 +4518,20 @@ ins_pipe( pipe_slow ); %} +// max = java.lang.Math.min(float a, float b) +instruct minF_avx10_reg(regF dst, regF a, regF b) %{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MinF a b)); + format %{ "minF $dst, $a, $b" %} + ins_encode %{ + __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MIN_COMPARE_SIGN); + %} + ins_pipe( pipe_slow ); +%} + // min = java.lang.Math.min(float a, float b) instruct minF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) %{ - predicate(UseAVX > 0 && !VLoopReductions::is_reduction(n)); + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); match(Set dst (MinF a b)); effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); format %{ "minF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} @@ -4509,7 +4542,7 @@ %} instruct minF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) %{ - predicate(UseAVX > 0 && VLoopReductions::is_reduction(n)); + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); match(Set dst (MinF a b)); effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); @@ -4521,9 +4554,20 @@ ins_pipe( pipe_slow ); %} +// max = java.lang.Math.min(double a, double b) +instruct minD_avx10_reg(regD dst, regD a, regD b) %{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MinD a b)); + format %{ "minD $dst, $a, $b" %} + ins_encode %{ + __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MIN_COMPARE_SIGN); + %} + ins_pipe( pipe_slow ); +%} + // min = java.lang.Math.min(double a, double b) instruct minD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) %{ - predicate(UseAVX > 0 && !VLoopReductions::is_reduction(n)); + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); match(Set dst (MinD a b)); effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); format %{ "minD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} @@ -4534,7 +4578,7 @@ %} instruct minD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) %{ - predicate(UseAVX > 0 && VLoopReductions::is_reduction(n)); + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); match(Set dst (MinD a b)); effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); @@ -7817,10 +7861,12 @@ effect(KILL cr); format %{ "cmpxchgb $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + "If rax == $mem_ptr then store $newval into $mem_ptr, " + "else store $mem_ptr into rax; rax -> byte\n\t" %} ins_encode %{ __ lock(); __ cmpxchgb($newval$$Register, $mem_ptr$$Address); + __ narrow_subword_type($oldval$$Register, T_BYTE); %} ins_pipe( pipe_cmpxchg ); %} @@ -7834,10 +7880,12 @@ effect(KILL cr); format %{ "cmpxchgw $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + "If rax == $mem_ptr then store $newval into $mem_ptr, " + "else store $mem_ptr into rax; rax -> short\n\t" %} ins_encode %{ __ lock(); __ cmpxchgw($newval$$Register, $mem_ptr$$Address); + __ narrow_subword_type($oldval$$Register, T_SHORT); %} ins_pipe( pipe_cmpxchg ); %} @@ -7851,7 +7899,8 @@ effect(KILL cr); format %{ "cmpxchgl $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + "If rax == $mem_ptr then store $newval into $mem_ptr, " + "else store $mem_ptr into rax\n\t" %} ins_encode %{ __ lock(); __ cmpxchgl($newval$$Register, $mem_ptr$$Address); @@ -7868,7 +7917,8 @@ effect(KILL cr); format %{ "cmpxchgq $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + "If rax == $mem_ptr then store $newval into $mem_ptr, " + "else store $mem_ptr into rax\n\t" %} ins_encode %{ __ lock(); __ cmpxchgq($newval$$Register, $mem_ptr$$Address); @@ -7885,7 +7935,8 @@ effect(KILL cr); format %{ "cmpxchgl $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + "If rax == $mem_ptr then store $newval into $mem_ptr, " + "else store $mem_ptr into rax\n\t" %} ins_encode %{ __ lock(); __ cmpxchgl($newval$$Register, $mem_ptr$$Address); @@ -7903,7 +7954,8 @@ effect(KILL cr); format %{ "cmpxchgq $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + "If rax == $mem_ptr then store $newval into $mem_ptr, " + "else store $mem_ptr into rax\n\t" %} ins_encode %{ __ lock(); __ cmpxchgq($newval$$Register, $mem_ptr$$Address); @@ -11671,6 +11723,7 @@ // XXX do mem variants instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvF2I src)); effect(KILL cr); format %{ "convert_f2i $dst, $src" %} @@ -11680,8 +11733,31 @@ ins_pipe(pipe_slow); %} +instruct convF2I_reg_reg_avx10(rRegI dst, regF src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2I src)); + format %{ "evcvttss2sisl $dst, $src" %} + ins_encode %{ + __ evcvttss2sisl($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2I_reg_mem_avx10(rRegI dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2I (LoadF src))); + format %{ "evcvttss2sisl $dst, $src" %} + ins_encode %{ + __ evcvttss2sisl($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvF2L src)); effect(KILL cr); format %{ "convert_f2l $dst, $src"%} @@ -11691,8 +11767,31 @@ ins_pipe(pipe_slow); %} +instruct convF2L_reg_reg_avx10(rRegL dst, regF src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2L src)); + format %{ "evcvttss2sisq $dst, $src" %} + ins_encode %{ + __ evcvttss2sisq($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2L_reg_mem_avx10(rRegL dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2L (LoadF src))); + format %{ "evcvttss2sisq $dst, $src" %} + ins_encode %{ + __ evcvttss2sisq($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvD2I src)); effect(KILL cr); format %{ "convert_d2i $dst, $src"%} @@ -11702,8 +11801,31 @@ ins_pipe(pipe_slow); %} +instruct convD2I_reg_reg_avx10(rRegI dst, regD src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2I src)); + format %{ "evcvttsd2sisl $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisl($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2I_reg_mem_avx10(rRegI dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2I (LoadD src))); + format %{ "evcvttsd2sisl $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisl($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvD2L src)); effect(KILL cr); format %{ "convert_d2l $dst, $src"%} @@ -11712,6 +11834,28 @@ %} ins_pipe(pipe_slow); %} + +instruct convD2L_reg_reg_avx10(rRegL dst, regD src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2L src)); + format %{ "evcvttsd2sisq $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisq($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2L_reg_mem_avx10(rRegL dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2L (LoadD src))); + format %{ "evcvttsd2sisq $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisq($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} instruct round_double_reg(rRegL dst, regD src, rRegL rtmp, rcx_RegL rcx, rFlagsReg cr) %{ diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/zero/bytecodeInterpreter_zero.inline.hpp openjdk-25-25.0.5+8/src/hotspot/cpu/zero/bytecodeInterpreter_zero.inline.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/zero/bytecodeInterpreter_zero.inline.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/zero/bytecodeInterpreter_zero.inline.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -26,6 +26,8 @@ #ifndef CPU_ZERO_BYTECODEINTERPRETER_ZERO_INLINE_HPP #define CPU_ZERO_BYTECODEINTERPRETER_ZERO_INLINE_HPP +#include "sanitizers/ub.hpp" + // Inline interpreter functions for zero inline jfloat BytecodeInterpreter::VMfloatAdd(jfloat op1, jfloat op2) { @@ -40,6 +42,7 @@ return op1 * op2; } +ATTRIBUTE_NO_UBSAN // IEEE-754 division by zero is well-defined inline jfloat BytecodeInterpreter::VMfloatDiv(jfloat op1, jfloat op2) { return op1 / op2; } @@ -68,7 +71,7 @@ } inline jlong BytecodeInterpreter::VMlongAdd(jlong op1, jlong op2) { - return op1 + op2; + return java_add(op1, op2); } inline jlong BytecodeInterpreter::VMlongAnd(jlong op1, jlong op2) { @@ -82,7 +85,7 @@ } inline jlong BytecodeInterpreter::VMlongMul(jlong op1, jlong op2) { - return op1 * op2; + return java_multiply(op1, op2); } inline jlong BytecodeInterpreter::VMlongOr(jlong op1, jlong op2) { @@ -90,7 +93,7 @@ } inline jlong BytecodeInterpreter::VMlongSub(jlong op1, jlong op2) { - return op1 - op2; + return java_subtract(op1, op2); } inline jlong BytecodeInterpreter::VMlongXor(jlong op1, jlong op2) { @@ -104,19 +107,19 @@ } inline jlong BytecodeInterpreter::VMlongUshr(jlong op1, jint op2) { - return ((unsigned long long) op1) >> (op2 & 0x3F); + return java_shift_right_unsigned(op1, op2); } inline jlong BytecodeInterpreter::VMlongShr(jlong op1, jint op2) { - return op1 >> (op2 & 0x3F); + return java_shift_right(op1, op2); } inline jlong BytecodeInterpreter::VMlongShl(jlong op1, jint op2) { - return op1 << (op2 & 0x3F); + return java_shift_left(op1, op2); } inline jlong BytecodeInterpreter::VMlongNeg(jlong op) { - return -op; + return java_negate(op); } inline jlong BytecodeInterpreter::VMlongNot(jlong op) { @@ -183,8 +186,8 @@ return op1 + op2; } +ATTRIBUTE_NO_UBSAN // IEEE-754 division by zero is well-defined inline jdouble BytecodeInterpreter::VMdoubleDiv(jdouble op1, jdouble op2) { - // Divide by zero... QQQ return op1 / op2; } @@ -228,7 +231,7 @@ // Integer Arithmetic inline jint BytecodeInterpreter::VMintAdd(jint op1, jint op2) { - return op1 + op2; + return java_add(op1, op2); } inline jint BytecodeInterpreter::VMintAnd(jint op1, jint op2) { @@ -242,11 +245,11 @@ } inline jint BytecodeInterpreter::VMintMul(jint op1, jint op2) { - return op1 * op2; + return java_multiply(op1, op2); } inline jint BytecodeInterpreter::VMintNeg(jint op) { - return -op; + return java_negate(op); } inline jint BytecodeInterpreter::VMintOr(jint op1, jint op2) { @@ -260,19 +263,19 @@ } inline jint BytecodeInterpreter::VMintShl(jint op1, jint op2) { - return op1 << (op2 & 0x1F); + return java_shift_left(op1, op2); } inline jint BytecodeInterpreter::VMintShr(jint op1, jint op2) { - return op1 >> (op2 & 0x1F); + return java_shift_right(op1, op2); } inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) { - return op1 - op2; + return java_subtract(op1, op2); } inline juint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { - return ((juint) op1) >> (op2 & 0x1F); + return java_shift_right_unsigned(op1, op2); } inline jint BytecodeInterpreter::VMintXor(jint op1, jint op2) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp openjdk-25-25.0.5+8/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -385,12 +385,15 @@ goto unlock_unwind_and_return; void **arguments; - void *mirror; { + // These locals must remain on stack until call completes + void *mirror; + void *env; + { arguments = (void **) stack->alloc(handler->argument_count() * sizeof(void **)); void **dst = arguments; - void *env = thread->jni_environment(); + env = thread->jni_environment(); *(dst++) = &env; if (method->is_static()) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/os/linux/os_linux.cpp openjdk-25-25.0.5+8/src/hotspot/os/linux/os_linux.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/os/linux/os_linux.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/os/linux/os_linux.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -162,10 +162,8 @@ address os::Linux::_initial_thread_stack_bottom = nullptr; uintptr_t os::Linux::_initial_thread_stack_size = 0; -int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = nullptr; int (*os::Linux::_pthread_setname_np)(pthread_t, const char*) = nullptr; pthread_t os::Linux::_main_thread; -bool os::Linux::_supports_fast_thread_cpu_time = false; const char * os::Linux::_libc_version = nullptr; const char * os::Linux::_libpthread_version = nullptr; @@ -1529,29 +1527,6 @@ } } -void os::Linux::fast_thread_clock_init() { - clockid_t clockid; - struct timespec tp; - int (*pthread_getcpuclockid_func)(pthread_t, clockid_t *) = - (int(*)(pthread_t, clockid_t *)) dlsym(RTLD_DEFAULT, "pthread_getcpuclockid"); - - // Switch to using fast clocks for thread cpu time if - // the clock_getres() returns 0 error code. - // Note, that some kernels may support the current thread - // clock (CLOCK_THREAD_CPUTIME_ID) but not the clocks - // returned by the pthread_getcpuclockid(). - // If the fast POSIX clocks are supported then the clock_getres() - // must return at least tp.tv_sec == 0 which means a resolution - // better than 1 sec. This is extra check for reliability. - - if (pthread_getcpuclockid_func && - pthread_getcpuclockid_func(_main_thread, &clockid) == 0 && - clock_getres(clockid, &tp) == 0 && tp.tv_sec == 0) { - _supports_fast_thread_cpu_time = true; - _pthread_getcpuclockid = pthread_getcpuclockid_func; - } -} - // thread_id is kernel thread id (similar to Solaris LWP id) intx os::current_thread_id() { return os::Linux::gettid(); } int os::current_process_id() { @@ -2189,6 +2164,10 @@ st->cr(); } + if (os::Linux::print_numa_info(st)) { + st->cr(); + } + VM_Version::print_platform_virtualization_info(st); os::Linux::print_steal_info(st); @@ -2592,6 +2571,97 @@ return true; } +#define SYS_DEVICES_NODE "/sys/devices/system/node" + +static size_t read_sysfs_file(const char* path, char* buf, size_t sz) { + FILE* f = os::fopen(path, "r"); + if (f == nullptr) return 0; + size_t n = fread(buf, 1, sz - 1, f); + fclose(f); + buf[n] = '\0'; + while (n > 0 && (buf[n-1] == '\n' || buf[n-1] == '\r')) buf[--n] = '\0'; + return n; +} + +static void print_numa_memory_info(outputStream* st, int node) { + char path[256]; + char line[256]; + long long mem_total = -1; + long long mem_free = -1; + os::snprintf_checked(path, sizeof(path), SYS_DEVICES_NODE "/node%d/meminfo", node); + FILE* f = os::fopen(path, "r"); + if (f == nullptr) { + return; + } + + while (fgets(line, sizeof(line), f) != nullptr) { + long long mval; + if (sscanf(line, "Node %*d MemTotal: %lld kB", &mval) == 1) mem_total = mval; + if (sscanf(line, "Node %*d MemFree: %lld kB", &mval) == 1) mem_free = mval; + } + fclose(f); + + if (mem_total >= 0) { st->print_cr("mem size: %lld kB", mem_total); } + if (mem_free >= 0) { st->print_cr("mem free: %lld kB", mem_free); } +} + +static void print_numa_cpu_list(outputStream* st, int node) { + char path[256]; + char buf[1024]; + os::snprintf_checked(path, sizeof(path), SYS_DEVICES_NODE "/node%d/cpulist", node); + if (read_sysfs_file(path, buf, sizeof(buf)) > 0) { + st->print_cr("cpus: %s", buf); + } else { + st->print_cr("cpus: (unavailable)"); + } +} + +bool os::Linux::print_numa_info(outputStream* st) { + if (!UseNUMA) { + // If NUMA optimizations are not enabled we don't print anything + return false; + } + + char buf[1024]; + if (read_sysfs_file("/sys/devices/system/node/online", buf, sizeof(buf)) > 0) { + st->print_cr("NUMA nodes online: %s", buf); + } else { + return false; + } + + bool first = true; + int node_count = 0; + + if (nindex_to_node() == nullptr) { + return false; + } + + for (int node: *nindex_to_node()) { + char nodepath[256]; + os::snprintf_checked(nodepath, sizeof(nodepath), SYS_DEVICES_NODE "/node%d", node); + DIR* currd = os::opendir(nodepath); + if (currd == nullptr) continue; + if (first) { + st->cr(); + first = false; + } + os::closedir(currd); + + st->print_cr("NUMA node %d", node); + StreamIndentor si(st); + print_numa_cpu_list(st, node); + print_numa_memory_info(st, node); + node_count++; + } + + if (node_count == 0) { + return false; + } + + st->print_cr("Total NUMA node count: %d", node_count); + return true; +} + void os::Linux::print_steal_info(outputStream* st) { if (has_initial_tick_info) { CPUPerfTicks pticks; @@ -4370,14 +4440,7 @@ return (*priority_ptr != -1 || errno == 0 ? OS_OK : OS_ERR); } -// This is the fastest way to get thread cpu time on Linux. -// Returns cpu time (user+sys) for any thread, not only for current. -// POSIX compliant clocks are implemented in the kernels 2.6.16+. -// It might work on 2.6.10+ with a special kernel/glibc patch. -// For reference, please, see IEEE Std 1003.1-2004: -// http://www.unix.org/single_unix_specification - -jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) { +jlong os::Linux::thread_cpu_time(clockid_t clockid) { struct timespec tp; int status = clock_gettime(clockid, &tp); assert(status == 0, "clock_gettime error: %s", os::strerror(errno)); @@ -4690,8 +4753,6 @@ os::Posix::init_2(); - Linux::fast_thread_clock_init(); - if (PosixSignals::init() == JNI_ERR) { return JNI_ERR; } @@ -5118,20 +5179,42 @@ return fd; } -static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time); +// Since kernel v2.6.12 the Linux ABI has had support for encoding the clock +// types in the last three bits. Bit 2 indicates whether a cpu clock refers to a +// thread or a process. Bits 1 and 0 give the type: PROF=0, VIRT=1, SCHED=2, or +// FD=3. The clock CPUCLOCK_VIRT (0b001) reports the thread's consumed user +// time. POSIX compliant implementations of pthread_getcpuclockid return the +// clock CPUCLOCK_SCHED (0b010) which reports the thread's consumed system+user +// time (as mandated by the POSIX standard POSIX.1-2024/IEEE Std 1003.1-2024 +// §3.90). +static bool get_thread_clockid(Thread* thread, clockid_t* clockid, bool total) { + constexpr clockid_t CLOCK_TYPE_MASK = 3; + constexpr clockid_t CPUCLOCK_VIRT = 1; + + int rc = pthread_getcpuclockid(thread->osthread()->pthread_id(), clockid); + if (rc != 0) { + // It's possible to encounter a terminated native thread that failed + // to detach itself from the VM - which should result in ESRCH. + assert_status(rc == ESRCH, rc, "pthread_getcpuclockid failed"); + return false; + } -static jlong fast_cpu_time(Thread *thread) { - clockid_t clockid; - int rc = os::Linux::pthread_getcpuclockid(thread->osthread()->pthread_id(), - &clockid); - if (rc == 0) { - return os::Linux::fast_thread_cpu_time(clockid); - } else { - // It's possible to encounter a terminated native thread that failed - // to detach itself from the VM - which should result in ESRCH. - assert_status(rc == ESRCH, rc, "pthread_getcpuclockid failed"); - return -1; - } + if (!total) { + clockid_t clockid_tmp = *clockid; + clockid_tmp = (clockid_tmp & ~CLOCK_TYPE_MASK) | CPUCLOCK_VIRT; + *clockid = clockid_tmp; + } + + return true; +} + +static jlong user_thread_cpu_time(Thread *thread); + +static jlong total_thread_cpu_time(Thread *thread) { + clockid_t clockid; + bool success = get_thread_clockid(thread, &clockid, true); + + return success ? os::Linux::thread_cpu_time(clockid) : -1; } // current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) @@ -5142,82 +5225,34 @@ // the fast estimate available on the platform. jlong os::current_thread_cpu_time() { - if (os::Linux::supports_fast_thread_cpu_time()) { - return os::Linux::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); - } else { - // return user + sys since the cost is the same - return slow_thread_cpu_time(Thread::current(), true /* user + sys */); - } + return os::Linux::thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } jlong os::thread_cpu_time(Thread* thread) { - // consistent with what current_thread_cpu_time() returns - if (os::Linux::supports_fast_thread_cpu_time()) { - return fast_cpu_time(thread); - } else { - return slow_thread_cpu_time(thread, true /* user + sys */); - } + return total_thread_cpu_time(thread); } jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { - if (user_sys_cpu_time && os::Linux::supports_fast_thread_cpu_time()) { - return os::Linux::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); + if (user_sys_cpu_time) { + return os::Linux::thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } else { - return slow_thread_cpu_time(Thread::current(), user_sys_cpu_time); + return user_thread_cpu_time(Thread::current()); } } jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { - if (user_sys_cpu_time && os::Linux::supports_fast_thread_cpu_time()) { - return fast_cpu_time(thread); + if (user_sys_cpu_time) { + return total_thread_cpu_time(thread); } else { - return slow_thread_cpu_time(thread, user_sys_cpu_time); + return user_thread_cpu_time(thread); } } -// -1 on error. -static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { - pid_t tid = thread->osthread()->thread_id(); - char *s; - char stat[2048]; - size_t statlen; - char proc_name[64]; - int count; - long sys_time, user_time; - char cdummy; - int idummy; - long ldummy; - FILE *fp; - - snprintf(proc_name, 64, "/proc/self/task/%d/stat", tid); - fp = os::fopen(proc_name, "r"); - if (fp == nullptr) return -1; - statlen = fread(stat, 1, 2047, fp); - stat[statlen] = '\0'; - fclose(fp); - - // Skip pid and the command string. Note that we could be dealing with - // weird command names, e.g. user could decide to rename java launcher - // to "java 1.4.2 :)", then the stat file would look like - // 1234 (java 1.4.2 :)) R ... ... - // We don't really need to know the command string, just find the last - // occurrence of ")" and then start parsing from there. See bug 4726580. - s = strrchr(stat, ')'); - if (s == nullptr) return -1; - - // Skip blank chars - do { s++; } while (s && isspace((unsigned char) *s)); - - count = sscanf(s,"%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu", - &cdummy, &idummy, &idummy, &idummy, &idummy, &idummy, - &ldummy, &ldummy, &ldummy, &ldummy, &ldummy, - &user_time, &sys_time); - if (count != 13) return -1; - if (user_sys_cpu_time) { - return ((jlong)sys_time + (jlong)user_time) * (1000000000 / os::Posix::clock_tics_per_second()); - } else { - return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second()); - } +static jlong user_thread_cpu_time(Thread *thread) { + clockid_t clockid; + bool success = get_thread_clockid(thread, &clockid, false); + + return success ? os::Linux::thread_cpu_time(clockid) : -1; } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/os/linux/os_linux.hpp openjdk-25-25.0.5+8/src/hotspot/os/linux/os_linux.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/os/linux/os_linux.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/os/linux/os_linux.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -32,7 +32,6 @@ class os::Linux { friend class os; - static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *); static int (*_pthread_setname_np)(pthread_t, const char*); static address _initial_thread_stack_bottom; @@ -41,8 +40,6 @@ static const char *_libc_version; static const char *_libpthread_version; - static bool _supports_fast_thread_cpu_time; - static GrowableArray* _cpu_to_node; static GrowableArray* _nindex_to_node; @@ -80,6 +77,7 @@ static void print_proc_sys_info(outputStream* st); static bool print_ld_preload_file(outputStream* st); static void print_uptime_info(outputStream* st); + static bool print_numa_info(outputStream* st); public: struct CPUPerfTicks { @@ -145,18 +143,7 @@ static bool manually_expand_stack(JavaThread * t, address addr); static void expand_stack_to(address bottom); - // fast POSIX clocks support - static void fast_thread_clock_init(void); - - static int pthread_getcpuclockid(pthread_t tid, clockid_t *clock_id) { - return _pthread_getcpuclockid ? _pthread_getcpuclockid(tid, clock_id) : -1; - } - - static bool supports_fast_thread_cpu_time() { - return _supports_fast_thread_cpu_time; - } - - static jlong fast_thread_cpu_time(clockid_t clockid); + static jlong thread_cpu_time(clockid_t clockid); static jlong sendfile(int out_fd, int in_fd, jlong* offset, jlong count); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/os/windows/os_perf_windows.cpp openjdk-25-25.0.5+8/src/hotspot/os/windows/os_perf_windows.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/os/windows/os_perf_windows.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/os/windows/os_perf_windows.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -779,6 +779,114 @@ return OS_OK; } +// Look up the PDH index by reading the English (locale 009) counter name +// registry. See KB Q287159: Using PDH APIs Correctly in a Localized Language +// for details. +static OSReturn lookup_perf_index_by_english_name(const char* english_name, + DWORD* result) { + ResourceMark rm; + + DWORD type = 0; + DWORD size = 0; + + // Determine the required buffer size + if (RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Counter 009", + nullptr, &type, nullptr, &size) != ERROR_SUCCESS) { + return OS_ERR; + } + + // Since registry entries in `HKEY_PERFORMANCE_DATA` are generated on the fly, + // they could change between calls, so we can't rely just on the size returned + // by the first call. Instead, Microsoft's documentation suggests running + // these calls in a loop until the return code is no longer `ERROR_MORE_DATA`. + + char* buffer; + do { + if (size == 0) { + return OS_ERR; + } + + // When `RegQueryValueEx()` returns `ERROR_MORE_DATA`, the value in the + // callback argument is undefined, so we need to create a new variable whose + // address is passed as the callback size argument. + buffer = NEW_RESOURCE_ARRAY(char, size); + + DWORD cb_size = size; + LSTATUS status = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Counter 009", + nullptr, &type, (LPBYTE)buffer, + &cb_size); + if (status == ERROR_MORE_DATA) { + // We need to increase the buffer size. Since we don't know _how much_ to + // increase it by, we use an estimate (4096) for the increment. + DWORD increment = 4096; + if (size > MAXDWORD - increment) { + return OS_ERR; + } + size += increment; + } else if (status == ERROR_SUCCESS) { + break; + } else { + // If there was some other problem fetching this registry entry, tell the + // caller that we couldn't lookup the index. + return OS_ERR; + } + } while (true); + + if (type != REG_MULTI_SZ) { + return OS_ERR; + } + + // The buffer contains indices and names in the form (\0\0)*, so + // iterate character by character to parse the name and if it matches the + // English name, then we return the integer value of the index. + for (const char* p = buffer; *p != '\0'; ) { + const char* idx_str = p; + p += strlen(p) + 1; + if (*p == '\0') { + break; + } + + const char* name = p; + p += strlen(p) + 1; + if (strcmp(name, english_name) == 0) { + errno = 0; + char* end = nullptr; + unsigned long value = strtoul(idx_str, &end, 10); + if (errno == 0 && end != idx_str && value <= MAXDWORD) { + *result = (DWORD)value; + return OS_OK; + } + } + } + + return OS_ERR; +} + +// Return the counter index of the 'Processor Information' counter, if +// available, or else the 'Processor' counter. The former is aware of the +// possibility of multiple processor groups and thus provides a more accurate +// processor count whereas the latter serves as fallback. +static DWORD get_proc_counter() { + static DWORD pdh_idx = 0; + if (pdh_idx != 0) { + return pdh_idx; + } + + // Some APIs accept English counter names whereas others accept counter names + // in the specific user's locale. We determine the locale-specific name using + // the counter index, but to find the counter index, we use the English name + // of the counter and look for it in a specific registry key. + DWORD info_idx; + if (lookup_perf_index_by_english_name("Processor Information", + &info_idx) != OS_OK) { + info_idx = PDH_PROCESSOR_IDX; + } + + // Assign to the static variable so that the value persists across calls. + pdh_idx = info_idx; + return pdh_idx; +} + /* * Enuerate the Processor PDH object and returns a buffer containing the enumerated instances. * Caller needs ResourceMark; @@ -786,8 +894,11 @@ * @return buffer if successful, null on failure. */ static const char* enumerate_cpu_instances() { - char* processor; //'Processor' == PDH_PROCESSOR_IDX - if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) { + // The `PdhEnumObjectItems()` function accepts a localized name of the perf + // counter. To obtain the name that is specific to the user's locale, we + // perform a reverse lookup from counter index to counter name. + char* processor; + if (lookup_name_by_index(get_proc_counter(), &processor) != OS_OK) { return nullptr; } DWORD c_size = 0; @@ -821,13 +932,17 @@ static int count_logical_cpus(const char* instances) { assert(instances != nullptr, "invariant"); - // count logical instances. - DWORD count; - char* tmp; - for (count = 0, tmp = const_cast(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], count++); - // PDH reports an instance for each logical processor plus an instance for the total (_Total) - assert(count == os::processor_count() + 1, "invalid enumeration!"); - return count - 1; + DWORD count = 0; + for (const char* tmp = instances; *tmp != '\0'; tmp += strlen(tmp) + 1) { + // In both the 'Processor' counter and the 'Processor Information' counter, + // the output contains totals for the processor group(s). We filter those + // out by looking for the `_Total` substring. + if (strstr(tmp, "_Total") == nullptr) { + count++; + } + } + assert(count >= 1, "invalid enumeration!"); + return count; } static int number_of_logical_cpus() { @@ -847,7 +962,16 @@ static double cpuFactor = .0; if (numCpus == 0) { numCpus = number_of_logical_cpus(); - assert(os::processor_count() <= (int)numCpus, "invariant"); + + // If we are using the legacy 'Processor' counter, which counts processors + // only in the first processor group, then `numCpus` can undercount, in + // which case, `numCpus` will be likely smaller than `os_processor_count`. + // However, when we use the 'Processor Information' counter, we expect both + // `numCpus` and `os::processorCount` to be identical. In both cases, we + // expect to see at least one CPU. + assert(numCpus >= 1 && numCpus <= (DWORD)os::processor_count(), + "unexpected cpu count"); + cpuFactor = numCpus * 100; } return cpuFactor; @@ -861,8 +985,8 @@ static int initialize_cpu_query_counters(MultiCounterQueryP query, DWORD pdh_counter_idx) { assert(query != nullptr, "invariant"); assert(query->counters != nullptr, "invariant"); - char* processor; //'Processor' == PDH_PROCESSOR_IDX - if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) { + char* processor; + if (lookup_name_by_index(get_proc_counter(), &processor) != OS_OK) { return OS_ERR; } char* counter_name = nullptr; @@ -880,7 +1004,11 @@ counter_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN; // "\\%s(%s)\\%s" const char* instances = enumerate_cpu_instances(); DWORD index = 0; - for (char* tmp = const_cast(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], index++) { + for (char* tmp = const_cast(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1]) { + // Skip totals for each processor group. + if (strstr(tmp, ",_Total") != nullptr) { + continue; + } const size_t tmp_len = strlen(tmp); char* counter_path = NEW_RESOURCE_ARRAY(char, counter_len + tmp_len + 1); const size_t jio_snprintf_result = jio_snprintf(counter_path, @@ -896,6 +1024,7 @@ // return OS_OK to have the system continue to run without the missing counter return OS_OK; } + index++; } // Query once to initialize the counters which require at least two samples // (like the % CPU usage) to calculate correctly. diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/os/windows/os_windows.cpp openjdk-25-25.0.5+8/src/hotspot/os/windows/os_windows.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/os/windows/os_windows.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/os/windows/os_windows.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -2628,14 +2628,13 @@ DWORD exception_code = exception_record->ExceptionCode; #if defined(_M_ARM64) address pc = (address) exceptionInfo->ContextRecord->Pc; + + if (handle_safefetch(exception_code, pc, (void*)exceptionInfo->ContextRecord)) { + return EXCEPTION_CONTINUE_EXECUTION; + } #elif defined(_M_AMD64) address pc = (address) exceptionInfo->ContextRecord->Rip; -#else - #error unknown architecture -#endif - Thread* t = Thread::current_or_null_safe(); -#if defined(_M_AMD64) if ((exception_code == EXCEPTION_ACCESS_VIOLATION) && VM_Version::is_cpuinfo_segv_addr(pc)) { // Verify that OS save/restore AVX registers. @@ -2648,6 +2647,8 @@ VM_Version::clear_apx_test_state(); return Handle_Exception(exceptionInfo, VM_Version::cpuinfo_cont_addr_apx()); } +#else + #error unknown architecture #endif #ifdef CAN_SHOW_REGISTERS_ON_ASSERT @@ -2658,6 +2659,7 @@ } #endif + Thread* t = Thread::current_or_null_safe(); if (t != nullptr && t->is_Java_thread()) { JavaThread* thread = JavaThread::cast(t); bool in_java = thread->thread_state() == _thread_in_Java; @@ -2688,10 +2690,8 @@ // Fatal red zone violation. overflow_state->disable_stack_red_zone(); tty->print_raw_cr("An unrecoverable stack overflow has occurred."); -#if !defined(USE_VECTORED_EXCEPTION_HANDLING) report_error(t, exception_code, pc, exception_record, exceptionInfo->ContextRecord); -#endif return EXCEPTION_CONTINUE_SEARCH; } } else if (exception_code == EXCEPTION_ACCESS_VIOLATION) { @@ -2743,10 +2743,8 @@ } // Stack overflow or null pointer exception in native code. -#if !defined(USE_VECTORED_EXCEPTION_HANDLING) report_error(t, exception_code, pc, exception_record, exceptionInfo->ContextRecord); -#endif return EXCEPTION_CONTINUE_SEARCH; } // /EXCEPTION_ACCESS_VIOLATION // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2821,41 +2819,21 @@ } } -#if !defined(USE_VECTORED_EXCEPTION_HANDLING) - if (exception_code != EXCEPTION_BREAKPOINT) { - report_error(t, exception_code, pc, exception_record, - exceptionInfo->ContextRecord); - } -#endif - return EXCEPTION_CONTINUE_SEARCH; -} + bool should_report_error = (exception_code != EXCEPTION_BREAKPOINT); -#if defined(USE_VECTORED_EXCEPTION_HANDLING) -LONG WINAPI topLevelVectoredExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { - PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; #if defined(_M_ARM64) - address pc = (address) exceptionInfo->ContextRecord->Pc; -#elif defined(_M_AMD64) - address pc = (address) exceptionInfo->ContextRecord->Rip; -#else - #error unknown architecture + should_report_error = should_report_error && + FAILED(exception_code) && + (exception_code != EXCEPTION_UNCAUGHT_CXX_EXCEPTION); #endif - // Fast path for code part of the code cache - if (CodeCache::low_bound() <= pc && pc < CodeCache::high_bound()) { - return topLevelExceptionFilter(exceptionInfo); - } - - // If the exception occurred in the codeCache, pass control - // to our normal exception handler. - CodeBlob* cb = CodeCache::find_blob(pc); - if (cb != nullptr) { - return topLevelExceptionFilter(exceptionInfo); + if (should_report_error) { + report_error(t, exception_code, pc, exception_record, + exceptionInfo->ContextRecord); } return EXCEPTION_CONTINUE_SEARCH; } -#endif #if defined(USE_VECTORED_EXCEPTION_HANDLING) LONG WINAPI topLevelUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { @@ -4488,7 +4466,7 @@ // Setup Windows Exceptions #if defined(USE_VECTORED_EXCEPTION_HANDLING) - topLevelVectoredExceptionHandler = AddVectoredExceptionHandler(1, topLevelVectoredExceptionFilter); + topLevelVectoredExceptionHandler = AddVectoredExceptionHandler(1, topLevelExceptionFilter); previousUnhandledExceptionFilter = SetUnhandledExceptionFilter(topLevelUnhandledExceptionFilter); #endif diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/os/windows/os_windows.hpp openjdk-25-25.0.5+8/src/hotspot/os/windows/os_windows.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/os/windows/os_windows.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/os/windows/os_windows.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -150,6 +150,8 @@ // signal support static void* install_signal_handler(int sig, signal_handler_t handler); static void* user_handler(); + + static void context_set_pc(CONTEXT* uc, address pc); }; #endif // OS_WINDOWS_OS_WINDOWS_HPP diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/os/windows/safefetch_static_windows.cpp openjdk-25-25.0.5+8/src/hotspot/os/windows/safefetch_static_windows.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/os/windows/safefetch_static_windows.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/os/windows/safefetch_static_windows.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 SAP SE. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 "os_windows.hpp" +#include "runtime/os.hpp" +#include "runtime/safefetch.hpp" +#include "utilities/globalDefinitions.hpp" + +#ifdef SAFEFETCH_METHOD_STATIC_ASSEMBLY + +// SafeFetch handling, static assembly style: +// +// SafeFetch32 and SafeFetchN are implemented via static assembly +// and live in os_cpu/xx_xx/safefetch_xx_xx.S + +extern "C" char _SafeFetch32_continuation[]; +extern "C" char _SafeFetch32_fault[]; + +#ifdef _LP64 +extern "C" char _SafeFetchN_continuation[]; +extern "C" char _SafeFetchN_fault[]; +#endif // _LP64 + +bool handle_safefetch(int exception_code, address pc, void* context) { + CONTEXT* ctx = (CONTEXT*)context; + if (exception_code == EXCEPTION_ACCESS_VIOLATION && ctx != nullptr) { + if (pc == (address)_SafeFetch32_fault) { + os::win32::context_set_pc(ctx, (address)_SafeFetch32_continuation); + return true; + } +#ifdef _LP64 + if (pc == (address)_SafeFetchN_fault) { + os::win32::context_set_pc(ctx, (address)_SafeFetchN_continuation); + return true; + } +#endif + } + return false; +} + +#endif // SAFEFETCH_METHOD_STATIC_ASSEMBLY diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp openjdk-25-25.0.5+8/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -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. * Copyright (c) 2023, Rivos Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -167,13 +167,16 @@ void RiscvHwprobe::add_features_from_query_result() { assert(rw_hwprobe_completed, "hwprobe not init yet."); - if (is_valid(RISCV_HWPROBE_KEY_MVENDORID)) { + // For value-type keys, the kernel returns (uint64_t)-1 when CPUs in the + // query set disagree (different core types). Skip these as the value is + // not meaningful for the system as a whole. + if (is_valid(RISCV_HWPROBE_KEY_MVENDORID) && query[RISCV_HWPROBE_KEY_MVENDORID].value != (uint64_t)-1) { VM_Version::mvendorid.enable_feature(query[RISCV_HWPROBE_KEY_MVENDORID].value); } - if (is_valid(RISCV_HWPROBE_KEY_MARCHID)) { + if (is_valid(RISCV_HWPROBE_KEY_MARCHID) && query[RISCV_HWPROBE_KEY_MARCHID].value != (uint64_t)-1) { VM_Version::marchid.enable_feature(query[RISCV_HWPROBE_KEY_MARCHID].value); } - if (is_valid(RISCV_HWPROBE_KEY_MIMPID)) { + if (is_valid(RISCV_HWPROBE_KEY_MIMPID) && query[RISCV_HWPROBE_KEY_MIMPID].value != (uint64_t)-1) { VM_Version::mimpid.enable_feature(query[RISCV_HWPROBE_KEY_MIMPID].value); } if (is_set(RISCV_HWPROBE_KEY_BASE_BEHAVIOR, RISCV_HWPROBE_BASE_BEHAVIOR_IMA)) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp openjdk-25-25.0.5+8/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -115,6 +115,10 @@ return reinterpret_cast(uc->REG_BCP); } +void os::win32::context_set_pc(CONTEXT* uc, address pc) { + uc->Pc = (intptr_t)pc; +} + bool os::win32::get_frame_at_stack_banging_point(JavaThread* thread, struct _EXCEPTION_POINTERS* exceptionInfo, address pc, frame* fr) { PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/os_cpu/windows_aarch64/safefetch_windows_aarch64.S openjdk-25-25.0.5+8/src/hotspot/os_cpu/windows_aarch64/safefetch_windows_aarch64.S --- openjdk-25-25.0.4.1+1/src/hotspot/os_cpu/windows_aarch64/safefetch_windows_aarch64.S 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/os_cpu/windows_aarch64/safefetch_windows_aarch64.S 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,65 @@ +; +; Copyright (c) 2022 SAP SE. All rights reserved. +; Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. +; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +; +; This code is free software; you can redistribute it and/or modify it +; under the terms of the GNU General Public License version 2 only, as +; published by the Free Software Foundation. +; +; This code is distributed in the hope that it will be useful, but WITHOUT +; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +; version 2 for more details (a copy is included in the LICENSE file that +; accompanied this code). +; +; You should have received a copy of the GNU General Public License version +; 2 along with this work; if not, write to the Free Software Foundation, +; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +; +; Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +; or visit www.oracle.com if you need additional information or have any +; questions. +; + + ; Support for int SafeFetch32(int* address, int defaultval); + ; + ; x0 : address + ; w1 : defaultval + + ; needed to align function start to 4 byte + ALIGN 4 + EXPORT _SafeFetch32_fault + EXPORT _SafeFetch32_continuation + EXPORT SafeFetch32_impl + AREA safefetch_text, CODE + +SafeFetch32_impl +_SafeFetch32_fault + ldr w0, [x0] + ret + +_SafeFetch32_continuation + mov x0, x1 + ret + + ; Support for intptr_t SafeFetchN(intptr_t* address, intptr_t defaultval); + ; + ; x0 : address + ; x1 : defaultval + + ALIGN 4 + EXPORT _SafeFetchN_fault + EXPORT _SafeFetchN_continuation + EXPORT SafeFetchN_impl + +SafeFetchN_impl +_SafeFetchN_fault + ldr x0, [x0] + ret + +_SafeFetchN_continuation + mov x0, x1 + ret + + END diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/c1/c1_Compiler.cpp openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_Compiler.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/c1/c1_Compiler.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_Compiler.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -142,7 +142,7 @@ case vmIntrinsics::_arraycopy: case vmIntrinsics::_currentTimeMillis: case vmIntrinsics::_nanoTime: - case vmIntrinsics::_Reference_get: + case vmIntrinsics::_Reference_get0: // Use the intrinsic version of Reference.get() so that the value in // the referent field can be registered by the G1 pre-barrier code. // Also to prevent commoning reads from this field across safepoint diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/c1/c1_GraphBuilder.cpp openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_GraphBuilder.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/c1/c1_GraphBuilder.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_GraphBuilder.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -3341,7 +3341,7 @@ break; } - case vmIntrinsics::_Reference_get: + case vmIntrinsics::_Reference_get0: { { // With java.lang.ref.reference.get() we must go through the diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/c1/c1_LIRGenerator.cpp openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_LIRGenerator.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/c1/c1_LIRGenerator.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_LIRGenerator.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1185,7 +1185,7 @@ // Example: ref.get() // Combination of LoadField and g1 pre-write barrier -void LIRGenerator::do_Reference_get(Intrinsic* x) { +void LIRGenerator::do_Reference_get0(Intrinsic* x) { const int referent_offset = java_lang_ref_Reference::referent_offset(); @@ -2914,8 +2914,8 @@ case vmIntrinsics::_onSpinWait: __ on_spin_wait(); break; - case vmIntrinsics::_Reference_get: - do_Reference_get(x); + case vmIntrinsics::_Reference_get0: + do_Reference_get0(x); break; case vmIntrinsics::_updateCRC32: diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/c1/c1_LIRGenerator.hpp openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_LIRGenerator.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/c1/c1_LIRGenerator.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/c1/c1_LIRGenerator.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -266,7 +266,7 @@ void do_CompareAndSwap(Intrinsic* x, ValueType* type); void do_PreconditionsCheckIndex(Intrinsic* x, BasicType type); void do_FPIntrinsics(Intrinsic* x); - void do_Reference_get(Intrinsic* x); + void do_Reference_get0(Intrinsic* x); void do_update_CRC32(Intrinsic* x); void do_update_CRC32C(Intrinsic* x); void do_vectorizedMismatch(Intrinsic* x); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/cds/aotConstantPoolResolver.cpp openjdk-25-25.0.5+8/src/hotspot/share/cds/aotConstantPoolResolver.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/cds/aotConstantPoolResolver.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/cds/aotConstantPoolResolver.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -408,7 +408,7 @@ } bool AOTConstantPoolResolver::check_lambda_metafactory_methodtype_arg(ConstantPool* cp, int bsms_attribute_index, int arg_i) { - int mt_index = cp->operand_argument_index_at(bsms_attribute_index, arg_i); + int mt_index = cp->bsm_attribute_entry(bsms_attribute_index)->argument(arg_i); if (!cp->tag_at(mt_index).is_method_type()) { // malformed class? return false; @@ -424,7 +424,7 @@ } bool AOTConstantPoolResolver::check_lambda_metafactory_methodhandle_arg(ConstantPool* cp, int bsms_attribute_index, int arg_i) { - int mh_index = cp->operand_argument_index_at(bsms_attribute_index, arg_i); + int mh_index = cp->bsm_attribute_entry(bsms_attribute_index)->argument(arg_i); if (!cp->tag_at(mh_index).is_method_handle()) { // malformed class? return false; @@ -563,7 +563,7 @@ } int bsms_attribute_index = cp->bootstrap_methods_attribute_index(cp_index); - int arg_count = cp->operand_argument_count_at(bsms_attribute_index); + int arg_count = cp->bsm_attribute_entry(bsms_attribute_index)->argument_count(); if (arg_count != 3) { // Malformed class? return false; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/cds/filemap.cpp openjdk-25-25.0.5+8/src/hotspot/share/cds/filemap.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/cds/filemap.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/cds/filemap.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1317,6 +1317,13 @@ return false; } else { assert(mapped_base == requested_base, "must be"); + + if (VerifySharedSpaces && !r->check_region_crc(mapped_base)) { + aot_log_error(aot)("region %d CRC error", MetaspaceShared::ac); + os::unmap_memory(mapped_base, r->used_aligned()); + return false; + } + r->set_mapped_from_file(true); r->set_mapped_base(mapped_base); aot_log_info(aot)("Mapped static region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/classFileParser.cpp openjdk-25-25.0.5+8/src/hotspot/share/classfile/classFileParser.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/classFileParser.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/classfile/classFileParser.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -47,6 +47,7 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/annotations.hpp" +#include "oops/bsmAttribute.inline.hpp" #include "oops/constantPool.inline.hpp" #include "oops/fieldInfo.hpp" #include "oops/fieldStreams.inline.hpp" @@ -3270,8 +3271,9 @@ TRAPS) { assert(cfs != nullptr, "invariant"); assert(cp != nullptr, "invariant"); + const int cp_size = cp->length(); - const u1* const current_start = cfs->current(); + const u1* const current_before_parsing = cfs->current(); guarantee_property(attribute_byte_length >= sizeof(u2), "Invalid BootstrapMethods attribute length %u in class file %s", @@ -3280,57 +3282,40 @@ cfs->guarantee_more(attribute_byte_length, CHECK); - const int attribute_array_length = cfs->get_u2_fast(); + const int num_bootstrap_methods = cfs->get_u2_fast(); - guarantee_property(_max_bootstrap_specifier_index < attribute_array_length, + guarantee_property(_max_bootstrap_specifier_index < num_bootstrap_methods, "Short length on BootstrapMethods in class file %s", CHECK); + const u4 bootstrap_methods_u2_len = (attribute_byte_length - sizeof(u2)) / sizeof(u2); - // The attribute contains a counted array of counted tuples of shorts, - // represending bootstrap specifiers: - // length*{bootstrap_method_index, argument_count*{argument_index}} - const unsigned int operand_count = (attribute_byte_length - (unsigned)sizeof(u2)) / (unsigned)sizeof(u2); - // operand_count = number of shorts in attr, except for leading length - - // The attribute is copied into a short[] array. - // The array begins with a series of short[2] pairs, one for each tuple. - const int index_size = (attribute_array_length * 2); - - Array* const operands = - MetadataFactory::new_array(_loader_data, index_size + operand_count, CHECK); - - // Eagerly assign operands so they will be deallocated with the constant + // Eagerly assign the arrays so that they will be deallocated with the constant // pool if there is an error. - cp->set_operands(operands); + BSMAttributeEntries::InsertionIterator iter = + cp->bsm_entries().start_extension(num_bootstrap_methods, + bootstrap_methods_u2_len, + _loader_data, + CHECK); - int operand_fill_index = index_size; - const int cp_size = cp->length(); - - for (int n = 0; n < attribute_array_length; n++) { - // Store a 32-bit offset into the header of the operand array. - ConstantPool::operand_offset_at_put(operands, n, operand_fill_index); - - // Read a bootstrap specifier. + for (int i = 0; i < num_bootstrap_methods; i++) { cfs->guarantee_more(sizeof(u2) * 2, CHECK); // bsm, argc - const u2 bootstrap_method_index = cfs->get_u2_fast(); - const u2 argument_count = cfs->get_u2_fast(); + u2 bootstrap_method_ref = cfs->get_u2_fast(); + u2 num_bootstrap_arguments = cfs->get_u2_fast(); guarantee_property( - valid_cp_range(bootstrap_method_index, cp_size) && - cp->tag_at(bootstrap_method_index).is_method_handle(), - "bootstrap_method_index %u has bad constant type in class file %s", - bootstrap_method_index, - CHECK); - - guarantee_property((operand_fill_index + 1 + argument_count) < operands->length(), - "Invalid BootstrapMethods num_bootstrap_methods or num_bootstrap_arguments value in class file %s", - CHECK); - - operands->at_put(operand_fill_index++, bootstrap_method_index); - operands->at_put(operand_fill_index++, argument_count); + valid_cp_range(bootstrap_method_ref, cp_size) && + cp->tag_at(bootstrap_method_ref).is_method_handle(), + "bootstrap_method_index %u has bad constant type in class file %s", + bootstrap_method_ref, + CHECK); + cfs->guarantee_more(sizeof(u2) * num_bootstrap_arguments, CHECK); // argv[argc] + + BSMAttributeEntry* entry = iter.reserve_new_entry(bootstrap_method_ref, num_bootstrap_arguments); + guarantee_property(entry != nullptr, + "Invalid BootstrapMethods num_bootstrap_methods." + " The total amount of space reserved for the BootstrapMethod attribute was not sufficient", CHECK); - cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc] - for (int j = 0; j < argument_count; j++) { + for (int argi = 0; argi < num_bootstrap_arguments; argi++) { const u2 argument_index = cfs->get_u2_fast(); guarantee_property( valid_cp_range(argument_index, cp_size) && @@ -3338,10 +3323,11 @@ "argument_index %u has bad constant type in class file %s", argument_index, CHECK); - operands->at_put(operand_fill_index++, argument_index); + entry->set_argument(argi, argument_index); } } - guarantee_property(current_start + attribute_byte_length == cfs->current(), + cp->bsm_entries().end_extension(iter, _loader_data, CHECK); + guarantee_property(current_before_parsing + attribute_byte_length == cfs->current(), "Bad length on BootstrapMethods in class file %s", CHECK); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/stringTable.cpp openjdk-25-25.0.5+8/src/hotspot/share/classfile/stringTable.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/stringTable.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/classfile/stringTable.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -615,6 +615,10 @@ }; void StringTable::clean_dead_entries(JavaThread* jt) { + // BulkDeleteTask::prepare() may take ConcurrentHashTableResize_lock (nosafepoint-2). + // When NativeHeapTrimmer is enabled, SuspendMark may take NativeHeapTrimmer::_lock (nosafepoint). + // Take SuspendMark first to keep lock order and avoid deadlock. + NativeHeapTrimmer::SuspendMark sm("stringtable"); StringTableHash::BulkDeleteTask bdt(_local_table); if (!bdt.prepare(jt)) { return; @@ -622,7 +626,6 @@ StringTableDeleteCheck stdc; StringTableDoDelete stdd; - NativeHeapTrimmer::SuspendMark sm("stringtable"); { TraceTime timer("Clean", TRACETIME_LOG(Debug, stringtable, perf)); while(bdt.do_task(jt, stdc, stdd)) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/symbolTable.cpp openjdk-25-25.0.5+8/src/hotspot/share/classfile/symbolTable.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/symbolTable.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/classfile/symbolTable.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -765,6 +765,10 @@ }; void SymbolTable::clean_dead_entries(JavaThread* jt) { + // BulkDeleteTask::prepare() may take ConcurrentHashTableResize_lock (nosafepoint-2). + // When NativeHeapTrimmer is enabled, SuspendMark may take NativeHeapTrimmer::_lock (nosafepoint). + // Take SuspendMark first to keep lock order and avoid deadlock. + NativeHeapTrimmer::SuspendMark sm("symboltable"); SymbolTableHash::BulkDeleteTask bdt(_local_table); if (!bdt.prepare(jt)) { return; @@ -772,7 +776,6 @@ SymbolTableDeleteCheck stdc; SymbolTableDoDelete stdd; - NativeHeapTrimmer::SuspendMark sm("symboltable"); { TraceTime timer("Clean", TRACETIME_LOG(Debug, symboltable, perf)); while (bdt.do_task(jt, stdc, stdd)) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/vmIntrinsics.cpp openjdk-25-25.0.5+8/src/hotspot/share/classfile/vmIntrinsics.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/vmIntrinsics.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/classfile/vmIntrinsics.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -99,7 +99,7 @@ case vmIntrinsics::_dpow: case vmIntrinsics::_Preconditions_checkIndex: case vmIntrinsics::_Preconditions_checkLongIndex: - case vmIntrinsics::_Reference_get: + case vmIntrinsics::_Reference_get0: case vmIntrinsics::_Continuation_doYield: case vmIntrinsics::_updateCRC32: case vmIntrinsics::_updateBytesCRC32: @@ -244,7 +244,7 @@ case vmIntrinsics::_storeFence: case vmIntrinsics::_fullFence: case vmIntrinsics::_countPositives: - case vmIntrinsics::_Reference_get: + case vmIntrinsics::_Reference_get0: case vmIntrinsics::_Continuation_doYield: case vmIntrinsics::_Continuation_enterSpecial: case vmIntrinsics::_Continuation_pin: diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/vmIntrinsics.hpp openjdk-25-25.0.5+8/src/hotspot/share/classfile/vmIntrinsics.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/vmIntrinsics.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/classfile/vmIntrinsics.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -461,7 +461,7 @@ do_signature(vectorizedMismatch_signature, "(Ljava/lang/Object;JLjava/lang/Object;JII)I") \ \ /* java/lang/ref/Reference */ \ - do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \ + do_intrinsic(_Reference_get0, java_lang_ref_Reference, get0_name, void_object_signature, F_RN) \ do_intrinsic(_Reference_refersTo0, java_lang_ref_Reference, refersTo0_name, object_boolean_signature, F_RN) \ do_intrinsic(_PhantomReference_refersTo0, java_lang_ref_PhantomReference, refersTo0_name, object_boolean_signature, F_RN) \ do_intrinsic(_Reference_clear0, java_lang_ref_Reference, clear0_name, void_method_signature, F_RN) \ diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/vmSymbols.hpp openjdk-25-25.0.5+8/src/hotspot/share/classfile/vmSymbols.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/classfile/vmSymbols.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/classfile/vmSymbols.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -422,7 +422,7 @@ template(sp_name, "sp") \ template(pc_name, "pc") \ template(cs_name, "cs") \ - template(get_name, "get") \ + template(get0_name, "get0") \ template(refersTo0_name, "refersTo0") \ template(clear0_name, "clear0") \ template(put_name, "put") \ diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/code/aotCodeCache.cpp openjdk-25-25.0.5+8/src/hotspot/share/code/aotCodeCache.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/code/aotCodeCache.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/code/aotCodeCache.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -141,6 +141,11 @@ return; // AOTCache must be specified to dump and use AOT code } + // Disable adapters caching which requires CPU features matching checks + // (implemented by JDK-8377507 and JDK-8381975) which we don't + // have in this version of code. + FLAG_SET_ERGO_IF_DEFAULT(AOTAdapterCaching, false); + // Disable stubs caching until JDK-8357398 is fixed. FLAG_SET_ERGO(AOTStubCaching, false); @@ -158,14 +163,11 @@ bool is_dumping = false; bool is_using = false; if (CDSConfig::is_dumping_final_static_archive() && CDSConfig::is_dumping_aot_linked_classes()) { - FLAG_SET_ERGO_IF_DEFAULT(AOTAdapterCaching, true); - FLAG_SET_ERGO_IF_DEFAULT(AOTStubCaching, true); is_dumping = true; } else if (CDSConfig::is_using_archive() && CDSConfig::is_using_aot_linked_classes()) { - FLAG_SET_ERGO_IF_DEFAULT(AOTAdapterCaching, true); - FLAG_SET_ERGO_IF_DEFAULT(AOTStubCaching, true); is_using = true; } else { + FLAG_SET_ERGO(AOTAdapterCaching, false); log_info(aot, codecache, init)("AOT Code Cache is not used: AOT Class Linking is not used."); return; // nothing to do } @@ -1334,7 +1336,7 @@ SET_ADDRESS(_extrs, G1BarrierSetRuntime::write_ref_field_pre_entry); #endif #if INCLUDE_SHENANDOAHGC - SET_ADDRESS(_extrs, ShenandoahRuntime::write_ref_field_pre); + SET_ADDRESS(_extrs, ShenandoahRuntime::write_barrier_pre); SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom); SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom_narrow); #endif diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/compiler/compilationPolicy.cpp openjdk-25-25.0.5+8/src/hotspot/share/compiler/compilationPolicy.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/compiler/compilationPolicy.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/compiler/compilationPolicy.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1430,7 +1430,7 @@ // Determine if a method should be compiled with a normal entry point at a different level. CompLevel CompilationPolicy::call_event(const methodHandle& method, CompLevel cur_level, JavaThread* THREAD) { CompLevel osr_level = MIN2((CompLevel) method->highest_osr_comp_level(), common(method, cur_level, THREAD, true)); - CompLevel next_level = common(method, cur_level, THREAD, !TrainingData::have_data() && is_old(method)); + CompLevel next_level = common(method, cur_level, THREAD, is_old(method)); // If OSR method level is greater than the regular method level, the levels should be // equalized by raising the regular method level in order to avoid OSRs during each diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,8 +50,8 @@ // stall. We'll try to prefetch the object (for write, given that // we might need to install the forwarding reference) and we'll // get back to it when pop it from the queue - Prefetch::write(obj->mark_addr(), 0); - Prefetch::read(obj->mark_addr(), (HeapWordSize*2)); + Prefetch::write(obj->base_addr(), oopDesc::mark_offset_in_bytes()); + Prefetch::read(obj->base_addr(), oopDesc::mark_offset_in_bytes() + (HeapWordSize*2)); // slightly paranoid test; I'm trying to catch potential // problems before we go into push_on_queue to know where the diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ if (PSScavenge::is_obj_in_young(heap_oop)) { oop obj = CompressedOops::decode_not_null(heap_oop); assert(!PSScavenge::is_obj_in_to_space(obj), "revisiting object?"); - Prefetch::write(obj->mark_addr(), 0); + Prefetch::write(obj->base_addr(), oopDesc::mark_offset_in_bytes()); push_depth(ScannerTask(p)); } } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -133,7 +133,6 @@ addr = ensure_in_register(gen, addr, T_ADDRESS); assert(addr->is_register(), "must be a register at this point"); LIR_Opr result = gen->result_register_for(obj->value_type()); - __ move(obj, result); LIR_Opr tmp1 = gen->new_register(T_ADDRESS); LIR_Opr tmp2 = gen->new_register(T_ADDRESS); @@ -164,6 +163,11 @@ CodeStub* slow = new ShenandoahLoadReferenceBarrierStub(obj, addr, result, tmp1, tmp2, decorators); __ branch(lir_cond_notEqual, slow); + + // No barrier is needed, move obj to result now. + __ move(obj, result); + + // Slow-path re-enters here with result set. __ branch_destination(slow->continuation()); return result; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -127,6 +127,7 @@ visitor->do_input(_addr); visitor->do_temp(_addr); visitor->do_temp(_result); + visitor->do_output(_result); visitor->do_temp(_tmp1); visitor->do_temp(_tmp2); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -250,9 +250,8 @@ } __ else_(); { // logging buffer is full, call the runtime - const TypeFunc *tf = ShenandoahBarrierSetC2::write_ref_field_pre_Type(); - __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), "shenandoah_wb_pre", - pre_val, tls); + const TypeFunc *tf = ShenandoahBarrierSetC2::write_barrier_pre_Type(); + __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), "shenandoah_wb_pre", pre_val); } __ end_if(); // (!index) } __ end_if(); // (pre_val != nullptr) } __ end_if(); // (!marking) @@ -270,7 +269,7 @@ bool ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(Node* call) { return call->is_CallLeaf() && - call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre); + call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre); } bool ShenandoahBarrierSetC2::is_shenandoah_clone_call(Node* call) { @@ -520,11 +519,10 @@ #undef __ -const TypeFunc* ShenandoahBarrierSetC2::write_ref_field_pre_Type() { - const Type **fields = TypeTuple::fields(2); +const TypeFunc* ShenandoahBarrierSetC2::write_barrier_pre_Type() { + const Type **fields = TypeTuple::fields(1); fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value - fields[TypeFunc::Parms+1] = TypeRawPtr::NOTNULL; // thread - const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields); + const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields); // create result type (range) fields = TypeTuple::fields(0); @@ -1108,7 +1106,7 @@ Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_reshape) const { if (is_shenandoah_wb_pre_call(n)) { - uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_Type()->domain()->cnt(); + uint cnt = ShenandoahBarrierSetC2::write_barrier_pre_Type()->domain()->cnt(); if (n->req() > cnt) { Node* addp = n->in(cnt); if (has_only_shenandoah_wb_pre_uses(addp)) { @@ -1194,7 +1192,7 @@ assert (n->is_Call(), ""); CallNode *call = n->as_Call(); if (ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(call)) { - uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_Type()->domain()->cnt(); + uint cnt = ShenandoahBarrierSetC2::write_barrier_pre_Type()->domain()->cnt(); if (call->req() > cnt) { assert(call->req() == cnt + 1, "only one extra input"); Node *addp = call->in(cnt); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -103,7 +103,7 @@ ShenandoahBarrierSetC2State* state() const; - static const TypeFunc* write_ref_field_pre_Type(); + static const TypeFunc* write_barrier_pre_Type(); static const TypeFunc* clone_barrier_Type(); static const TypeFunc* load_reference_barrier_Type(); virtual bool has_load_barrier_nodes() const { return true; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -30,6 +30,7 @@ #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "memory/resourceArea.hpp" +#include "runtime/orderAccess.hpp" void print_raw_memory(ShenandoahMessageBuffer &msg, void* loc) { // Be extra safe. Only access data that is guaranteed to be safe: @@ -381,6 +382,15 @@ } } +void ShenandoahAsserts::assert_bitmap_clear_above_top(ShenandoahHeapRegion* region) { + ShenandoahMarkingContext* const ctx = ShenandoahHeap::heap()->marking_context(); + const HeapWord* top_bitmap = ctx->top_bitmap(region); + // Make sure that top is loaded before any of the marks from the bitmap are loaded. If another + // thread has cleared the bitmap we must not allow any stale reads. + OrderAccess::loadload(); + assert(ctx->is_bitmap_range_within_region_clear(top_bitmap, region->end()), "Bitmap above top_bitmap() must be clear"); +} + void ShenandoahAsserts::assert_in_cset(void* interior_loc, oop obj, const char* file, int line) { assert_correct(interior_loc, obj, file, line); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -30,6 +30,8 @@ #include "runtime/mutex.hpp" #include "utilities/formatBuffer.hpp" +class ShenandoahHeapRegion; + typedef FormatBuffer<8192> ShenandoahMessageBuffer; class ShenandoahAsserts { @@ -64,6 +66,7 @@ static void assert_marked(void* interior_loc, oop obj, const char* file, int line); static void assert_marked_weak(void* interior_loc, oop obj, const char* file, int line); static void assert_marked_strong(void* interior_loc, oop obj, const char* file, int line); + static void assert_bitmap_clear_above_top(ShenandoahHeapRegion* region); static void assert_in_cset(void* interior_loc, oop obj, const char* file, int line); static void assert_not_in_cset(void* interior_loc, oop obj, const char* file, int line); static void assert_not_in_cset_loc(void* interior_loc, const char* file, int line); @@ -127,6 +130,9 @@ #define shenandoah_assert_marked_strong(interior_loc, obj) \ ShenandoahAsserts::assert_marked_strong(interior_loc, obj, __FILE__, __LINE__) +#define shenandoah_assert_clear_above_top(region) \ + ShenandoahAsserts::assert_bitmap_clear_above_top(region) + #define shenandoah_assert_in_cset_if(interior_loc, obj, condition) \ if (condition) ShenandoahAsserts::assert_in_cset(interior_loc, obj, __FILE__, __LINE__) #define shenandoah_assert_in_cset_except(interior_loc, obj, exception) \ @@ -211,6 +217,7 @@ #define shenandoah_assert_marked_strong_except(interior_loc, obj, exception) #define shenandoah_assert_marked_strong(interior_loc, obj) +#define shenandoah_assert_clear_above_top(region) #define shenandoah_assert_in_cset_if(interior_loc, obj, condition) #define shenandoah_assert_in_cset_except(interior_loc, obj, exception) #define shenandoah_assert_in_cset(interior_loc, obj) diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -72,21 +72,33 @@ bool ShenandoahBarrierSet::need_load_reference_barrier(DecoratorSet decorators, BasicType type) { if (!ShenandoahLoadRefBarrier) return false; - // Only needed for references return is_reference_type(type); } bool ShenandoahBarrierSet::need_keep_alive_barrier(DecoratorSet decorators, BasicType type) { if (!ShenandoahSATBBarrier) return false; - // Only needed for references if (!is_reference_type(type)) return false; - bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; bool unknown = (decorators & ON_UNKNOWN_OOP_REF) != 0; bool on_weak_ref = (decorators & (ON_WEAK_OOP_REF | ON_PHANTOM_OOP_REF)) != 0; return (on_weak_ref || unknown) && keep_alive; } +bool ShenandoahBarrierSet::need_satb_barrier(DecoratorSet decorators, BasicType type) { + if (!ShenandoahSATBBarrier) return false; + if (!is_reference_type(type)) return false; + bool as_normal = (decorators & AS_NORMAL) != 0; + bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; + return as_normal && !dest_uninitialized; +} + +bool ShenandoahBarrierSet::need_card_barrier(DecoratorSet decorators, BasicType type) { + if (!ShenandoahCardBarrier) return false; + if (!is_reference_type(type)) return false; + bool in_heap = (decorators & IN_HEAP) != 0; + return in_heap; +} + void ShenandoahBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { #if COMPILER2_OR_JVMCI if (ReduceInitialCardMarks && ShenandoahCardBarrier && !ShenandoahHeap::heap()->is_in_young(new_obj)) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -60,6 +60,8 @@ static bool need_load_reference_barrier(DecoratorSet decorators, BasicType type); static bool need_keep_alive_barrier(DecoratorSet decorators, BasicType type); + static bool need_satb_barrier(DecoratorSet decorators, BasicType type); + static bool need_card_barrier(DecoratorSet decorators, BasicType type); static bool is_strong_access(DecoratorSet decorators) { return (decorators & (ON_WEAK_OOP_REF | ON_PHANTOM_OOP_REF)) == 0; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -181,9 +181,6 @@ }; class ShenandoahNMethodAndDisarmClosure : public NMethodToOopClosure { -private: - BarrierSetNMethod* const _bs; - public: inline ShenandoahNMethodAndDisarmClosure(OopClosure* cl); inline void do_nmethod(nmethod* nm); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -209,15 +209,13 @@ } ShenandoahNMethodAndDisarmClosure::ShenandoahNMethodAndDisarmClosure(OopClosure* cl) : - NMethodToOopClosure(cl, true /* fix_relocations */), - _bs(BarrierSet::barrier_set()->barrier_set_nmethod()) { -} + NMethodToOopClosure(cl, true /* fix_relocations */) {} void ShenandoahNMethodAndDisarmClosure::do_nmethod(nmethod* nm) { assert(nm != nullptr, "Sanity"); assert(!ShenandoahNMethod::gc_data(nm)->is_unregistered(), "Should not be here"); NMethodToOopClosure::do_nmethod(nm); - _bs->disarm(nm); + ShenandoahNMethod::disarm_nmethod(nm); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -40,20 +40,6 @@ ShenandoahNMethodTable* ShenandoahCodeRoots::_nmethod_table; int ShenandoahCodeRoots::_disarmed_value = 1; -bool ShenandoahCodeRoots::use_nmethod_barriers_for_mark() { - // Continuations need nmethod barriers for scanning stack chunk nmethods. - if (Continuations::enabled()) return true; - - // Concurrent class unloading needs nmethod barriers. - // When a nmethod is about to be executed, we need to make sure that all its - // metadata are marked. The alternative is to remark thread roots at final mark - // pause, which would cause latency issues. - if (ShenandoahHeap::heap()->unload_classes()) return true; - - // Otherwise, we can go without nmethod barriers. - return false; -} - void ShenandoahCodeRoots::initialize() { _nmethod_table = new ShenandoahNMethodTable(); } @@ -68,27 +54,14 @@ _nmethod_table->unregister_nmethod(nm); } -void ShenandoahCodeRoots::arm_nmethods_for_mark() { - if (use_nmethod_barriers_for_mark()) { - BarrierSet::barrier_set()->barrier_set_nmethod()->arm_all_nmethods(); - } -} - -void ShenandoahCodeRoots::arm_nmethods_for_evac() { +void ShenandoahCodeRoots::arm_nmethods() { BarrierSet::barrier_set()->barrier_set_nmethod()->arm_all_nmethods(); } class ShenandoahDisarmNMethodClosure : public NMethodClosure { -private: - BarrierSetNMethod* const _bs; - public: - ShenandoahDisarmNMethodClosure() : - _bs(BarrierSet::barrier_set()->barrier_set_nmethod()) { - } - virtual void do_nmethod(nmethod* nm) { - _bs->disarm(nm); + ShenandoahNMethod::disarm_nmethod(nm); } }; @@ -111,10 +84,8 @@ }; void ShenandoahCodeRoots::disarm_nmethods() { - if (use_nmethod_barriers_for_mark()) { - ShenandoahDisarmNMethodsTask task; - ShenandoahHeap::heap()->workers()->run_task(&task); - } + ShenandoahDisarmNMethodsTask task; + ShenandoahHeap::heap()->workers()->run_task(&task); } class ShenandoahNMethodUnlinkClosure : public NMethodClosure { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -67,14 +67,11 @@ // Concurrent nmethod unloading support static void unlink(WorkerThreads* workers, bool unloading_occurred); static void purge(); - static void arm_nmethods_for_mark(); - static void arm_nmethods_for_evac(); + static void arm_nmethods(); static void disarm_nmethods(); static int disarmed_value() { return _disarmed_value; } static int* disarmed_value_address() { return &_disarmed_value; } - static bool use_nmethod_barriers_for_mark(); - private: static ShenandoahNMethodTable* _nmethod_table; static int _disarmed_value; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -739,9 +739,8 @@ // Make above changes visible to worker threads OrderAccess::fence(); - // Arm nmethods for concurrent mark - ShenandoahCodeRoots::arm_nmethods_for_mark(); - + // Arm nmethods/stack for concurrent processing + ShenandoahCodeRoots::arm_nmethods(); ShenandoahStackWatermark::change_epoch_id(); if (ShenandoahPacing) { heap->pacer()->setup_for_mark(); @@ -803,7 +802,7 @@ heap->set_has_forwarded_objects(true); // Arm nmethods/stack for concurrent processing - ShenandoahCodeRoots::arm_nmethods_for_evac(); + ShenandoahCodeRoots::arm_nmethods(); ShenandoahStackWatermark::change_epoch_id(); if (ShenandoahPacing) { @@ -1033,14 +1032,10 @@ class ShenandoahEvacUpdateCodeCacheClosure : public NMethodClosure { private: - BarrierSetNMethod* const _bs; ShenandoahEvacuateUpdateMetadataClosure _cl; public: - ShenandoahEvacUpdateCodeCacheClosure() : - _bs(BarrierSet::barrier_set()->barrier_set_nmethod()), - _cl() { - } + ShenandoahEvacUpdateCodeCacheClosure() : _cl() {} void do_nmethod(nmethod* n) { ShenandoahNMethod* data = ShenandoahNMethod::gc_data(n); @@ -1048,8 +1043,8 @@ // Setup EvacOOM scope below reentrant lock to avoid deadlock with // nmethod_entry_barrier ShenandoahEvacOOMScope oom; - data->oops_do(&_cl, true/*fix relocation*/); - _bs->disarm(n); + data->oops_do(&_cl, /* fix_relocations = */ true); + ShenandoahNMethod::disarm_nmethod(n); } }; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -307,22 +307,25 @@ } bool ShenandoahControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) { + // Only read the cancellation cause once. Other threads may change it. ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (heap->cancelled_gc()) { - if (heap->cancelled_cause() == GCCause::_shenandoah_stop_vm) { - return true; - } + const GCCause::Cause cancelled_cause = heap->cancelled_cause(); + if (cancelled_cause == GCCause::_no_gc) { + return false; + } - if (ShenandoahCollectorPolicy::is_allocation_failure(heap->cancelled_cause())) { - assert (_degen_point == ShenandoahGC::_degenerated_outside_cycle, - "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); - _degen_point = point; - return true; - } + if (cancelled_cause == GCCause::_shenandoah_stop_vm) { + return true; + } - fatal("Unexpected reason for cancellation: %s", GCCause::to_string(heap->cancelled_cause())); + if (ShenandoahCollectorPolicy::is_allocation_failure(cancelled_cause)) { + assert (_degen_point == ShenandoahGC::_degenerated_outside_cycle, + "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); + _degen_point = point; + return true; } - return false; + + fatal("Unexpected reason for cancellation: %s", GCCause::to_string(cancelled_cause)); } void ShenandoahControlThread::stop_service() { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -184,3 +184,7 @@ _threads_in_evac[i].clear(); } } + +bool ShenandoahEvacOOMHandler::is_active() { + return ShenandoahThreadLocalData::evac_oom_scope_level(Thread::current()) > 0; +} diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -146,6 +146,11 @@ void clear(); + /** + * Returns true if current thread is in evacuation OOM protocol. + */ + static bool is_active(); + private: // Register/Unregister thread to evacuation OOM protocol void register_thread(Thread* t); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,7 +1,7 @@ /* * Copyright (c) 2016, 2021, Red Hat, Inc. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,6 @@ #include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" -#include "runtime/orderAccess.hpp" static const char* partition_name(ShenandoahFreeSetPartitionId t) { switch (t) { @@ -1049,11 +1048,10 @@ } _heap->generation_for(r->affiliation())->increment_affiliated_region_count(); -#ifdef ASSERT - ShenandoahMarkingContext* const ctx = _heap->marking_context(); - assert(ctx->top_at_mark_start(r) == r->bottom(), "Newly established allocation region starts with TAMS equal to bottom"); - assert(ctx->is_bitmap_range_within_region_clear(ctx->top_bitmap(r), r->end()), "Bitmap above top_bitmap() must be clear"); -#endif + + assert(_heap->marking_context()->top_at_mark_start(r) == r->bottom(), + "Newly established allocation region (%zu) must start with TAMS equal to bottom", r->index()); + shenandoah_assert_clear_above_top(r); log_debug(gc, free)("Using new region (%zu) for %s (" PTR_FORMAT ").", r->index(), ShenandoahAllocRequest::alloc_type_to_string(req.type()), p2i(&req)); } else { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -581,28 +581,31 @@ } bool ShenandoahGenerationalControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) { - if (!_heap->cancelled_gc()) { + // Only read the cancellation cause once. Other threads may change it. + const GCCause::Cause cancelled_cause = _heap->cancelled_cause(); + if (cancelled_cause == GCCause::_no_gc) { return false; } - if (_heap->cancelled_cause() == GCCause::_shenandoah_stop_vm - || _heap->cancelled_cause() == GCCause::_shenandoah_concurrent_gc) { - log_debug(gc, thread)("Cancellation detected, reason: %s", GCCause::to_string(_heap->cancelled_cause())); + if (cancelled_cause == GCCause::_shenandoah_stop_vm + || cancelled_cause == GCCause::_shenandoah_concurrent_gc) { + log_debug(gc, thread)("Cancellation detected, reason: %s", GCCause::to_string(cancelled_cause)); return true; } - if (ShenandoahCollectorPolicy::is_allocation_failure(_heap->cancelled_cause())) { + if (ShenandoahCollectorPolicy::is_allocation_failure(cancelled_cause)) { assert(_degen_point == ShenandoahGC::_degenerated_unset, "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + _requested_gc_cause = cancelled_cause; _degen_point = point; log_debug(gc, thread)("Cancellation detected:, reason: %s, degen point: %s", - GCCause::to_string(_heap->cancelled_cause()), + GCCause::to_string(cancelled_cause), ShenandoahGC::degen_point_to_string(_degen_point)); return true; } fatal("Cancel GC either for alloc failure GC, or gracefully exiting, or to pause old generation marking"); - return false; } void ShenandoahGenerationalControlThread::service_stw_full_cycle(GCCause::Cause cause) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -80,7 +80,6 @@ promote_regions(); } else { assert(!ShenandoahHeap::heap()->collection_set()->is_empty(), "Should have a collection set here"); - ShenandoahEvacOOMScope oom_evac_scope; evacuate_and_promote_regions(); } } @@ -124,6 +123,7 @@ if (r->is_cset()) { assert(r->has_live(), "Region %zu should have been reclaimed early", r->index()); + ShenandoahEvacOOMScope oom_evac_scope; _heap->marked_object_iterate(r, &cl); if (ShenandoahPacing) { _heap->pacer()->report_evac(r->used() >> LogHeapWordSize); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1190,11 +1190,9 @@ if (_concurrent) { ShenandoahConcurrentWorkerSession worker_session(worker_id); ShenandoahSuspendibleThreadSetJoiner stsj; - ShenandoahEvacOOMScope oom_evac_scope; do_work(); } else { ShenandoahParallelWorkerSession worker_session(worker_id); - ShenandoahEvacOOMScope oom_evac_scope; do_work(); } } @@ -1205,7 +1203,10 @@ ShenandoahHeapRegion* r; while ((r =_cs->claim_next()) != nullptr) { assert(r->has_live(), "Region %zu should have been reclaimed early", r->index()); - _sh->marked_object_iterate(r, &cl); + { + ShenandoahEvacOOMScope oom_evac_scope; + _sh->marked_object_iterate(r, &cl); + } if (ShenandoahPacing) { _sh->pacer()->report_evac(r->used() >> LogHeapWordSize); @@ -2223,8 +2224,18 @@ } bool ShenandoahHeap::try_cancel_gc(GCCause::Cause cause) { - const GCCause::Cause prev = _cancelled_gc.xchg(cause); - return prev == GCCause::_no_gc || prev == GCCause::_shenandoah_concurrent_gc; + while (true) { + const GCCause::Cause prev = _cancelled_gc.get(); + if (prev != GCCause::_no_gc && prev != GCCause::_shenandoah_concurrent_gc && cause != GCCause::_shenandoah_stop_vm) { + // Only when the gc has not been cancelled, or it has been cancelled to interrupt an old marking cycle + // do we allow the new cancellation request to happen. We make an exception for stopping the VM. + return false; + } + + if (_cancelled_gc.cmpxchg(cause, prev) == prev) { + return true; + } + } } void ShenandoahHeap::cancel_concurrent_mark() { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -258,6 +258,7 @@ inline bool ShenandoahHeap::check_cancelled_gc_and_yield(bool sts_active) { if (sts_active && !cancelled_gc()) { + assert(!ShenandoahEvacOOMHandler::is_active(), "Potential deadlock: cannot yield while OOM evac handler is active"); if (SuspendibleThreadSet::should_yield()) { SuspendibleThreadSet::yield(); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -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. * Copyright (c) 2013, 2020, Red Hat, Inc. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -32,7 +32,6 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" -#include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" @@ -40,15 +39,12 @@ #include "jfr/jfrEvents.hpp" #include "memory/allocation.hpp" #include "memory/iterator.inline.hpp" -#include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" -#include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" -#include "runtime/safepoint.hpp" #include "utilities/powerOfTwo.hpp" size_t ShenandoahHeapRegion::RegionCount = 0; @@ -863,16 +859,7 @@ p2i(top()), p2i(ctx->top_at_mark_start(this)), p2i(_update_watermark), p2i(ctx->top_bitmap(this))); } -#ifdef ASSERT - { - size_t idx = this->index(); - HeapWord* top_bitmap = ctx->top_bitmap(this); - - assert(ctx->is_bitmap_range_within_region_clear(top_bitmap, _end), - "Region %zu, bitmap should be clear between top_bitmap: " PTR_FORMAT " and end: " PTR_FORMAT, idx, - p2i(top_bitmap), p2i(_end)); - } -#endif + shenandoah_assert_clear_above_top(this); if (region_affiliation == new_affiliation) { return; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -269,6 +269,7 @@ ShenandoahSharedFlag _recycling; // Used to indicate that the region is being recycled; see try_recycle*(). + // This is only read/written by a gc worker to avoid unnecessary bitmap resets bool _needs_bitmap_reset; public: diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -81,13 +81,13 @@ inline void do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task, uint worker_id); template - inline void do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop array, bool weak); + inline void do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop array, Klass* klass, bool weak); template inline void do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, oop array, int chunk, int pow, bool weak); template - inline void count_liveness(ShenandoahLiveData* live_data, oop obj, uint worker_id); + inline void count_liveness(ShenandoahLiveData* live_data, oop obj, Klass* klass, uint worker_id); template void mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *t, StringDedup::Requests* const req); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -75,31 +75,32 @@ cl->set_weak(weak); if (task->is_not_chunked()) { - if (obj->is_instance()) { + Klass* klass = obj->klass(); + if (klass->is_instance_klass()) { // Case 1: Normal oop, process as usual. - if (obj->is_stackChunk()) { + if (klass->is_stack_chunk_instance_klass()) { // Loom doesn't support mixing of weak marking and strong marking of stack chunks. cl->set_weak(false); } obj->oop_iterate(cl); dedup_string(obj, req); - } else if (obj->is_objArray()) { + } else if (klass->is_objArray_klass()) { // Case 2: Object array instance and no chunk is set. Must be the first // time we visit it, start the chunked processing. - do_chunked_array_start(q, cl, obj, weak); + do_chunked_array_start(q, cl, obj, klass, weak); } else { // Case 3: Primitive array. Do nothing, no oops there. We use the same // performance tweak TypeArrayKlass::oop_oop_iterate_impl is using: // We skip iterating over the klass pointer since we know that // Universe::TypeArrayKlass never moves. - assert (obj->is_typeArray(), "should be type array"); + assert(klass->is_typeArray_klass(), "should be type array"); } // Count liveness the last: push the outstanding work to the queues first // Avoid double-counting objects that are visited twice due to upgrade // from final- to strong mark. if (task->count_liveness()) { - count_liveness(live_data, obj, worker_id); + count_liveness(live_data, obj, klass, worker_id); } } else { // Case 4: Array chunk, has sensible chunk id. Process it. @@ -108,11 +109,11 @@ } template -inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop obj, uint worker_id) { +inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop obj, Klass* klass, uint worker_id) { const ShenandoahHeap* const heap = ShenandoahHeap::heap(); const size_t region_idx = heap->heap_region_index_containing(obj); ShenandoahHeapRegion* const region = heap->get_region(region_idx); - const size_t size = obj->size(); + const size_t size = obj->size_given_klass(klass); // Age census for objects in the young generation if (GENERATION == YOUNG || (GENERATION == GLOBAL && region->is_young())) { @@ -152,14 +153,14 @@ } template -inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop obj, bool weak) { +inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop obj, Klass* klass, bool weak) { assert(obj->is_objArray(), "expect object array"); objArrayOop array = objArrayOop(obj); int len = array->length(); // Mark objArray klass metadata if (Devirtualizer::do_metadata(cl)) { - Devirtualizer::do_klass(cl, array->klass()); + Devirtualizer::do_klass(cl, klass); } if (len <= (int) ObjArrayMarkingStride*2) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,7 +1,7 @@ /* * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * 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 @@ -27,7 +27,7 @@ #include "gc/shared/markBitMap.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.hpp" -#include "shenandoahGlobalGeneration.hpp" +#include "runtime/orderAccess.hpp" ShenandoahMarkingContext::ShenandoahMarkingContext(MemRegion heap_region, MemRegion bitmap_region, size_t num_regions) : _mark_bit_map(heap_region, bitmap_region), @@ -91,6 +91,9 @@ if (top_bitmap > bottom) { _mark_bit_map.clear_range_large(MemRegion(bottom, top_bitmap)); + // All bitmap writes must complete before we update top at bitmap. If these writes were reordered, + // other threads could see stale marks above top, which is not valid. + OrderAccess::storestore(); _top_bitmaps[r->index()] = bottom; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -58,6 +58,7 @@ void ShenandoahRegulatorThread::regulate_young_and_old_cycles() { while (!should_terminate()) { + SuspendibleThreadSetJoiner joiner; ShenandoahGenerationalControlThread::GCMode mode = _control_thread->gc_mode(); if (mode == ShenandoahGenerationalControlThread::none) { if (should_start_metaspace_gc()) { @@ -95,6 +96,7 @@ void ShenandoahRegulatorThread::regulate_young_and_global_cycles() { while (!should_terminate()) { + SuspendibleThreadSetJoiner joiner; if (_control_thread->gc_mode() == ShenandoahGenerationalControlThread::none) { if (start_global_cycle()) { log_debug(gc)("Heuristics request for global collection accepted."); @@ -122,6 +124,7 @@ _last_sleep_adjust_time = current; } + SuspendibleThreadSetLeaver leaver; os::naked_short_sleep(_sleep); if (LogTarget(Debug, gc, thread)::is_enabled()) { double elapsed = os::elapsedTime() - current; @@ -146,6 +149,13 @@ bool ShenandoahRegulatorThread::request_concurrent_gc(ShenandoahGeneration* generation) const { double now = os::elapsedTime(); + + // This call may find the control thread waiting on workers which have suspended + // to allow a safepoint to run. If this regulator thread does not yield, the safepoint + // will not run. The worker threads won't progress, the control thread won't progress, + // and the regulator thread may never yield. Therefore, we leave the suspendible + // thread set before making this call. + SuspendibleThreadSetLeaver leaver; bool accepted = _control_thread->request_concurrent_gc(generation); if (LogTarget(Debug, gc, thread)::is_enabled() && accepted) { double wait_time = os::elapsedTime() - now; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -204,9 +204,6 @@ void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { NMethodToOopClosure code_blob_cl(oops, NMethodToOopClosure::FixRelocations); ShenandoahNMethodAndDisarmClosure nmethods_and_disarm_Cl(oops); - NMethodToOopClosure* adjust_code_closure = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? - static_cast(&nmethods_and_disarm_Cl) : - static_cast(&code_blob_cl); CLDToOopClosure adjust_cld_closure(oops, ClassLoaderData::_claim_strong); // Process light-weight/limited parallel roots then @@ -215,7 +212,7 @@ _cld_roots.cld_do(&adjust_cld_closure, worker_id); // Process heavy-weight/fully parallel roots the last - _code_roots.nmethods_do(adjust_code_closure, worker_id); + _code_roots.nmethods_do(&nmethods_and_disarm_Cl, worker_id); _thread_roots.oops_do(oops, nullptr, worker_id); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -172,10 +172,6 @@ void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) { NMethodToOopClosure update_nmethods(keep_alive, NMethodToOopClosure::FixRelocations); ShenandoahNMethodAndDisarmClosure nmethods_and_disarm_Cl(keep_alive); - NMethodToOopClosure* codes_cl = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? - static_cast(&nmethods_and_disarm_Cl) : - static_cast(&update_nmethods); - CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong); // Process light-weight/limited parallel roots then @@ -184,7 +180,7 @@ _cld_roots.cld_do(&clds, worker_id); // Process heavy-weight/fully parallel roots the last - _code_roots.nmethods_do(codes_cl, worker_id); + _code_roots.nmethods_do(&nmethods_and_disarm_Cl, worker_id); _thread_roots.oops_do(keep_alive, nullptr, worker_id); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -38,20 +38,16 @@ ShenandoahBarrierSet::barrier_set()->arraycopy_barrier(src, dst, length); JRT_END -JRT_LEAF(void, ShenandoahRuntime::write_ref_field_pre(oopDesc * orig, JavaThread * thread)) - assert(thread == JavaThread::current(), "pre-condition"); +JRT_LEAF(void, ShenandoahRuntime::write_barrier_pre(oopDesc* orig)) assert(orig != nullptr, "should be optimized out"); shenandoah_assert_correct(nullptr, orig); // Capture the original value that was in the field reference. + JavaThread* thread = JavaThread::current(); assert(ShenandoahThreadLocalData::satb_mark_queue(thread).is_active(), "Shouldn't be here otherwise"); SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(thread); ShenandoahBarrierSet::satb_mark_queue_set().enqueue_known_active(queue, orig); JRT_END -void ShenandoahRuntime::write_barrier_pre(oopDesc* orig) { - write_ref_field_pre(orig, JavaThread::current()); -} - JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_strong(oopDesc* src, oop* load_addr)) return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); JRT_END diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -36,7 +36,6 @@ static void arraycopy_barrier_oop(oop* src, oop* dst, size_t length); static void arraycopy_barrier_narrow_oop(narrowOop* src, narrowOop* dst, size_t length); - static void write_ref_field_pre(oopDesc* orig, JavaThread* thread); static void write_barrier_pre(oopDesc* orig); static oopDesc* load_reference_barrier_strong(oopDesc* src, oop* load_addr); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -70,7 +70,7 @@ // Arm all nmethods. Even though this is STW mark, some marking code // piggybacks on nmethod barriers for special instances. - ShenandoahCodeRoots::arm_nmethods_for_mark(); + ShenandoahCodeRoots::arm_nmethods(); // Weak reference processing assert(ShenandoahHeap::heap()->gc_generation() == _generation, "Marking unexpected generation"); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/include/jvm.h openjdk-25-25.0.5+8/src/hotspot/share/include/jvm.h --- openjdk-25-25.0.4.1+1/src/hotspot/share/include/jvm.h 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/include/jvm.h 2026-10-19 12:10:20.000000000 +0000 @@ -356,6 +356,9 @@ JNIEXPORT void JNICALL JVM_WaitForReferencePendingList(JNIEnv *env); +JNIEXPORT jobject JNICALL +JVM_ReferenceGet(JNIEnv *env, jobject ref); + JNIEXPORT jboolean JNICALL JVM_ReferenceRefersTo(JNIEnv *env, jobject ref, jobject o); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/interpreter/abstractInterpreter.cpp openjdk-25-25.0.5+8/src/hotspot/share/interpreter/abstractInterpreter.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/interpreter/abstractInterpreter.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/interpreter/abstractInterpreter.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -148,7 +148,7 @@ case vmIntrinsics::_fmaF: return java_lang_math_fmaF; case vmIntrinsics::_dsqrt: return java_lang_math_sqrt; case vmIntrinsics::_dsqrt_strict: return java_lang_math_sqrt_strict; - case vmIntrinsics::_Reference_get: return java_lang_ref_reference_get; + case vmIntrinsics::_Reference_get0: return java_lang_ref_reference_get0; case vmIntrinsics::_Object_init: if (m->code_size() == 1) { // We need to execute the special return bytecode to check for @@ -210,7 +210,7 @@ case java_lang_math_exp : return vmIntrinsics::_dexp; case java_lang_math_fmaD : return vmIntrinsics::_fmaD; case java_lang_math_fmaF : return vmIntrinsics::_fmaF; - case java_lang_ref_reference_get: return vmIntrinsics::_Reference_get; + case java_lang_ref_reference_get0: return vmIntrinsics::_Reference_get0; case java_util_zip_CRC32_update : return vmIntrinsics::_updateCRC32; case java_util_zip_CRC32_updateBytes : return vmIntrinsics::_updateBytesCRC32; @@ -320,7 +320,7 @@ case java_util_zip_CRC32_updateByteBuffer : tty->print("java_util_zip_CRC32_updateByteBuffer"); break; case java_util_zip_CRC32C_updateBytes : tty->print("java_util_zip_CRC32C_updateBytes"); break; case java_util_zip_CRC32C_updateDirectByteBuffer: tty->print("java_util_zip_CRC32C_updateDirectByteByffer"); break; - case java_lang_ref_reference_get : tty->print("java_lang_ref_reference_get"); break; + case java_lang_ref_reference_get0 : tty->print("java_lang_ref_reference_get0"); break; case java_lang_Thread_currentThread : tty->print("java_lang_Thread_currentThread"); break; case java_lang_Float_float16ToFloat : tty->print("java_lang_Float_float16ToFloat"); break; case java_lang_Float_floatToFloat16 : tty->print("java_lang_Float_floatToFloat16"); break; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/interpreter/abstractInterpreter.hpp openjdk-25-25.0.5+8/src/hotspot/share/interpreter/abstractInterpreter.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/interpreter/abstractInterpreter.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/interpreter/abstractInterpreter.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -83,7 +83,7 @@ java_lang_math_exp, // implementation of java.lang.Math.exp (x) java_lang_math_fmaF, // implementation of java.lang.Math.fma (x, y, z) java_lang_math_fmaD, // implementation of java.lang.Math.fma (x, y, z) - java_lang_ref_reference_get, // implementation of java.lang.ref.Reference.get() + java_lang_ref_reference_get0, // implementation of java.lang.ref.Reference.get() java_util_zip_CRC32_update, // implementation of java.util.zip.CRC32.update() java_util_zip_CRC32_updateBytes, // implementation of java.util.zip.CRC32.updateBytes() java_util_zip_CRC32_updateByteBuffer, // implementation of java.util.zip.CRC32.updateByteBuffer() diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp openjdk-25-25.0.5+8/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -204,7 +204,7 @@ method_entry(java_lang_math_pow ) method_entry(java_lang_math_fmaF ) method_entry(java_lang_math_fmaD ) - method_entry(java_lang_ref_reference_get) + method_entry(java_lang_ref_reference_get0) AbstractInterpreter::initialize_method_handle_entries(); method_entry(java_util_zip_CRC32C_updateBytes) @@ -228,6 +228,7 @@ // entries for `native` methods to use the same address in case // intrinsic is disabled. native_method_entry(java_lang_Thread_currentThread) + native_method_entry(java_lang_ref_reference_get0) native_method_entry(java_util_zip_CRC32_update) native_method_entry(java_util_zip_CRC32_updateBytes) @@ -465,7 +466,7 @@ case Interpreter::java_lang_math_fmaF : entry_point = generate_math_entry(kind); break; case Interpreter::java_lang_math_sqrt_strict : entry_point = generate_math_entry(Interpreter::java_lang_math_sqrt); break; - case Interpreter::java_lang_ref_reference_get + case Interpreter::java_lang_ref_reference_get0 : entry_point = generate_Reference_get_entry(); break; case Interpreter::java_util_zip_CRC32_update : entry_point = generate_CRC32_update_entry(); break; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp openjdk-25-25.0.5+8/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -64,7 +64,7 @@ method_entry(java_lang_math_exp ); method_entry(java_lang_math_fmaD ); method_entry(java_lang_math_fmaF ); - method_entry(java_lang_ref_reference_get); + method_entry(java_lang_ref_reference_get0); AbstractInterpreter::initialize_method_handle_entries(); @@ -107,7 +107,7 @@ case Interpreter::java_lang_math_exp : // fall thru case Interpreter::java_lang_math_fmaD : // fall thru case Interpreter::java_lang_math_fmaF : entry_point = generate_math_entry(kind); break; - case Interpreter::java_lang_ref_reference_get + case Interpreter::java_lang_ref_reference_get0 : entry_point = generate_Reference_get_entry(); break; default: fatal("unexpected method kind: %d", kind); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp openjdk-25-25.0.5+8/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -48,14 +48,6 @@ #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" -const unsigned int initial_size = 431; - -static JfrCHeapTraceIdSet* c_heap_allocate_set(int size = initial_size) { - return new JfrCHeapTraceIdSet(size); -} - -static JfrCHeapTraceIdSet* unloaded_thread_id_set = nullptr; - class ThreadIdExclusiveAccess : public StackObj { private: static Semaphore _mutex_semaphore; @@ -66,19 +58,13 @@ Semaphore ThreadIdExclusiveAccess::_mutex_semaphore(1); -static bool has_thread_exited(traceid tid) { - assert(tid != 0, "invariant"); - if (unloaded_thread_id_set == nullptr) { - return false; - } - ThreadIdExclusiveAccess lock; - return unloaded_thread_id_set->contains(tid); -} +static const unsigned initial_set_size = 512; +static JfrCHeapTraceIdSet* unloaded_thread_id_set = nullptr; static void add_to_unloaded_thread_set(traceid tid) { ThreadIdExclusiveAccess lock; if (unloaded_thread_id_set == nullptr) { - unloaded_thread_id_set = c_heap_allocate_set(); + unloaded_thread_id_set = new (mtTracing) JfrCHeapTraceIdSet(initial_set_size); } unloaded_thread_id_set->add(tid); } @@ -193,12 +179,6 @@ assert(entry != nullptr, "invariant"); } -static JfrResourceAreaTraceIdSet* id_set = nullptr; - -static void prepare_for_resolution() { - id_set = new JfrResourceAreaTraceIdSet(initial_size); -} - static bool stack_trace_precondition(const ObjectSample* sample) { assert(sample != nullptr, "invariant"); return sample->has_stack_trace_id() && !sample->is_dead(); @@ -213,6 +193,8 @@ JfrTraceId::load_leakp(object->klass()); } +static JfrResourceAreaTraceIdSet* resolution_set = nullptr; + class StackTraceBlobInstaller { private: BlobCache _cache; @@ -220,8 +202,9 @@ const JfrStackTrace* resolve(const ObjectSample* sample) const; public: StackTraceBlobInstaller() : _cache(JfrOptionSet::old_object_queue_size()) { - prepare_for_resolution(); + resolution_set = new JfrResourceAreaTraceIdSet(initial_set_size); } + void sample_do(ObjectSample* sample) { if (stack_trace_precondition(sample)) { add_to_leakp_set(sample); @@ -314,8 +297,8 @@ static bool is_processed(traceid method_id) { assert(method_id != 0, "invariant"); - assert(id_set != nullptr, "invariant"); - return !id_set->add(method_id); + assert(resolution_set != nullptr, "invariant"); + return !resolution_set->add(method_id); } void ObjectSampleCheckpoint::add_to_leakp_set(const InstanceKlass* ik, traceid method_id) { @@ -356,7 +339,7 @@ static void write_thread_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) { assert(sample->has_thread(), "invariant"); - if (sample->is_virtual_thread() || has_thread_exited(sample->thread_id())) { + if (sample->is_virtual_thread() || sample->thread_exited()) { write_blob(sample->thread(), writer); } } @@ -372,13 +355,13 @@ class LeakProfilerStackTraceWriter { private: JfrCheckpointWriter& _writer; - int _count; + unsigned _count; public: LeakProfilerStackTraceWriter(JfrCheckpointWriter& writer) : _writer(writer), _count(0) { assert(_stacktrace_id_set != nullptr, "invariant"); } - int count() const { return _count; } + unsigned count() const { return _count; } void operator()(const JfrStackTrace* stacktrace) { if (should_write(stacktrace)) { @@ -394,12 +377,10 @@ JfrCheckpointWriter writer(thread); writer.write_type(TYPE_STACKTRACE); - const int64_t count_offset = writer.reserve(sizeof(u4)); // Don't know how many yet - + writer.write_count(_stacktrace_id_set->size()); LeakProfilerStackTraceWriter lpstw(writer); JfrStackTraceRepository::iterate_leakprofiler(lpstw); assert(lpstw.count() == _stacktrace_id_set->size(), "invariant"); - writer.write_count(lpstw.count(), count_offset); } static void write_stacktrace_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) { @@ -422,6 +403,16 @@ write_type_set_blob(sample, writer); } +static void check_if_thread_exited(const ObjectSample* sample) { + assert(sample != nullptr, "invariant"); + if (sample->thread_exited() || unloaded_thread_id_set == nullptr) { + return; + } + if (unloaded_thread_id_set->contains(sample->thread_id())) { + sample->set_thread_exited(); + } +} + class BlobWriter { private: const ObjectSampler* _sampler; @@ -431,23 +422,36 @@ BlobWriter(const ObjectSampler* sampler, JfrCheckpointWriter& writer, jlong last_sweep) : _sampler(sampler), _writer(writer), _last_sweep(last_sweep) {} void sample_do(ObjectSample* sample) { + check_if_thread_exited(sample); if (sample->is_alive_and_older_than(_last_sweep)) { write_blobs(sample, _writer); } } }; +static void delete_unloaded_thread_id_set() { + if (unloaded_thread_id_set != nullptr) { + delete unloaded_thread_id_set; + unloaded_thread_id_set = nullptr; + } +} + static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thread* thread) { // sample set is predicated on time of last sweep const jlong last_sweep = emit_all ? max_jlong : ObjectSampler::last_sweep(); JfrCheckpointWriter writer(thread, false); BlobWriter cbw(sampler, writer, last_sweep); + ThreadIdExclusiveAccess lock; iterate_samples(cbw, true); + delete_unloaded_thread_id_set(); } -static inline unsigned int set_size() { - const unsigned int queue_size = static_cast(JfrOptionSet::old_object_queue_size()); - return queue_size > initial_size ? queue_size : initial_size; +static inline unsigned stacktrace_id_set_size() { + unsigned queue_size = static_cast(JfrOptionSet::old_object_queue_size()); + if (!is_power_of_2(queue_size)) { + queue_size = next_power_of_2(queue_size); + } + return queue_size > initial_set_size ? queue_size : initial_set_size; } void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread) { @@ -456,7 +460,9 @@ assert(thread != nullptr, "invariant"); { ResourceMark rm(thread); - _stacktrace_id_set = new JfrResourceAreaTraceIdSet(set_size()); + const unsigned stacktrace_set_size = stacktrace_id_set_size(); + assert(is_power_of_2(stacktrace_set_size), "invariant"); + _stacktrace_id_set = new JfrResourceAreaTraceIdSet(stacktrace_set_size); write_sample_blobs(sampler, emit_all, thread); if (_stacktrace_id_set->is_nonempty()) { write_stacktraces(thread); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp openjdk-25-25.0.5+8/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -59,6 +59,7 @@ size_t _heap_used_at_last_gc; int _index; bool _virtual_thread; + mutable bool _thread_exited; void release_references() { _stacktrace.~JfrBlobHandle(); @@ -82,7 +83,8 @@ _allocated(0), _heap_used_at_last_gc(0), _index(0), - _virtual_thread(false) {} + _virtual_thread(false), + _thread_exited(false) {} ObjectSample* next() const { return _next; @@ -225,6 +227,15 @@ _virtual_thread = true; } + bool thread_exited() const { + return _thread_exited; + } + + void set_thread_exited() const { + assert(!_thread_exited, "invariant"); + _thread_exited = true; + } + const JfrBlobHandle& type_set() const { return _type_set; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -64,11 +64,11 @@ chunkwriter.write_unbuffered(data_address, length); } -void JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) { +size_t JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) { assert(chunkwriter.is_valid(), "invariant"); check_internal_types(); if (last_metadata_id == metadata_id && chunkwriter.has_metadata()) { - return; + return 0; } JavaThread* const jt = JavaThread::current(); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); @@ -87,6 +87,7 @@ chunkwriter.write_padded_at_offset((u4)size_written, metadata_offset); chunkwriter.set_last_metadata_offset(metadata_offset); last_metadata_id = metadata_id; + return 1; } void JfrMetadataEvent::update(jbyteArray metadata) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ // class JfrMetadataEvent : AllStatic { public: - static void write(JfrChunkWriter& writer); + static size_t write(JfrChunkWriter& writer); static void update(jbyteArray metadata); }; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1048,19 +1048,15 @@ private: MethodCallback _method_cb; KlassCallback _klass_cb; - KlassUsedPredicate _klass_used_predicate; - MethodUsedPredicate _method_used_predicate; MethodFlagPredicate _method_flag_predicate; public: MethodIteratorHost(JfrCheckpointWriter* writer) : _method_cb(writer, unloading(), false), _klass_cb(writer, unloading(), false), - _klass_used_predicate(current_epoch()), - _method_used_predicate(current_epoch()), _method_flag_predicate(current_epoch()) {} bool operator()(KlassPtr klass) { - if (_method_used_predicate(klass)) { + if (klass->is_instance_klass()) { const InstanceKlass* ik = InstanceKlass::cast(klass); while (ik != nullptr) { const int len = ik->methods()->length(); @@ -1075,7 +1071,7 @@ ik = ik->previous_versions(); } } - return _klass_used_predicate(klass) ? _klass_cb(klass) : true; + return _klass_cb(klass); } int count() const { return _method_cb.count(); } @@ -1280,10 +1276,11 @@ _class_unload = class_unload; _flushpoint = flushpoint; if (_artifacts == nullptr) { - _artifacts = new JfrArtifactSet(class_unload); + _artifacts = new JfrArtifactSet(class_unload, previous_epoch()); } else { - _artifacts->initialize(class_unload); + _artifacts->initialize(class_unload, previous_epoch()); } + assert(current_epoch() || _leakp_writer != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); assert(!_artifacts->has_klass_entries(), "invariant"); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -29,18 +29,23 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" -JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_table(nullptr), - _klass_list(nullptr), - _total_count(0), - _class_unload(class_unload) { - initialize(class_unload); - assert(_klass_list != nullptr, "invariant"); +JfrArtifactSet::JfrArtifactSet(bool class_unload, bool previous_epoch) : _symbol_table(nullptr), + _klass_set(nullptr), + _klass_loader_set(nullptr), + _klass_loader_leakp_set(nullptr), + _total_count(0), + _class_unload(class_unload) { + initialize(class_unload, previous_epoch); + assert(!previous_epoch || _klass_loader_leakp_set != nullptr, "invariant"); + assert(_klass_loader_set != nullptr, "invariant"); + assert(_klass_set != nullptr, "invariant"); } -static const size_t initial_klass_list_size = 4096; -const int initial_klass_loader_set_size = 64; +static unsigned initial_klass_set_size = 4096; +static unsigned initial_klass_loader_set_size = 64; +static unsigned initial_klass_loader_leakp_set_size = 64; -void JfrArtifactSet::initialize(bool class_unload) { +void JfrArtifactSet::initialize(bool class_unload, bool previous_epoch) { _class_unload = class_unload; if (_symbol_table == nullptr) { _symbol_table = JfrSymbolTable::create(); @@ -50,9 +55,11 @@ _symbol_table->set_class_unload(class_unload); _total_count = 0; // Resource allocations. Keep in this allocation order. - _klass_loader_leakp_set = new GrowableArray(initial_klass_loader_set_size); - _klass_loader_set = new GrowableArray(initial_klass_loader_set_size); - _klass_list = new GrowableArray(initial_klass_list_size); + if (previous_epoch) { + _klass_loader_leakp_set = new JfrKlassSet(initial_klass_loader_leakp_set_size); + } + _klass_loader_set = new JfrKlassSet(initial_klass_loader_set_size); + _klass_set = new JfrKlassSet(initial_klass_set_size); } void JfrArtifactSet::clear() { @@ -93,17 +100,12 @@ } bool JfrArtifactSet::has_klass_entries() const { - return _klass_list->is_nonempty(); -} - -int JfrArtifactSet::entries() const { - return _klass_list->length(); + return _klass_set->is_nonempty(); } - -static inline bool not_in_set(GrowableArray* set, const Klass* k) { +static inline bool not_in_set(JfrArtifactSet::JfrKlassSet* set, const Klass* k) { assert(set != nullptr, "invariant"); assert(k != nullptr, "invariant"); - return !JfrMutablePredicate::test(set, k); + return set->add(k); } bool JfrArtifactSet::should_do_cld_klass(const Klass* k, bool leakp) { @@ -116,16 +118,21 @@ void JfrArtifactSet::register_klass(const Klass* k) { assert(k != nullptr, "invariant"); assert(IS_SERIALIZED(k), "invariant"); - assert(_klass_list != nullptr, "invariant"); - _klass_list->append(k); + assert(_klass_set != nullptr, "invariant"); + _klass_set->add(k); } size_t JfrArtifactSet::total_count() const { + assert(_klass_set != nullptr, "invariant"); + initial_klass_set_size = MAX2(initial_klass_set_size, _klass_set->table_size()); + assert(_klass_loader_set != nullptr, "invariant"); + initial_klass_loader_set_size = MAX2(initial_klass_loader_set_size, _klass_loader_set->table_size()); return _total_count; } void JfrArtifactSet::increment_checkpoint_id() { assert(_symbol_table != nullptr, "invariant"); _symbol_table->increment_checkpoint_id(); + assert(_klass_loader_leakp_set != nullptr, "invariant"); + initial_klass_loader_leakp_set_size = MAX2(initial_klass_loader_leakp_set_size, _klass_loader_leakp_set->table_size()); } - diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -28,12 +28,10 @@ #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/support/jfrSymbolTable.hpp" #include "jfr/utilities/jfrAllocation.hpp" +#include "jfr/utilities/jfrSet.hpp" #include "oops/klass.hpp" #include "oops/method.hpp" -template -class GrowableArray; - // Composite callback/functor building block template class CompositeFunctor { @@ -135,27 +133,6 @@ } }; -class KlassUsedPredicate { - bool _current_epoch; - public: - KlassUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {} - bool operator()(const Klass* klass) { - return _current_epoch ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass); - } -}; - -class MethodUsedPredicate { - bool _current_epoch; -public: - MethodUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {} - bool operator()(const Klass* klass) { - if (!klass->is_instance_klass()) { - return false; - } - return _current_epoch ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass); - } -}; - template class MethodFlagPredicate { bool _current_epoch; @@ -203,20 +180,46 @@ * in the respective VM subsystems. */ class JfrArtifactSet : public JfrCHeapObj { + public: + class JfrArtifactSetConfig : public AllStatic { + public: + typedef const Klass* KEY_TYPE; + + constexpr static AnyObj::allocation_type alloc_type() { + return AnyObj::RESOURCE_AREA; + } + + constexpr static MemTag memory_tag() { + return mtInternal; + } + + // Knuth multiplicative hashing. + static uint32_t hash(const KEY_TYPE& k) { + const uint32_t v = static_cast(JfrTraceId::load_raw(k)); + return v * UINT32_C(2654435761); + } + + static bool cmp(const KEY_TYPE& lhs, const KEY_TYPE& rhs) { + return lhs == rhs; + } + }; + + typedef JfrSet JfrKlassSet; + private: JfrSymbolTable* _symbol_table; - GrowableArray* _klass_list; - GrowableArray* _klass_loader_set; - GrowableArray* _klass_loader_leakp_set; + JfrKlassSet* _klass_set; + JfrKlassSet* _klass_loader_set; + JfrKlassSet* _klass_loader_leakp_set; size_t _total_count; bool _class_unload; public: - JfrArtifactSet(bool class_unload); + JfrArtifactSet(bool class_unload, bool previous_epoch); ~JfrArtifactSet(); // caller needs ResourceMark - void initialize(bool class_unload); + void initialize(bool class_unload, bool previous_epoch); void clear(); traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); @@ -231,7 +234,6 @@ const JfrSymbolTable::StringEntry* map_string(uintptr_t hash) const; bool has_klass_entries() const; - int entries() const; size_t total_count() const; void register_klass(const Klass* k); bool should_do_cld_klass(const Klass* k, bool leakp); @@ -254,19 +256,17 @@ template void iterate_klasses(Functor& functor) const { - if (iterate(functor, _klass_list)) { + if (iterate(functor, _klass_set)) { iterate(functor, _klass_loader_set); } } private: template - bool iterate(Functor& functor, GrowableArray* list) const { - assert(list != nullptr, "invariant"); - for (int i = 0; i < list->length(); ++i) { - if (!functor(list->at(i))) { - return false; - } + bool iterate(Functor& functor, JfrKlassSet* set) const { + assert(set != nullptr, "invariant"); + if (set->is_nonempty()) { + set->iterate(functor); } return true; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -368,13 +368,14 @@ class MetadataEvent : public StackObj { private: JfrChunkWriter& _cw; + size_t _elements; public: - MetadataEvent(JfrChunkWriter& cw) : _cw(cw) {} + MetadataEvent(JfrChunkWriter& cw) : _cw(cw), _elements(0) {} bool process() { - JfrMetadataEvent::write(_cw); + _elements = JfrMetadataEvent::write(_cw); return true; } - size_t elements() const { return 1; } + size_t elements() const { return _elements; } }; typedef WriteContent WriteMetadata; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp openjdk-25-25.0.5+8/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -30,10 +30,10 @@ #include "runtime/mutexLocker.hpp" #include "utilities/macros.hpp" -static const int initial_size = 1009; +static const int initial_size = 1024; static JfrCHeapTraceIdSet* c_heap_allocate_set(int size = initial_size) { - return new JfrCHeapTraceIdSet(size); + return new (mtTracing) JfrCHeapTraceIdSet(size); } // Track the set of unloaded klasses during a chunk / epoch. @@ -68,18 +68,9 @@ return get_unload_set(JfrTraceIdEpoch::previous()); } -static bool is_nonempty_set(u1 epoch) { - if (epoch == 0) { - return _unload_set_epoch_0 != nullptr && _unload_set_epoch_0->is_nonempty(); - } - return _unload_set_epoch_1 != nullptr && _unload_set_epoch_1->is_nonempty(); -} - void JfrKlassUnloading::clear() { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - if (is_nonempty_set(JfrTraceIdEpoch::previous())) { - get_unload_set_previous_epoch()->clear(); - } + get_unload_set_previous_epoch()->clear(); } static void add_to_unloaded_klass_set(traceid klass_id) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/utilities/jfrSet.hpp openjdk-25-25.0.5+8/src/hotspot/share/jfr/utilities/jfrSet.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/jfr/utilities/jfrSet.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/jfr/utilities/jfrSet.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -25,15 +25,13 @@ #ifndef SHARE_JFR_UTILITIES_JFRSET_HPP #define SHARE_JFR_UTILITIES_JFRSET_HPP -#include "jfr/utilities/jfrAllocation.hpp" +#include "memory/allocation.hpp" #include "jfr/utilities/jfrTypes.hpp" -#include "utilities/resizeableResourceHash.hpp" -template -class ConfigTraceID : public AllStatic { +template +class JfrSetConfig : public AllStatic { public: - typedef AllocPolicy STORAGE; - typedef traceid TYPE; + typedef K KEY_TYPE; constexpr static AnyObj::allocation_type alloc_type() { return AllocType; @@ -44,80 +42,171 @@ } // Knuth multiplicative hashing. - static uint32_t hash(const TYPE& id) { - const uint32_t v = static_cast(id); - return v * UINT32_C(2654435761); + static uint32_t hash(const KEY_TYPE& key) { + const uint32_t k = static_cast(key); + return k * UINT32_C(2654435761); } - static bool cmp(const TYPE& lhs, const TYPE& rhs) { + static bool cmp(const KEY_TYPE& lhs, const KEY_TYPE& rhs) { return lhs == rhs; } }; -constexpr static unsigned int MAX_TABLE_SIZE = 0x3fffffff; - template -class JfrSet : public CONFIG::STORAGE { - public: - typedef typename CONFIG::TYPE TYPE; - typedef ResizeableResourceHashtable HashMap; - - constexpr static bool is_cheap() { - return CONFIG::alloc_type() == AnyObj::C_HEAP; +class JfrSetStorage : public AnyObj { + typedef typename CONFIG::KEY_TYPE K; + protected: + K* _table; + unsigned _table_size; + unsigned _elements; + + static K* alloc_table(unsigned table_size) { + K* table; + if (CONFIG::alloc_type() == C_HEAP) { + table = NEW_C_HEAP_ARRAY(K, table_size, CONFIG::memory_tag()); + } else { + table = NEW_RESOURCE_ARRAY(K, table_size); + } + memset(table, 0, table_size * sizeof(K)); + return table; } - JfrSet(unsigned int initial_size, unsigned int max_size = MAX_TABLE_SIZE) : - _map(is_cheap() ? new (CONFIG::memory_tag()) HashMap(initial_size, max_size) : new HashMap(initial_size, max_size)) {} - - ~JfrSet() { - if (is_cheap()) { - delete _map; + JfrSetStorage(unsigned table_size) : + _table(alloc_table(table_size)), + _table_size(table_size), + _elements(0) {} + + ~JfrSetStorage() { + if (CONFIG::alloc_type() == C_HEAP) { + FREE_C_HEAP_ARRAY(K, _table); } } - bool add(const TYPE& k) { - bool inserted; - _map->put_if_absent(k, &inserted); - return inserted; + public: + template + void iterate(Functor& functor) { + assert(is_nonempty(), "invariant"); + for (unsigned i = 0; i < _table_size; ++i) { + K k = _table[i]; + if (k != 0) { + functor(k); + } + } } - bool remove(const TYPE& k) { - return _map->remove(k); + unsigned table_size() const { + return _table_size; } - bool contains(const TYPE& k) const { - return _map->contains(k); + unsigned size() const { + return _elements; } - bool is_empty() const { - return _map->number_of_entries() == 0; + bool is_nonempty() const { + return _elements > 0; } - bool is_nonempty() const { - return !is_empty(); + void clear() { + memset(_table, 0, _table_size * sizeof(K)); } +}; - int size() const { - return _map->number_of_entries(); +template +class JfrSet : public JfrSetStorage { + typedef typename CONFIG::KEY_TYPE K; + static_assert(sizeof(K) > 1, "invalid size of CONFIG::KEY_TYPE"); + private: + static const constexpr unsigned max_initial_size = 1 << 30; + unsigned _table_mask; + unsigned _resize_threshold; // 0.5 load factor + + uint32_t slot_idx(const uint32_t hash) const { + return hash & _table_mask; + } + + void resize() { + assert(this->_elements == _resize_threshold, "invariant"); + K* const old_table = this->_table; + assert(old_table != nullptr, "invariant"); + const unsigned old_table_size = this->table_size(); + guarantee(old_table_size <= max_initial_size, "overflow"); + this->_table_size = old_table_size << 1; + this->_table = JfrSetStorage::alloc_table(this->_table_size); + _table_mask = this->_table_size - 1; + _resize_threshold = old_table_size; + for (unsigned i = 0; i < old_table_size; ++i) { + const K k = old_table[i]; + if (k != 0) { + uint32_t idx = slot_idx(CONFIG::hash(k)); + do { + K v = this->_table[idx]; + if (v == 0) { + this->_table[idx] = k; + break; + } + idx = slot_idx(idx + 1); + } while (true); + } + } + if (CONFIG::alloc_type() == AnyObj::C_HEAP) { + FREE_C_HEAP_ARRAY(K, old_table); + } + assert(_table_mask + 1 == this->_table_size, "invariant"); + assert(_resize_threshold << 1 == this->_table_size, "invariant"); } - void clear() { - if (is_nonempty()) { - _map->unlink(this); + K* find_slot(K const& k) const { + uint32_t idx = slot_idx(CONFIG::hash(k)); + assert(idx < this->table_size(), "invariant"); + K* result = nullptr; + while (true) { + K v = this->_table[idx]; + if (v == 0) { + result = &this->_table[idx]; + break; + } + if (CONFIG::cmp(v, k)) { + result = reinterpret_cast(p2i(&this->_table[idx]) | 1); + break; + } + idx = slot_idx(idx + 1); } - assert(is_empty(), "invariant"); + assert(result != nullptr, "invariant"); + return result; } - // Callback for node deletion, used by clear(). - bool do_entry(const TYPE& k, const TYPE& v) { + public: + JfrSet(unsigned size) : + JfrSetStorage(size), + _table_mask(size - 1), + _resize_threshold(size >> 1) { + assert(size >= 2, "invariant"); + assert(size % 2 == 0, "invariant"); + assert(size <= max_initial_size, "avoid overflow in resize"); + } + + bool contains(K const& k) const { + K* const slot = find_slot(k); + return p2i(slot) & 1; + } + + bool add(K const& k) { + K* const slot = find_slot(k); + if (p2i(slot) & 1) { + // Already exists. + return false; + } + assert(*slot == 0, "invariant"); + *slot = k; + if (++this->_elements == _resize_threshold) { + resize(); + } + assert(this->_elements < _resize_threshold, "invariant"); return true; } - - private: - HashMap* _map; }; -typedef JfrSet > JfrCHeapTraceIdSet; -typedef JfrSet > JfrResourceAreaTraceIdSet; +typedef JfrSet > JfrCHeapTraceIdSet; +typedef JfrSet > JfrResourceAreaTraceIdSet; #endif // SHARE_JFR_UTILITIES_JFRSET_HPP diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/oops/bsmAttribute.hpp openjdk-25-25.0.5+8/src/hotspot/share/oops/bsmAttribute.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/oops/bsmAttribute.hpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/oops/bsmAttribute.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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_OOPS_BSMATTRIBUTE_HPP +#define SHARE_OOPS_BSMATTRIBUTE_HPP + +#include "oops/array.hpp" +#include "utilities/checkedCast.hpp" +#include "utilities/globalDefinitions.hpp" + +class ClassLoaderData; + +class BSMAttributeEntry { + friend class ConstantPool; + friend class BSMAttributeEntries; + + u2 _bootstrap_method_index; + u2 _argument_count; + + // The argument indexes are stored right after the object, in a contiguous array. + // [ bsmi_0 argc_0 arg_00 arg_01 ... arg_0N bsmi_1 argc_1 arg_10 ... arg_1N ... ] + // So in order to find the argument array, jump over ourselves. + const u2* argument_indexes() const { + return reinterpret_cast(this + 1); + } + u2* argument_indexes() { + return reinterpret_cast(this + 1); + } + // These are overlays on top of the BSMAttributeEntries data array, do not construct. + BSMAttributeEntry() = delete; + NONCOPYABLE(BSMAttributeEntry); + + void copy_args_into(BSMAttributeEntry* entry) const; + +public: + // Offsets for SA + enum { + _bsmi_offset = 0, + _argc_offset = 1, + _argv_offset = 2 + }; + + int bootstrap_method_index() const { + return _bootstrap_method_index; + } + int argument_count() const { + return _argument_count; + } + int argument(int n) const { + assert(checked_cast(n) < _argument_count, "oob"); + return argument_indexes()[n]; + } + + void set_argument(int index, u2 value) { + assert(index >= 0 && index < argument_count(), "invariant"); + argument_indexes()[index] = value; + } + + // How many u2s are required to store a BSM entry with argc arguments? + static int u2s_required (u2 argc) { + return 1 /* index */ + 1 /* argc */ + argc /* argv */; + } +}; + +// The BSMAttributeEntries stores the state of the BootstrapMethods attribute. +class BSMAttributeEntries { + friend class VMStructs; + friend class JVMCIVMStructs; + +public: + class InsertionIterator { + friend BSMAttributeEntries; + BSMAttributeEntries* _insert_into; + // Current unused offset into BSMAEs offset array. + int _cur_offset; + // Current unused offset into BSMAEs bsm-data array. + int _cur_array; + public: + InsertionIterator() : _insert_into(nullptr), _cur_offset(-1), _cur_array(-1) {} + InsertionIterator(BSMAttributeEntries* insert_into, int cur_offset, int cur_array) + : _insert_into(insert_into), + _cur_offset(cur_offset), + _cur_array(cur_array) {} + InsertionIterator(const InsertionIterator&) = default; + InsertionIterator& operator=(const InsertionIterator&) = default; + + int current_offset() const { return _cur_offset; } + // Add a new BSMAE, reserving the necessary memory for filling the argument vector. + // Returns null if there isn't enough space. + inline BSMAttributeEntry* reserve_new_entry(u2 bsmi, u2 argc); + }; + +private: + // Each bootstrap method has a variable-sized array associated with it. + // We want constant-time lookup of the Nth BSM. Therefore, we use an offset table, + // such that the Nth BSM is located at _bootstrap_methods[_offsets[N]]. + Array* _offsets; + Array* _bootstrap_methods; + + // Copy the first num_entries into iter. + void copy_into(InsertionIterator& iter, int num_entries) const; + +public: + BSMAttributeEntries() : _offsets(nullptr), _bootstrap_methods(nullptr) {} + BSMAttributeEntries(Array* offsets, Array* bootstrap_methods) + : _offsets(offsets), + _bootstrap_methods(bootstrap_methods) {} + + bool is_empty() const { + return _offsets == nullptr && _bootstrap_methods == nullptr; + } + + Array*& offsets() { return _offsets; } + const Array* const& offsets() const { return _offsets; } + Array*& bootstrap_methods() { return _bootstrap_methods; } + const Array* const& bootstrap_methods() const { return _bootstrap_methods; } + + BSMAttributeEntry* entry(int bsms_attribute_index) { + return reinterpret_cast(_bootstrap_methods->adr_at(_offsets->at(bsms_attribute_index))); + } + const BSMAttributeEntry* entry(int bsms_attribute_index) const { + return reinterpret_cast(_bootstrap_methods->adr_at(_offsets->at(bsms_attribute_index))); + } + + int number_of_entries() const { + return _offsets == nullptr ? 0 : _offsets->length(); + } + + // The number of U2s the BSM data consists of. + int array_length() const { + return _bootstrap_methods == nullptr ? 0 : _bootstrap_methods->length(); + } + + void deallocate_contents(ClassLoaderData* loader_data); + + // Extend to have the space for both this BSMAEntries and other's. + // Does not copy in the other's BSMAEntrys, that must be done via the InsertionIterator. + // This starts an insertion iterator. Any call to start_extension must have a matching end_extension call. + InsertionIterator start_extension(const BSMAttributeEntries& other, ClassLoaderData* loader_data, TRAPS); + // Extend the BSMAEntries with an additional number_of_entries with a total data_size. + InsertionIterator start_extension(int number_of_entries, int data_size, ClassLoaderData* loader_data, TRAPS); + // Reallocates the underlying memory to fit the limits of the InsertionIterator precisely. + // This ends an insertion iteration. The memory is truncated to fit exactly the data used. + void end_extension(InsertionIterator& iter, ClassLoaderData* loader_data, TRAPS); + // Append all of the BSMAEs in other into this. + void append(const BSMAttributeEntries& other, ClassLoaderData* loader_data, TRAPS); +}; + +#endif // SHARE_OOPS_BSMATTRIBUTE_HPP diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/oops/bsmAttribute.inline.hpp openjdk-25-25.0.5+8/src/hotspot/share/oops/bsmAttribute.inline.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/oops/bsmAttribute.inline.hpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/oops/bsmAttribute.inline.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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_OOPS_BSMATTRIBUTE_INLINE_HPP +#define SHARE_OOPS_BSMATTRIBUTE_INLINE_HPP + +#include "oops/bsmAttribute.hpp" + +inline BSMAttributeEntry* BSMAttributeEntries::InsertionIterator::reserve_new_entry(u2 bsmi, u2 argc) { + assert(_insert_into->offsets() != nullptr, "must"); + assert(_insert_into->bootstrap_methods() != nullptr, "must"); + + if (_cur_offset + 1 > _insert_into->offsets()->length() || + _cur_array + BSMAttributeEntry::u2s_required(argc) > _insert_into->bootstrap_methods()->length()) { + return nullptr; + } + _insert_into->offsets()->at_put(_cur_offset, _cur_array); + BSMAttributeEntry* e = _insert_into->entry(_cur_offset); + e->_bootstrap_method_index = bsmi; + e->_argument_count = argc; + + _cur_array += 1 + 1 + argc; + _cur_offset += 1; + return e; +} + +inline void BSMAttributeEntry::copy_args_into(BSMAttributeEntry* entry) const { + assert(entry->argument_count() == this->argument_count(), "must be same"); + for (int i = 0; i < argument_count(); i++) { + entry->set_argument(i, this->argument(i)); + } +} + +#endif // SHARE_OOPS_BSMATTRIBUTE_INLINE_HPP diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/oops/constantPool.cpp openjdk-25-25.0.5+8/src/hotspot/share/oops/constantPool.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/oops/constantPool.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/oops/constantPool.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -133,8 +133,7 @@ MetadataFactory::free_array(loader_data, resolved_klasses()); set_resolved_klasses(nullptr); - MetadataFactory::free_array(loader_data, operands()); - set_operands(nullptr); + bsm_entries().deallocate_contents(loader_data); release_C_heap_structures(); @@ -154,7 +153,8 @@ it->push(&_tags, MetaspaceClosure::_writable); it->push(&_cache); it->push(&_pool_holder); - it->push(&_operands); + it->push(&bsm_entries().offsets()); + it->push(&bsm_entries().bootstrap_methods()); it->push(&_resolved_klasses, MetaspaceClosure::_writable); for (int i = 0; i < length(); i++) { @@ -758,7 +758,7 @@ if (cpool->cache() == nullptr) return nullptr; // nothing to load yet if (!(which >= 0 && which < cpool->resolved_method_entries_length())) { // FIXME: should be an assert - log_debug(class, resolve)("bad operand %d in:", which); cpool->print(); + log_debug(class, resolve)("bad BSM %d in:", which); cpool->print(); return nullptr; } return cpool->cache()->method_if_resolved(which); @@ -1559,8 +1559,8 @@ int i1 = bootstrap_methods_attribute_index(index1); int i2 = cp2->bootstrap_methods_attribute_index(index2); bool match_entry = compare_entry_to(k1, cp2, k2); - bool match_operand = compare_operand_to(i1, cp2, i2); - return (match_entry && match_operand); + bool match_bsm = compare_bootstrap_entry_to(i1, cp2, i2); + return (match_entry && match_bsm); } break; case JVM_CONSTANT_InvokeDynamic: @@ -1570,8 +1570,8 @@ int i1 = bootstrap_methods_attribute_index(index1); int i2 = cp2->bootstrap_methods_attribute_index(index2); bool match_entry = compare_entry_to(k1, cp2, k2); - bool match_operand = compare_operand_to(i1, cp2, i2); - return (match_entry && match_operand); + bool match_bsm = compare_bootstrap_entry_to(i1, cp2, i2); + return (match_entry && match_bsm); } break; case JVM_CONSTANT_String: @@ -1605,140 +1605,29 @@ return false; } // end compare_entry_to() - -// Resize the operands array with delta_len and delta_size. -// Used in RedefineClasses for CP merge. -void ConstantPool::resize_operands(int delta_len, int delta_size, TRAPS) { - int old_len = operand_array_length(operands()); - int new_len = old_len + delta_len; - int min_len = (delta_len > 0) ? old_len : new_len; - - int old_size = operands()->length(); - int new_size = old_size + delta_size; - int min_size = (delta_size > 0) ? old_size : new_size; - - ClassLoaderData* loader_data = pool_holder()->class_loader_data(); - Array* new_ops = MetadataFactory::new_array(loader_data, new_size, CHECK); - - // Set index in the resized array for existing elements only - for (int idx = 0; idx < min_len; idx++) { - int offset = operand_offset_at(idx); // offset in original array - operand_offset_at_put(new_ops, idx, offset + 2*delta_len); // offset in resized array - } - // Copy the bootstrap specifiers only - Copy::conjoint_memory_atomic(operands()->adr_at(2*old_len), - new_ops->adr_at(2*new_len), - (min_size - 2*min_len) * sizeof(u2)); - // Explicitly deallocate old operands array. - // Note, it is not needed for 7u backport. - if ( operands() != nullptr) { // the safety check - MetadataFactory::free_array(loader_data, operands()); - } - set_operands(new_ops); -} // end resize_operands() - - -// Extend the operands array with the length and size of the ext_cp operands. +// Extend the BSMAttributeEntries with the length and size of the ext_cp BSMAttributeEntries. // Used in RedefineClasses for CP merge. -void ConstantPool::extend_operands(const constantPoolHandle& ext_cp, TRAPS) { - int delta_len = operand_array_length(ext_cp->operands()); - if (delta_len == 0) { - return; // nothing to do - } - int delta_size = ext_cp->operands()->length(); - - assert(delta_len > 0 && delta_size > 0, "extended operands array must be bigger"); - - if (operand_array_length(operands()) == 0) { - ClassLoaderData* loader_data = pool_holder()->class_loader_data(); - Array* new_ops = MetadataFactory::new_array(loader_data, delta_size, CHECK); - // The first element index defines the offset of second part - operand_offset_at_put(new_ops, 0, 2*delta_len); // offset in new array - set_operands(new_ops); - } else { - resize_operands(delta_len, delta_size, CHECK); - } +BSMAttributeEntries::InsertionIterator +ConstantPool::start_extension(const constantPoolHandle& ext_cp, TRAPS) { + BSMAttributeEntries::InsertionIterator iter = + bsm_entries().start_extension(ext_cp->bsm_entries(), pool_holder()->class_loader_data(), + CHECK_(BSMAttributeEntries::InsertionIterator())); + return iter; +} -} // end extend_operands() +void ConstantPool::end_extension(BSMAttributeEntries::InsertionIterator iter, TRAPS) { + bsm_entries().end_extension(iter, pool_holder()->class_loader_data(), THREAD); +} -// Shrink the operands array to a smaller array with new_len length. -// Used in RedefineClasses for CP merge. -void ConstantPool::shrink_operands(int new_len, TRAPS) { - int old_len = operand_array_length(operands()); - if (new_len == old_len) { - return; // nothing to do - } - assert(new_len < old_len, "shrunken operands array must be smaller"); - - int free_base = operand_next_offset_at(new_len - 1); - int delta_len = new_len - old_len; - int delta_size = 2*delta_len + free_base - operands()->length(); - - resize_operands(delta_len, delta_size, CHECK); - -} // end shrink_operands() - - -void ConstantPool::copy_operands(const constantPoolHandle& from_cp, - const constantPoolHandle& to_cp, - TRAPS) { - - int from_oplen = operand_array_length(from_cp->operands()); - int old_oplen = operand_array_length(to_cp->operands()); - if (from_oplen != 0) { - ClassLoaderData* loader_data = to_cp->pool_holder()->class_loader_data(); - // append my operands to the target's operands array - if (old_oplen == 0) { - // Can't just reuse from_cp's operand list because of deallocation issues - int len = from_cp->operands()->length(); - Array* new_ops = MetadataFactory::new_array(loader_data, len, CHECK); - Copy::conjoint_memory_atomic( - from_cp->operands()->adr_at(0), new_ops->adr_at(0), len * sizeof(u2)); - to_cp->set_operands(new_ops); - } else { - int old_len = to_cp->operands()->length(); - int from_len = from_cp->operands()->length(); - int old_off = old_oplen * sizeof(u2); - int from_off = from_oplen * sizeof(u2); - // Use the metaspace for the destination constant pool - Array* new_operands = MetadataFactory::new_array(loader_data, old_len + from_len, CHECK); - int fillp = 0, len = 0; - // first part of dest - Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(0), - new_operands->adr_at(fillp), - (len = old_off) * sizeof(u2)); - fillp += len; - // first part of src - Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(0), - new_operands->adr_at(fillp), - (len = from_off) * sizeof(u2)); - fillp += len; - // second part of dest - Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(old_off), - new_operands->adr_at(fillp), - (len = old_len - old_off) * sizeof(u2)); - fillp += len; - // second part of src - Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(from_off), - new_operands->adr_at(fillp), - (len = from_len - from_off) * sizeof(u2)); - fillp += len; - assert(fillp == new_operands->length(), ""); - - // Adjust indexes in the first part of the copied operands array. - for (int j = 0; j < from_oplen; j++) { - int offset = operand_offset_at(new_operands, old_oplen + j); - assert(offset == operand_offset_at(from_cp->operands(), j), "correct copy"); - offset += old_len; // every new tuple is preceded by old_len extra u2's - operand_offset_at_put(new_operands, old_oplen + j, offset); - } - // replace target operands array with combined array - to_cp->set_operands(new_operands); - } - } -} // end copy_operands() +void ConstantPool::copy_bsm_entries(const constantPoolHandle& from_cp, + const constantPoolHandle& to_cp, + TRAPS) { + to_cp->bsm_entries().append(from_cp->bsm_entries(), + to_cp->pool_holder()->class_loader_data(), + THREAD); +} // Copy this constant pool's entries at start_i to end_i (inclusive) @@ -1768,7 +1657,7 @@ break; } } - copy_operands(from_cp, to_cp, CHECK); + copy_bsm_entries(from_cp, to_cp, THREAD); } // end copy_cp_to_impl() @@ -1892,7 +1781,7 @@ { int k1 = from_cp->bootstrap_methods_attribute_index(from_i); int k2 = from_cp->bootstrap_name_and_type_ref_index_at(from_i); - k1 += operand_array_length(to_cp->operands()); // to_cp might already have operands + k1 += to_cp->bsm_entries().array_length(); // to_cp might already have a BSM attribute to_cp->dynamic_constant_at_put(to_i, k1, k2); } break; @@ -1900,7 +1789,7 @@ { int k1 = from_cp->bootstrap_methods_attribute_index(from_i); int k2 = from_cp->bootstrap_name_and_type_ref_index_at(from_i); - k1 += operand_array_length(to_cp->operands()); // to_cp might already have operands + k1 += to_cp->bsm_entries().array_length(); // to_cp might already have a BSM attribute to_cp->invoke_dynamic_at_put(to_i, k1, k2); } break; @@ -1936,42 +1825,47 @@ // Compare this constant pool's bootstrap specifier at idx1 to the constant pool // cp2's bootstrap specifier at idx2. -bool ConstantPool::compare_operand_to(int idx1, const constantPoolHandle& cp2, int idx2) { - int k1 = operand_bootstrap_method_ref_index_at(idx1); - int k2 = cp2->operand_bootstrap_method_ref_index_at(idx2); +bool ConstantPool::compare_bootstrap_entry_to(int idx1, const constantPoolHandle& cp2, int idx2) { + const BSMAttributeEntry* const e1 = bsm_attribute_entry(idx1); + const BSMAttributeEntry* const e2 = cp2->bsm_attribute_entry(idx2); + int k1 = e1->bootstrap_method_index(); + int k2 = e2->bootstrap_method_index(); bool match = compare_entry_to(k1, cp2, k2); if (!match) { return false; } - int argc = operand_argument_count_at(idx1); - if (argc == cp2->operand_argument_count_at(idx2)) { - for (int j = 0; j < argc; j++) { - k1 = operand_argument_index_at(idx1, j); - k2 = cp2->operand_argument_index_at(idx2, j); - match = compare_entry_to(k1, cp2, k2); - if (!match) { - return false; - } + + const int argc = e1->argument_count(); + if (argc != e2->argument_count()) { + return false; + } + + for (int j = 0; j < argc; j++) { + k1 = e1->argument(j); + k2 = e2->argument(j); + match = compare_entry_to(k1, cp2, k2); + if (!match) { + return false; } - return true; // got through loop; all elements equal } - return false; -} // end compare_operand_to() + + return true; // got through loop; all elements equal +} // end compare_bootstrap_entry_to() // Search constant pool search_cp for a bootstrap specifier that matches // this constant pool's bootstrap specifier data at pattern_i index. // Return the index of a matching bootstrap attribute record or (-1) if there is no match. -int ConstantPool::find_matching_operand(int pattern_i, - const constantPoolHandle& search_cp, int search_len) { - for (int i = 0; i < search_len; i++) { - bool found = compare_operand_to(pattern_i, search_cp, i); +int ConstantPool::find_matching_bsm_entry(int pattern_i, + const constantPoolHandle& search_cp, int offset_limit) { + for (int i = 0; i < offset_limit; i++) { + bool found = compare_bootstrap_entry_to(pattern_i, search_cp, i); if (found) { return i; } } return -1; // bootstrap specifier data not found; return unused index (-1) -} // end find_matching_operand() +} // end find_matching_bsm_entry() #ifndef PRODUCT @@ -2406,7 +2300,7 @@ assert(is_constantPool(), "must be constantPool"); st->print("constant pool [%d]", length()); if (has_preresolution()) st->print("/preresolution"); - if (operands() != nullptr) st->print("/operands[%d]", operands()->length()); + if (!bsm_entries().is_empty()) st->print("/BSMs[%d]", bsm_entries().bootstrap_methods()->length()); print_address_on(st); if (pool_holder() != nullptr) { st->print(" for "); @@ -2441,3 +2335,87 @@ guarantee(pool_holder()->is_klass(), "should be klass"); } } + +void BSMAttributeEntries::deallocate_contents(ClassLoaderData* loader_data) { + MetadataFactory::free_array(loader_data, this->_offsets); + MetadataFactory::free_array(loader_data, this->_bootstrap_methods); + this->_offsets = nullptr; + this->_bootstrap_methods = nullptr; +} + +void BSMAttributeEntries::copy_into(InsertionIterator& iter, int num_entries) const { + assert(num_entries + iter._cur_offset <= iter._insert_into->_offsets->length(), "must"); + for (int i = 0; i < num_entries; i++) { + const BSMAttributeEntry* e = entry(i); + BSMAttributeEntry* e_new = iter.reserve_new_entry(e->bootstrap_method_index(), e->argument_count()); + assert(e_new != nullptr, "must be"); + e->copy_args_into(e_new); + } +} + +BSMAttributeEntries::InsertionIterator +BSMAttributeEntries::start_extension(const BSMAttributeEntries& other, ClassLoaderData* loader_data, TRAPS) { + InsertionIterator iter = start_extension(other.number_of_entries(), other.array_length(), + loader_data, CHECK_(BSMAttributeEntries::InsertionIterator())); + return iter; +} + +BSMAttributeEntries::InsertionIterator +BSMAttributeEntries::start_extension(int number_of_entries, int array_length, + ClassLoaderData* loader_data, TRAPS) { + InsertionIterator extension_iterator(this, this->number_of_entries(), this->array_length()); + int new_number_of_entries = this->number_of_entries() + number_of_entries; + int new_array_length = this->array_length() + array_length; + int invalid_index = new_array_length; + + Array* new_offsets = + MetadataFactory::new_array(loader_data, new_number_of_entries, invalid_index, CHECK_(InsertionIterator())); + Array* new_array = MetadataFactory::new_array(loader_data, new_array_length, CHECK_(InsertionIterator())); + { // Copy over all the old BSMAEntry's and their respective offsets + BSMAttributeEntries carrier(new_offsets, new_array); + InsertionIterator copy_iter(&carrier, 0, 0); + copy_into(copy_iter, this->number_of_entries()); + } + // Replace content + deallocate_contents(loader_data); + _offsets = new_offsets; + _bootstrap_methods = new_array; + return extension_iterator; +} + + +void BSMAttributeEntries::append(const BSMAttributeEntries& other, ClassLoaderData* loader_data, TRAPS) { + if (other.number_of_entries() == 0) { + return; // Done! + } + InsertionIterator iter = start_extension(other, loader_data, CHECK); + other.copy_into(iter, other.number_of_entries()); + end_extension(iter, loader_data, THREAD); +} + +void BSMAttributeEntries::end_extension(InsertionIterator& iter, ClassLoaderData* loader_data, TRAPS) { + assert(iter._insert_into == this, "must be"); + assert(iter._cur_offset <= this->_offsets->length(), "must be"); + assert(iter._cur_array <= this->_bootstrap_methods->length(), "must be"); + + // Did we fill up all of the available space? If so, do nothing. + if (iter._cur_offset == this->_offsets->length() && + iter._cur_array == this->_bootstrap_methods->length()) { + return; + } + + // We used less, truncate by allocating new arrays + Array* new_offsets = + MetadataFactory::new_array(loader_data, iter._cur_offset, 0, CHECK); + Array* new_array = + MetadataFactory::new_array(loader_data, iter._cur_array, CHECK); + { // Copy over the constructed BSMAEntry's + BSMAttributeEntries carrier(new_offsets, new_array); + InsertionIterator copy_iter(&carrier, 0, 0); + copy_into(copy_iter, iter._cur_offset); + } + + deallocate_contents(loader_data); + _offsets = new_offsets; + _bootstrap_methods = new_array; +} diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/oops/constantPool.hpp openjdk-25-25.0.5+8/src/hotspot/share/oops/constantPool.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/oops/constantPool.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/oops/constantPool.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "oops/arrayOop.hpp" +#include "oops/bsmAttribute.inline.hpp" #include "oops/cpCache.hpp" #include "oops/objArrayOop.hpp" #include "oops/oopHandle.hpp" @@ -89,7 +90,8 @@ Array* _tags; // the tag array describing the constant pool's contents ConstantPoolCache* _cache; // the cache holding interpreter runtime information InstanceKlass* _pool_holder; // the corresponding class - Array* _operands; // for variable-sized (InvokeDynamic) nodes, usually empty + + BSMAttributeEntries _bsm_entries; // Consider using an array of compressed klass pointers to // save space on 64-bit platforms. @@ -130,8 +132,6 @@ u1* tag_addr_at(int cp_index) const { return tags()->adr_at(cp_index); } - void set_operands(Array* operands) { _operands = operands; } - u2 flags() const { return _flags; } void set_flags(u2 f) { _flags = f; } @@ -171,7 +171,13 @@ virtual bool is_constantPool() const { return true; } Array* tags() const { return _tags; } - Array* operands() const { return _operands; } + + BSMAttributeEntries& bsm_entries() { + return _bsm_entries; + } + const BSMAttributeEntries& bsm_entries() const { + return _bsm_entries; + } bool has_preresolution() const { return (_flags & _has_preresolution) != 0; } void set_has_preresolution() { @@ -519,121 +525,37 @@ assert(tag_at(cp_index).has_bootstrap(), "Corrupted constant pool"); return extract_low_short_from_int(*int_at_addr(cp_index)); } - int bootstrap_operand_base(int cp_index) { - int bsms_attribute_index = bootstrap_methods_attribute_index(cp_index); - return operand_offset_at(operands(), bsms_attribute_index); - } - // The first part of the operands array consists of an index into the second part. - // Extract a 32-bit index value from the first part. - static int operand_offset_at(Array* operands, int bsms_attribute_index) { - int n = (bsms_attribute_index * 2); - assert(n >= 0 && n+2 <= operands->length(), "oob"); - // The first 32-bit index points to the beginning of the second part - // of the operands array. Make sure this index is in the first part. - DEBUG_ONLY(int second_part = build_int_from_shorts(operands->at(0), - operands->at(1))); - assert(second_part == 0 || n+2 <= second_part, "oob (2)"); - int offset = build_int_from_shorts(operands->at(n+0), - operands->at(n+1)); - // The offset itself must point into the second part of the array. - assert(offset == 0 || (offset >= second_part && offset <= operands->length()), "oob (3)"); - return offset; - } - static void operand_offset_at_put(Array* operands, int bsms_attribute_index, int offset) { - int n = bsms_attribute_index * 2; - assert(n >= 0 && n+2 <= operands->length(), "oob"); - operands->at_put(n+0, extract_low_short_from_int(offset)); - operands->at_put(n+1, extract_high_short_from_int(offset)); - } - static int operand_array_length(Array* operands) { - if (operands == nullptr || operands->length() == 0) return 0; - int second_part = operand_offset_at(operands, 0); - return (second_part / 2); - } - -#ifdef ASSERT - // operand tuples fit together exactly, end to end - static int operand_limit_at(Array* operands, int bsms_attribute_index) { - int nextidx = bsms_attribute_index + 1; - if (nextidx == operand_array_length(operands)) - return operands->length(); - else - return operand_offset_at(operands, nextidx); - } - int bootstrap_operand_limit(int cp_index) { - int bsms_attribute_index = bootstrap_methods_attribute_index(cp_index); - return operand_limit_at(operands(), bsms_attribute_index); - } -#endif //ASSERT - - // Layout of InvokeDynamic and Dynamic bootstrap method specifier - // data in second part of operands array. This encodes one record in - // the BootstrapMethods attribute. The whole specifier also includes - // the name and type information from the main constant pool entry. - enum { - _indy_bsm_offset = 0, // CONSTANT_MethodHandle bsm - _indy_argc_offset = 1, // u2 argc - _indy_argv_offset = 2 // u2 argv[argc] - }; - // These functions are used in RedefineClasses for CP merge + BSMAttributeEntry* bsm_attribute_entry(int bsms_attribute_index) { + return _bsm_entries.entry(bsms_attribute_index); + } - int operand_offset_at(int bsms_attribute_index) { - assert(0 <= bsms_attribute_index && - bsms_attribute_index < operand_array_length(operands()), - "Corrupted CP operands"); - return operand_offset_at(operands(), bsms_attribute_index); - } - u2 operand_bootstrap_method_ref_index_at(int bsms_attribute_index) { - int offset = operand_offset_at(bsms_attribute_index); - return operands()->at(offset + _indy_bsm_offset); - } - u2 operand_argument_count_at(int bsms_attribute_index) { - int offset = operand_offset_at(bsms_attribute_index); - u2 argc = operands()->at(offset + _indy_argc_offset); - return argc; - } - u2 operand_argument_index_at(int bsms_attribute_index, int j) { - int offset = operand_offset_at(bsms_attribute_index); - return operands()->at(offset + _indy_argv_offset + j); - } - int operand_next_offset_at(int bsms_attribute_index) { - int offset = operand_offset_at(bsms_attribute_index) + _indy_argv_offset - + operand_argument_count_at(bsms_attribute_index); - return offset; - } - // Compare a bootstrap specifier data in the operands arrays - bool compare_operand_to(int bsms_attribute_index1, const constantPoolHandle& cp2, - int bsms_attribute_index2); - // Find a bootstrap specifier data in the operands array - int find_matching_operand(int bsms_attribute_index, const constantPoolHandle& search_cp, - int operands_cur_len); - // Resize the operands array with delta_len and delta_size - void resize_operands(int delta_len, int delta_size, TRAPS); - // Extend the operands array with the length and size of the ext_cp operands - void extend_operands(const constantPoolHandle& ext_cp, TRAPS); - // Shrink the operands array to a smaller array with new_len length - void shrink_operands(int new_len, TRAPS); + bool compare_bootstrap_entry_to(int bsms_attribute_index1, const constantPoolHandle& cp2, + int bsms_attribute_index2); + // Find a BSM entry in search_cp that matches the BSM at bsm_attribute_index. + // Return -1 if not found. + int find_matching_bsm_entry(int bsms_attribute_index, const constantPoolHandle& search_cp, + int offset_limit); + // Extend the BSM attribute storage to fit both the current data and the BSM data in ext_cp. + // Use the returned InsertionIterator to fill out the newly allocated space. + BSMAttributeEntries::InsertionIterator start_extension(const constantPoolHandle& ext_cp, TRAPS); + void end_extension(BSMAttributeEntries::InsertionIterator iter, TRAPS); u2 bootstrap_method_ref_index_at(int cp_index) { assert(tag_at(cp_index).has_bootstrap(), "Corrupted constant pool"); - int op_base = bootstrap_operand_base(cp_index); - return operands()->at(op_base + _indy_bsm_offset); + int bsmai = bootstrap_methods_attribute_index(cp_index); + return bsm_attribute_entry(bsmai)->bootstrap_method_index(); } u2 bootstrap_argument_count_at(int cp_index) { assert(tag_at(cp_index).has_bootstrap(), "Corrupted constant pool"); - int op_base = bootstrap_operand_base(cp_index); - u2 argc = operands()->at(op_base + _indy_argc_offset); - DEBUG_ONLY(int end_offset = op_base + _indy_argv_offset + argc; - int next_offset = bootstrap_operand_limit(cp_index)); - assert(end_offset == next_offset, "matched ending"); - return argc; + int bsmai = bootstrap_methods_attribute_index(cp_index); + return bsm_attribute_entry(bsmai)->argument_count(); } u2 bootstrap_argument_index_at(int cp_index, int j) { - int op_base = bootstrap_operand_base(cp_index); - DEBUG_ONLY(int argc = operands()->at(op_base + _indy_argc_offset)); - assert((uint)j < (uint)argc, "oob"); - return operands()->at(op_base + _indy_argv_offset + j); + int bsmai = bootstrap_methods_attribute_index(cp_index); + BSMAttributeEntry* bsme = bsm_attribute_entry(bsmai); + assert((uint)j < (uint)bsme->argument_count(), "oob"); + return bsm_attribute_entry(bsmai)->argument(j); } // The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve, @@ -840,7 +762,7 @@ } static void copy_cp_to_impl(const constantPoolHandle& from_cp, int start_cpi, int end_cpi, const constantPoolHandle& to_cp, int to_cpi, TRAPS); static void copy_entry_to(const constantPoolHandle& from_cp, int from_cpi, const constantPoolHandle& to_cp, int to_cpi); - static void copy_operands(const constantPoolHandle& from_cp, const constantPoolHandle& to_cp, TRAPS); + static void copy_bsm_entries(const constantPoolHandle& from_cp, const constantPoolHandle& to_cp, TRAPS); int find_matching_entry(int pattern_i, const constantPoolHandle& search_cp); int version() const { return _saved._version; } void set_version(int version) { _saved._version = version; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/oops/oop.hpp openjdk-25-25.0.5+8/src/hotspot/share/oops/oop.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/oops/oop.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/oops/oop.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -64,9 +64,11 @@ // Must be trivial; see verifying static assert after the class. oopDesc() = default; + inline void* base_addr(); + inline const void* base_addr() const; + inline markWord mark() const; inline markWord mark_acquire() const; - inline markWord* mark_addr() const; inline void set_mark(markWord m); static inline void set_mark(HeapWord* mem, markWord m); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/oops/oop.inline.hpp openjdk-25-25.0.5+8/src/hotspot/share/oops/oop.inline.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/oops/oop.inline.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/oops/oop.inline.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -47,6 +47,9 @@ // Implementation of all inlined member functions defined in oop.hpp // We need a separate file to avoid circular references +void* oopDesc::base_addr() { return this; } +const void* oopDesc::base_addr() const { return this; } + markWord oopDesc::mark() const { return Atomic::load(&_mark); } @@ -55,10 +58,6 @@ return Atomic::load_acquire(&_mark); } -markWord* oopDesc::mark_addr() const { - return (markWord*) &_mark; -} - void oopDesc::set_mark(markWord m) { Atomic::store(&_mark, m); } @@ -120,7 +119,7 @@ Klass* oopDesc::klass_or_null_acquire() const { switch (ObjLayout::klass_mode()) { case ObjLayout::Compact: - return mark_acquire().klass(); + return mark_acquire().klass_or_null(); case ObjLayout::Compressed: { narrowKlass narrow_klass = Atomic::load_acquire(&_metadata._compressed_klass); return CompressedKlassPointers::decode(narrow_klass); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/arraycopynode.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/arraycopynode.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/arraycopynode.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/arraycopynode.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -182,6 +182,12 @@ return nullptr; } + Node* out_mem = proj_out_or_null(TypeFunc::Memory); + if (can_reshape && out_mem == nullptr) { // dead node? + return NodeSentinel; + } + + Node* base_src = in(ArrayCopyNode::Src); Node* base_dest = in(ArrayCopyNode::Dest); Node* ctl = in(TypeFunc::Control); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/c2compiler.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/c2compiler.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/c2compiler.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/c2compiler.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -767,7 +767,7 @@ case vmIntrinsics::_doubleToRawLongBits: case vmIntrinsics::_doubleToLongBits: case vmIntrinsics::_longBitsToDouble: - case vmIntrinsics::_Reference_get: + case vmIntrinsics::_Reference_get0: case vmIntrinsics::_Reference_refersTo0: case vmIntrinsics::_PhantomReference_refersTo0: case vmIntrinsics::_Reference_clear0: diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/callnode.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/callnode.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/callnode.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/callnode.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -42,6 +42,7 @@ #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" #include "utilities/powerOfTwo.hpp" #include "code/vmreg.hpp" @@ -935,7 +936,7 @@ } -void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj, bool do_asserts) { +void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj, bool do_asserts) const { projs->fallthrough_proj = nullptr; projs->fallthrough_catchproj = nullptr; projs->fallthrough_ioproj = nullptr; @@ -1319,6 +1320,76 @@ //============================================================================= +bool CallLeafPureNode::is_unused() const { + return proj_out_or_null(TypeFunc::Parms) == nullptr; +} + +bool CallLeafPureNode::is_dead() const { + return proj_out_or_null(TypeFunc::Control) == nullptr; +} + +/* We make a tuple of the global input state + TOP for the output values. + * We use this to delete a pure function that is not used: by replacing the call with + * such a tuple, we let output Proj's idealization pick the corresponding input of the + * pure call, so jumping over it, and effectively, removing the call from the graph. + * This avoids doing the graph surgery manually, but leaves that to IGVN + * that is specialized for doing that right. We need also tuple components for output + * values of the function to respect the return arity, and in case there is a projection + * that would pick an output (which shouldn't happen at the moment). + */ +TupleNode* CallLeafPureNode::make_tuple_of_input_state_and_top_return_values(const Compile* C) const { + // Transparently propagate input state but parameters + TupleNode* tuple = TupleNode::make( + tf()->range(), + in(TypeFunc::Control), + in(TypeFunc::I_O), + in(TypeFunc::Memory), + in(TypeFunc::FramePtr), + in(TypeFunc::ReturnAdr)); + + // And add TOPs for the return values + for (uint i = TypeFunc::Parms; i < tf()->range()->cnt(); i++) { + tuple->set_req(i, C->top()); + } + + return tuple; +} + +CallLeafPureNode* CallLeafPureNode::inline_call_leaf_pure_node(Node* control) const { + Node* top = Compile::current()->top(); + if (control == nullptr) { + control = in(TypeFunc::Control); + } + + CallLeafPureNode* call = new CallLeafPureNode(tf(), entry_point(), _name, nullptr); + call->init_req(TypeFunc::Control, control); + call->init_req(TypeFunc::I_O, top); + call->init_req(TypeFunc::Memory, top); + call->init_req(TypeFunc::ReturnAdr, top); + call->init_req(TypeFunc::FramePtr, top); + for (unsigned int i = 0; i < tf()->domain()->cnt() - TypeFunc::Parms; i++) { + call->init_req(TypeFunc::Parms + i, in(TypeFunc::Parms + i)); + } + + return call; +} + +Node* CallLeafPureNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (is_dead()) { + return nullptr; + } + + // We need to wait until IGVN because during parsing, usages might still be missing + // and we would remove the call immediately. + if (can_reshape && is_unused()) { + // The result is not used. We remove the call by replacing it with a tuple, that + // is later disintegrated by the projections. + return make_tuple_of_input_state_and_top_return_values(phase->C); + } + + return CallRuntimeNode::Ideal(phase, can_reshape); +} + #ifndef PRODUCT void CallLeafNode::dump_spec(outputStream *st) const { st->print("# "); @@ -2373,3 +2444,158 @@ return true; } + +PowDNode::PowDNode(Compile* C, Node* base, Node* exp) + : CallLeafPureNode( + OptoRuntime::Math_DD_D_Type(), + StubRoutines::dpow() != nullptr ? StubRoutines::dpow() : CAST_FROM_FN_PTR(address, SharedRuntime::dpow), + "pow", + nullptr) { + add_flag(Flag_is_macro); + C->add_macro_node(this); + + init_req(TypeFunc::Parms + 0, base); + init_req(TypeFunc::Parms + 1, C->top()); // double slot padding + init_req(TypeFunc::Parms + 2, exp); + init_req(TypeFunc::Parms + 3, C->top()); // double slot padding +} + +const Type* PowDNode::Value(PhaseGVN* phase) const { + const Type* t_base = phase->type(base()); + const Type* t_exp = phase->type(exp()); + + if (t_base == Type::TOP || t_exp == Type::TOP) { + return Type::TOP; + } + + const TypeD* base_con = t_base->isa_double_constant(); + const TypeD* exp_con = t_exp->isa_double_constant(); + const TypeD* result_t = nullptr; + + // constant folding: both inputs are constants + if (base_con != nullptr && exp_con != nullptr) { + result_t = TypeD::make(SharedRuntime::dpow(base_con->getd(), exp_con->getd())); + } + + // Special cases when only the exponent is known: + if (exp_con != nullptr) { + double e = exp_con->getd(); + + // If the second argument is positive or negative zero, then the result is 1.0. + // i.e., pow(x, +/-0.0D) => 1.0 + if (e == 0.0) { // true for both -0.0 and +0.0 + result_t = TypeD::ONE; + } + + // If the second argument is NaN, then the result is NaN. + // i.e., pow(x, NaN) => NaN + if (g_isnan(e)) { + result_t = TypeD::make(NAN); + } + } + + if (result_t != nullptr) { + // We can't simply return a TypeD here, it must be a tuple type to be compatible with call nodes. + const Type** fields = TypeTuple::fields(2); + fields[TypeFunc::Parms + 0] = result_t; + fields[TypeFunc::Parms + 1] = Type::HALF; + return TypeTuple::make(TypeFunc::Parms + 2, fields); + } + + return tf()->range(); +} + +Node* PowDNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (!can_reshape) { + return nullptr; // wait for igvn + } + + PhaseIterGVN* igvn = phase->is_IterGVN(); + Node* base = this->base(); + Node* exp = this->exp(); + + const Type* t_exp = phase->type(exp); + const TypeD* exp_con = t_exp->isa_double_constant(); + + // Special cases when only the exponent is known: + if (exp_con != nullptr) { + double e = exp_con->getd(); + + // If the second argument is 1.0, then the result is the same as the first argument. + // i.e., pow(x, 1.0) => x + if (e == 1.0) { + return make_tuple_of_input_state_and_result(igvn, base); + } + + // If the second argument is 2.0, then strength reduce to multiplications. + // i.e., pow(x, 2.0) => x * x + if (e == 2.0) { + Node* mul = igvn->transform(new MulDNode(base, base)); + return make_tuple_of_input_state_and_result(igvn, mul); + } + + // If the second argument is 0.5, the strength reduce to square roots. + // i.e., pow(x, 0.5) => sqrt(x) iff x > 0 + if (e == 0.5 && Matcher::match_rule_supported(Op_SqrtD)) { + Node* ctrl = in(TypeFunc::Control); + Node* zero = igvn->zerocon(T_DOUBLE); + + // According to the API specs, pow(-0.0, 0.5) = 0.0 and sqrt(-0.0) = -0.0. + // So pow(-0.0, 0.5) shouldn't be replaced with sqrt(-0.0). + // -0.0/+0.0 are both excluded since floating-point comparison doesn't distinguish -0.0 from +0.0. + Node* cmp = igvn->register_new_node_with_optimizer(new CmpDNode(base, zero)); + Node* test = igvn->register_new_node_with_optimizer(new BoolNode(cmp, BoolTest::le)); + + IfNode* iff = new IfNode(ctrl, test, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN); + igvn->register_new_node_with_optimizer(iff); + Node* if_slow = igvn->register_new_node_with_optimizer(new IfTrueNode(iff)); // x <= 0 + Node* if_fast = igvn->register_new_node_with_optimizer(new IfFalseNode(iff)); // x > 0 + + // slow path: call pow(x, 0.5) + Node* call = igvn->register_new_node_with_optimizer(inline_call_leaf_pure_node(if_slow)); + Node* call_ctrl = igvn->register_new_node_with_optimizer(new ProjNode(call, TypeFunc::Control)); + Node* call_result = igvn->register_new_node_with_optimizer(new ProjNode(call, TypeFunc::Parms + 0)); + + // fast path: sqrt(x) + Node* sqrt = igvn->register_new_node_with_optimizer(new SqrtDNode(igvn->C, if_fast, base)); + + // merge paths + RegionNode* region = new RegionNode(3); + igvn->register_new_node_with_optimizer(region); + region->init_req(1, call_ctrl); // slow path + region->init_req(2, if_fast); // fast path + + PhiNode* phi = new PhiNode(region, Type::DOUBLE); + igvn->register_new_node_with_optimizer(phi); + phi->init_req(1, call_result); // slow: pow() result + phi->init_req(2, sqrt); // fast: sqrt() result + + igvn->C->set_has_split_ifs(true); // Has chance for split-if optimization + + return make_tuple_of_input_state_and_result(igvn, phi, region); + } + } + + return CallLeafPureNode::Ideal(phase, can_reshape); +} + +// We can't simply have Ideal() returning a Con or MulNode since the users are still expecting a Call node, but we could +// produce a tuple that follows the same pattern so users can still get control, io, memory, etc.. +TupleNode* PowDNode::make_tuple_of_input_state_and_result(PhaseIterGVN* phase, Node* result, Node* control) { + if (control == nullptr) { + control = in(TypeFunc::Control); + } + + Compile* C = phase->C; + C->remove_macro_node(this); + TupleNode* tuple = TupleNode::make( + tf()->range(), + control, + in(TypeFunc::I_O), + in(TypeFunc::Memory), + in(TypeFunc::FramePtr), + in(TypeFunc::ReturnAdr), + result, + C->top()); + return tuple; +} diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/callnode.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/callnode.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/callnode.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/callnode.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -752,7 +752,7 @@ // 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); + void extract_projections(CallProjections* projs, bool separate_io_proj, bool do_asserts = true) const; virtual uint match_edge(uint idx) const; @@ -820,11 +820,14 @@ // calls and optimized virtual calls, plus calls to wrappers for run-time // routines); generates static stub. class CallStaticJavaNode : public CallJavaNode { + // If this is an uncommon trap guarded by some condition, is it safe to change the condition to a narrower condition? + // See comment in PhaseIdealLoop::do_split_if() + bool _safe_for_fold_compare; virtual bool cmp( const Node &n ) const; virtual uint size_of() const; // Size is bigger public: CallStaticJavaNode(Compile* C, const TypeFunc* tf, address addr, ciMethod* method) - : CallJavaNode(tf, addr, method) { + : CallJavaNode(tf, addr, method), _safe_for_fold_compare(true) { init_class_id(Class_CallStaticJava); if (C->eliminate_boxing() && (method != nullptr) && method->is_boxing_method()) { init_flags(Flag_is_macro); @@ -832,7 +835,7 @@ } } CallStaticJavaNode(const TypeFunc* tf, address addr, const char* name, const TypePtr* adr_type) - : CallJavaNode(tf, addr, nullptr) { + : CallJavaNode(tf, addr, nullptr), _safe_for_fold_compare(true) { init_class_id(Class_CallStaticJava); // This node calls a runtime stub, which often has narrow memory effects. _adr_type = adr_type; @@ -856,6 +859,14 @@ virtual int Opcode() const; virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + void clear_safe_for_fold_compare() { + _safe_for_fold_compare = false; + } + + bool safe_for_fold_compare() const { + return _safe_for_fold_compare; + } + #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; virtual void dump_compact_spec(outputStream *st) const; @@ -928,6 +939,35 @@ #endif }; +/* A pure function call, they are assumed not to be safepoints, not to read or write memory, + * have no exception... They just take parameters, return a value without side effect. It is + * always correct to create some, or remove them, if the result is not used. + * + * They still have control input to allow easy lowering into other kind of calls that require + * a control, but this is more a technical than a moral constraint. + * + * Pure calls must have only control and data input and output: I/O, Memory and so on must be top. + * Nevertheless, pure calls can typically be expensive math operations so care must be taken + * when letting the node float. + */ +class CallLeafPureNode : public CallLeafNode { +protected: + bool is_unused() const; + bool is_dead() const; + TupleNode* make_tuple_of_input_state_and_top_return_values(const Compile* C) const; + +public: + CallLeafPureNode(const TypeFunc* tf, address addr, const char* name, + const TypePtr* adr_type) + : CallLeafNode(tf, addr, name, adr_type) { + init_class_id(Class_CallLeafPure); + } + int Opcode() const override; + Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + + CallLeafPureNode* inline_call_leaf_pure_node(Node* control = nullptr) const; +}; + //------------------------------CallLeafNoFPNode------------------------------- // CallLeafNode, not using floating point or using it in the same manner as // the generated code @@ -1277,4 +1317,19 @@ JVMState* dbg_jvms() const { return nullptr; } #endif }; + +//------------------------------PowDNode-------------------------------------- +class PowDNode : public CallLeafPureNode { + TupleNode* make_tuple_of_input_state_and_result(PhaseIterGVN* phase, Node* result, Node* control = nullptr); + +public: + PowDNode(Compile* C, Node* base, Node* exp); + int Opcode() const override; + const Type* Value(PhaseGVN* phase) const override; + Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + + Node* base() const { return in(TypeFunc::Parms + 0); } + Node* exp() const { return in(TypeFunc::Parms + 2); } +}; + #endif // SHARE_OPTO_CALLNODE_HPP diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/cfgnode.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/cfgnode.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/cfgnode.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/cfgnode.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -457,6 +457,7 @@ #endif bool same_condition(const Node* dom, PhaseIterGVN* igvn) const; + void mark_projections_unsafe_for_fold_compare() const; }; class RangeCheckNode : public IfNode { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/classes.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/classes.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/classes.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/classes.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -61,6 +61,7 @@ macro(CallJava) macro(CallLeaf) macro(CallLeafNoFP) +macro(CallLeafPure) macro(CallLeafVector) macro(CallRuntime) macro(CallStaticJava) @@ -282,6 +283,7 @@ macro(OpaqueNotNull) macro(OpaqueInitializedAssertionPredicate) macro(OpaqueTemplateAssertionPredicate) +macro(PowD) macro(ProfileBoolean) macro(OrI) macro(OrL) @@ -372,6 +374,7 @@ macro(SubL) macro(TailCall) macro(TailJump) +macro(Tuple) macro(MacroLogicV) macro(ThreadLocal) macro(Unlock) diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/compile.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/compile.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/compile.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/compile.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -783,19 +783,9 @@ StartNode* s = new StartNode(root(), tf()->domain()); initial_gvn()->set_type_bottom(s); verify_start(s); - if (method()->intrinsic_id() == vmIntrinsics::_Reference_get) { - // With java.lang.ref.reference.get() we must go through the - // intrinsic - even when get() is the root - // method of the compile - so that, if necessary, the value in - // the referent field of the reference object gets recorded by - // the pre-barrier code. - cg = find_intrinsic(method(), false); - } - if (cg == nullptr) { - float past_uses = method()->interpreter_invocation_count(); - float expected_uses = past_uses; - cg = CallGenerator::for_inline(method(), expected_uses); - } + float past_uses = method()->interpreter_invocation_count(); + float expected_uses = past_uses; + cg = CallGenerator::for_inline(method(), expected_uses); } if (failing()) return; if (cg == nullptr) { @@ -3298,6 +3288,25 @@ case Op_Opaque1: // Remove Opaque Nodes before matching n->subsume_by(n->in(1), this); break; + case Op_CallLeafPure: { + // If the pure call is not supported, then lower to a CallLeaf. + if (!Matcher::match_rule_supported(Op_CallLeafPure)) { + CallNode* call = n->as_Call(); + CallNode* new_call = new CallLeafNode(call->tf(), call->entry_point(), + call->_name, TypeRawPtr::BOTTOM); + new_call->init_req(TypeFunc::Control, call->in(TypeFunc::Control)); + new_call->init_req(TypeFunc::I_O, C->top()); + new_call->init_req(TypeFunc::Memory, C->top()); + new_call->init_req(TypeFunc::ReturnAdr, C->top()); + new_call->init_req(TypeFunc::FramePtr, C->top()); + for (unsigned int i = TypeFunc::Parms; i < call->tf()->domain()->cnt(); i++) { + new_call->init_req(i, call->in(i)); + } + n->subsume_by(new_call, this); + } + frc.inc_call_count(); + break; + } case Op_CallStaticJava: case Op_CallJava: case Op_CallDynamicJava: diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/divnode.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/divnode.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/divnode.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/divnode.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -42,19 +42,19 @@ #include -ModFloatingNode::ModFloatingNode(Compile* C, const TypeFunc* tf, const char* name) : CallLeafNode(tf, nullptr, name, TypeRawPtr::BOTTOM) { +ModFloatingNode::ModFloatingNode(Compile* C, const TypeFunc* tf, address addr, const char* name) : CallLeafPureNode(tf, addr, name, TypeRawPtr::BOTTOM) { add_flag(Flag_is_macro); C->add_macro_node(this); } -ModDNode::ModDNode(Compile* C, Node* a, Node* b) : ModFloatingNode(C, OptoRuntime::Math_DD_D_Type(), "drem") { +ModDNode::ModDNode(Compile* C, Node* a, Node* b) : ModFloatingNode(C, OptoRuntime::Math_DD_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::drem), "drem") { init_req(TypeFunc::Parms + 0, a); init_req(TypeFunc::Parms + 1, C->top()); init_req(TypeFunc::Parms + 2, b); init_req(TypeFunc::Parms + 3, C->top()); } -ModFNode::ModFNode(Compile* C, Node* a, Node* b) : ModFloatingNode(C, OptoRuntime::modf_Type(), "frem") { +ModFNode::ModFNode(Compile* C, Node* a, Node* b) : ModFloatingNode(C, OptoRuntime::modf_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::frem), "frem") { init_req(TypeFunc::Parms + 0, a); init_req(TypeFunc::Parms + 1, b); } @@ -1516,137 +1516,109 @@ return unsigned_mod_value(phase, this); } -Node* ModFNode::Ideal(PhaseGVN* phase, bool can_reshape) { - if (!can_reshape) { - return nullptr; - } - PhaseIterGVN* igvn = phase->is_IterGVN(); - - bool result_is_unused = proj_out_or_null(TypeFunc::Parms) == nullptr; - bool not_dead = proj_out_or_null(TypeFunc::Control) != nullptr; - if (result_is_unused && not_dead) { - return replace_with_con(igvn, TypeF::make(0.)); - } - - // Either input is TOP ==> the result is TOP - const Type* t1 = phase->type(dividend()); - const Type* t2 = phase->type(divisor()); - if (t1 == Type::TOP || t2 == Type::TOP) { - return phase->C->top(); - } - +const Type* ModFNode::get_result_if_constant(const Type* dividend, const Type* divisor) const { // If either number is not a constant, we know nothing. - if ((t1->base() != Type::FloatCon) || (t2->base() != Type::FloatCon)) { + if ((dividend->base() != Type::FloatCon) || (divisor->base() != Type::FloatCon)) { return nullptr; // note: x%x can be either NaN or 0 } - float f1 = t1->getf(); - float f2 = t2->getf(); - jint x1 = jint_cast(f1); // note: *(int*)&f1, not just (int)f1 - jint x2 = jint_cast(f2); + float dividend_f = dividend->getf(); + float divisor_f = divisor->getf(); + jint dividend_i = jint_cast(dividend_f); // note: *(int*)&f1, not just (int)f1 + jint divisor_i = jint_cast(divisor_f); // If either is a NaN, return an input NaN - if (g_isnan(f1)) { - return replace_with_con(igvn, t1); + if (g_isnan(dividend_f)) { + return dividend; } - if (g_isnan(f2)) { - return replace_with_con(igvn, t2); + if (g_isnan(divisor_f)) { + return divisor; } // If an operand is infinity or the divisor is +/- zero, punt. - if (!g_isfinite(f1) || !g_isfinite(f2) || x2 == 0 || x2 == min_jint) { + if (!g_isfinite(dividend_f) || !g_isfinite(divisor_f) || divisor_i == 0 || divisor_i == min_jint) { return nullptr; } // We must be modulo'ing 2 float constants. // Make sure that the sign of the fmod is equal to the sign of the dividend - jint xr = jint_cast(fmod(f1, f2)); - if ((x1 ^ xr) < 0) { + jint xr = jint_cast(fmod(dividend_f, divisor_f)); + if ((dividend_i ^ xr) < 0) { xr ^= min_jint; } - return replace_with_con(igvn, TypeF::make(jfloat_cast(xr))); + return TypeF::make(jfloat_cast(xr)); } -Node* ModDNode::Ideal(PhaseGVN* phase, bool can_reshape) { - if (!can_reshape) { - return nullptr; - } - PhaseIterGVN* igvn = phase->is_IterGVN(); - - bool result_is_unused = proj_out_or_null(TypeFunc::Parms) == nullptr; - bool not_dead = proj_out_or_null(TypeFunc::Control) != nullptr; - if (result_is_unused && not_dead) { - return replace_with_con(igvn, TypeD::make(0.)); - } - - // Either input is TOP ==> the result is TOP - const Type* t1 = phase->type(dividend()); - const Type* t2 = phase->type(divisor()); - if (t1 == Type::TOP || t2 == Type::TOP) { - return nullptr; - } - +const Type* ModDNode::get_result_if_constant(const Type* dividend, const Type* divisor) const { // If either number is not a constant, we know nothing. - if ((t1->base() != Type::DoubleCon) || (t2->base() != Type::DoubleCon)) { + if ((dividend->base() != Type::DoubleCon) || (divisor->base() != Type::DoubleCon)) { return nullptr; // note: x%x can be either NaN or 0 } - double f1 = t1->getd(); - double f2 = t2->getd(); - jlong x1 = jlong_cast(f1); // note: *(long*)&f1, not just (long)f1 - jlong x2 = jlong_cast(f2); + double dividend_d = dividend->getd(); + double divisor_d = divisor->getd(); + jlong dividend_l = jlong_cast(dividend_d); // note: *(long*)&f1, not just (long)f1 + jlong divisor_l = jlong_cast(divisor_d); // If either is a NaN, return an input NaN - if (g_isnan(f1)) { - return replace_with_con(igvn, t1); + if (g_isnan(dividend_d)) { + return dividend; } - if (g_isnan(f2)) { - return replace_with_con(igvn, t2); + if (g_isnan(divisor_d)) { + return divisor; } // If an operand is infinity or the divisor is +/- zero, punt. - if (!g_isfinite(f1) || !g_isfinite(f2) || x2 == 0 || x2 == min_jlong) { + if (!g_isfinite(dividend_d) || !g_isfinite(divisor_d) || divisor_l == 0 || divisor_l == min_jlong) { return nullptr; } // We must be modulo'ing 2 double constants. // Make sure that the sign of the fmod is equal to the sign of the dividend - jlong xr = jlong_cast(fmod(f1, f2)); - if ((x1 ^ xr) < 0) { + jlong xr = jlong_cast(fmod(dividend_d, divisor_d)); + if ((dividend_l ^ xr) < 0) { xr ^= min_jlong; } - return replace_with_con(igvn, TypeD::make(jdouble_cast(xr))); + return TypeD::make(jdouble_cast(xr)); +} + +Node* ModFloatingNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (can_reshape) { + PhaseIterGVN* igvn = phase->is_IterGVN(); + + // Either input is TOP ==> the result is TOP + const Type* dividend_type = phase->type(dividend()); + const Type* divisor_type = phase->type(divisor()); + if (dividend_type == Type::TOP || divisor_type == Type::TOP) { + return phase->C->top(); + } + const Type* constant_result = get_result_if_constant(dividend_type, divisor_type); + if (constant_result != nullptr) { + return make_tuple_of_input_state_and_constant_result(igvn, constant_result); + } + } + + return CallLeafPureNode::Ideal(phase, can_reshape); } -Node* ModFloatingNode::replace_with_con(PhaseIterGVN* phase, const Type* con) { - Compile* C = phase->C; +/* Give a tuple node for ::Ideal to return, made of the input state (control to return addr) + * and the given constant result. Idealization of projections will make sure to transparently + * propagate the input state and replace the result by the said constant. + */ +TupleNode* ModFloatingNode::make_tuple_of_input_state_and_constant_result(PhaseIterGVN* phase, const Type* con) const { Node* con_node = phase->makecon(con); - CallProjections projs; - extract_projections(&projs, false, false); - phase->replace_node(projs.fallthrough_proj, in(TypeFunc::Control)); - if (projs.fallthrough_catchproj != nullptr) { - phase->replace_node(projs.fallthrough_catchproj, in(TypeFunc::Control)); - } - if (projs.fallthrough_memproj != nullptr) { - phase->replace_node(projs.fallthrough_memproj, in(TypeFunc::Memory)); - } - if (projs.catchall_memproj != nullptr) { - phase->replace_node(projs.catchall_memproj, C->top()); - } - if (projs.fallthrough_ioproj != nullptr) { - phase->replace_node(projs.fallthrough_ioproj, in(TypeFunc::I_O)); - } - assert(projs.catchall_ioproj == nullptr, "no exceptions from floating mod"); - assert(projs.catchall_catchproj == nullptr, "no exceptions from floating mod"); - if (projs.resproj != nullptr) { - phase->replace_node(projs.resproj, con_node); - } - phase->replace_node(this, C->top()); - C->remove_macro_node(this); - disconnect_inputs(C); - return nullptr; + TupleNode* tuple = TupleNode::make( + tf()->range(), + in(TypeFunc::Control), + in(TypeFunc::I_O), + in(TypeFunc::Memory), + in(TypeFunc::FramePtr), + in(TypeFunc::ReturnAdr), + con_node); + + return tuple; } //============================================================================= diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/divnode.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/divnode.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/divnode.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/divnode.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -156,40 +156,45 @@ }; // Base class for float and double modulus -class ModFloatingNode : public CallLeafNode { +class ModFloatingNode : public CallLeafPureNode { + TupleNode* make_tuple_of_input_state_and_constant_result(PhaseIterGVN* phase, const Type* con) const; + protected: - Node* replace_with_con(PhaseIterGVN* phase, const Type* con); + virtual Node* dividend() const = 0; + virtual Node* divisor() const = 0; + virtual const Type* get_result_if_constant(const Type* dividend, const Type* divisor) const = 0; public: - ModFloatingNode(Compile* C, const TypeFunc* tf, const char *name); + ModFloatingNode(Compile* C, const TypeFunc* tf, address addr, const char* name); + Node* Ideal(PhaseGVN* phase, bool can_reshape) override; }; // Float Modulus class ModFNode : public ModFloatingNode { private: - Node* dividend() const { return in(TypeFunc::Parms + 0); } - Node* divisor() const { return in(TypeFunc::Parms + 1); } + Node* dividend() const override { return in(TypeFunc::Parms + 0); } + Node* divisor() const override { return in(TypeFunc::Parms + 1); } + const Type* get_result_if_constant(const Type* dividend, const Type* divisor) const override; public: ModFNode(Compile* C, Node* a, Node* b); - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegF; } - virtual uint size_of() const { return sizeof(*this); } - virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + int Opcode() const override; + uint ideal_reg() const override { return Op_RegF; } + uint size_of() const override { return sizeof(*this); } }; // Double Modulus class ModDNode : public ModFloatingNode { private: - Node* dividend() const { return in(TypeFunc::Parms + 0); } - Node* divisor() const { return in(TypeFunc::Parms + 2); } + Node* dividend() const override { return in(TypeFunc::Parms + 0); } + Node* divisor() const override { return in(TypeFunc::Parms + 2); } + const Type* get_result_if_constant(const Type* dividend, const Type* divisor) const override; public: ModDNode(Compile* C, Node* a, Node* b); - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegD; } - virtual uint size_of() const { return sizeof(*this); } - virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + int Opcode() const override; + uint ideal_reg() const override { return Op_RegD; } + uint size_of() const override { return sizeof(*this); } }; //------------------------------UModINode--------------------------------------- diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/graphKit.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/graphKit.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/graphKit.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/graphKit.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1880,14 +1880,20 @@ // after the call, if this call has restricted memory effects. Node* GraphKit::set_predefined_input_for_runtime_call(SafePointNode* call, Node* narrow_mem) { // Set fixed predefined input arguments - Node* memory = reset_memory(); - Node* m = narrow_mem == nullptr ? memory : narrow_mem; - call->init_req( TypeFunc::Control, control() ); - call->init_req( TypeFunc::I_O, top() ); // does no i/o - call->init_req( TypeFunc::Memory, m ); // may gc ptrs - call->init_req( TypeFunc::FramePtr, frameptr() ); - call->init_req( TypeFunc::ReturnAdr, top() ); - return memory; + call->init_req(TypeFunc::Control, control()); + call->init_req(TypeFunc::I_O, top()); // does no i/o + call->init_req(TypeFunc::ReturnAdr, top()); + if (call->is_CallLeafPure()) { + call->init_req(TypeFunc::Memory, top()); + call->init_req(TypeFunc::FramePtr, top()); + return nullptr; + } else { + Node* memory = reset_memory(); + Node* m = narrow_mem == nullptr ? memory : narrow_mem; + call->init_req(TypeFunc::Memory, m); // may gc ptrs + call->init_req(TypeFunc::FramePtr, frameptr()); + return memory; + } } //-------------------set_predefined_output_for_runtime_call-------------------- @@ -1905,6 +1911,11 @@ const TypePtr* hook_mem) { // no i/o set_control(_gvn.transform( new ProjNode(call,TypeFunc::Control) )); + if (call->is_CallLeafPure()) { + // Pure function have only control (for now) and data output, in particular + // they don't touch the memory, so we don't want a memory proj that is set after. + return; + } if (keep_mem) { // First clone the existing memory state set_all_memory(keep_mem); @@ -2491,6 +2502,8 @@ } else if (flags & RC_VECTOR){ uint num_bits = call_type->range()->field_at(TypeFunc::Parms)->is_vect()->length_in_bytes() * BitsPerByte; call = new CallLeafVectorNode(call_type, call_addr, call_name, adr_type, num_bits); + } else if (flags & RC_PURE) { + call = new CallLeafPureNode(call_type, call_addr, call_name, adr_type); } else { call = new CallLeafNode(call_type, call_addr, call_name, adr_type); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/graphKit.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/graphKit.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/graphKit.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/graphKit.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -784,6 +784,7 @@ RC_NARROW_MEM = 16, // input memory is same as output RC_UNCOMMON = 32, // freq. expected to be like uncommon trap RC_VECTOR = 64, // CallLeafVectorNode + RC_PURE = 128, // CallLeaf is pure RC_LEAF = 0 // null value: no flags set }; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/ifnode.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/ifnode.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/ifnode.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/ifnode.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -876,6 +876,10 @@ return false; } + if (!dom_unc->safe_for_fold_compare()) { + return false; + } + // See merge_uncommon_traps: the reason of the uncommon trap // will be changed and the state of the dominating If will be // used. Checked that we didn't apply this transformation in a @@ -1666,6 +1670,57 @@ return true; } +void IfNode::mark_projections_unsafe_for_fold_compare() const { + // With the following code pattern + // + // if (some_condition) { + // v = 0; + // } else { + // v = 1; + // } // v is Phi(0, 1) + // if (v == 0) { + // uncommon_trap(); // reexecutes the "if (v == 0) {" above, captures v as stack argument to ifeq bytecode + // } + // if (some_other_condition) { + // uncommon_trap(); // reexecutes the "if (some_other_condition) {" + // } + // + // if the second if is split thru Phi, the result is: + // + // if (some_condition) { + // uncommon_trap(); // reexecutes the "if (v == 0) {" that was removed above, captures v = 0 as stack argument to ifeq bytecode + // } + // if (some_other_condition) { + // uncommon_trap(); // reexecutes the "if (some_other_condition) {" + // } + // + // some_condition and some_other_condition could be folded into + // a single new condition that is narrower than some_condition + // (done by IfNode::fold_compares(), for instance): + // + // if (combined_narrower_condition) { + // uncommon_trap(); // reexecutes the "if (v == 0) {" that was removed, captures v = 0 as stack argument to ifeq bytecode + // } + // + // Then combined_narrower_condition is true for some input value for + // which some_condition is false. When such an input value is used + // at runtime, the trap is taken which causes "if (v == 0) {" to be + // reexecuted with v = 0 even though some_condition is wrong, causing + // the wrong branch to be executed. + // + // Mark the uncommon trap nodes to prevent such a transformation + // from happening. + IfProjNode* true_projection = proj_out(1)->as_IfProj(); + IfProjNode* false_projection = proj_out(0)->as_IfProj(); + CallStaticJavaNode* unc = true_projection->is_uncommon_trap_proj(); + if (unc != nullptr) { + unc->clear_safe_for_fold_compare(); + } + unc = false_projection->is_uncommon_trap_proj(); + if (unc != nullptr) { + unc->clear_safe_for_fold_compare(); + } +} static int subsuming_bool_test_encode(Node*); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/library_call.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/library_call.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/library_call.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/library_call.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -564,7 +564,7 @@ case vmIntrinsics::_getCallerClass: return inline_native_Reflection_getCallerClass(); - case vmIntrinsics::_Reference_get: return inline_reference_get(); + case vmIntrinsics::_Reference_get0: return inline_reference_get0(); case vmIntrinsics::_Reference_refersTo0: return inline_reference_refersTo0(false); case vmIntrinsics::_PhantomReference_refersTo0: return inline_reference_refersTo0(true); case vmIntrinsics::_Reference_clear0: return inline_reference_clear0(false); @@ -1802,7 +1802,7 @@ Node* b = (call_type == OptoRuntime::Math_DD_D_Type()) ? argument(2) : nullptr; const TypePtr* no_memory_effects = nullptr; - Node* trig = make_runtime_call(RC_LEAF, call_type, funcAddr, funcName, + Node* trig = make_runtime_call(RC_LEAF | RC_PURE, call_type, funcAddr, funcName, no_memory_effects, a, top(), b, b ? top() : nullptr); Node* value = _gvn.transform(new ProjNode(trig, TypeFunc::Parms+0)); @@ -1817,61 +1817,17 @@ //------------------------------inline_math_pow----------------------------- bool LibraryCallKit::inline_math_pow() { + Node* base = argument(0); Node* exp = argument(2); - const TypeD* d = _gvn.type(exp)->isa_double_constant(); - if (d != nullptr) { - if (d->getd() == 2.0) { - // Special case: pow(x, 2.0) => x * x - Node* base = argument(0); - set_result(_gvn.transform(new MulDNode(base, base))); - return true; - } else if (d->getd() == 0.5 && Matcher::match_rule_supported(Op_SqrtD)) { - // Special case: pow(x, 0.5) => sqrt(x) - Node* base = argument(0); - Node* zero = _gvn.zerocon(T_DOUBLE); - - RegionNode* region = new RegionNode(3); - Node* phi = new PhiNode(region, Type::DOUBLE); - - Node* cmp = _gvn.transform(new CmpDNode(base, zero)); - // According to the API specs, pow(-0.0, 0.5) = 0.0 and sqrt(-0.0) = -0.0. - // So pow(-0.0, 0.5) shouldn't be replaced with sqrt(-0.0). - // -0.0/+0.0 are both excluded since floating-point comparison doesn't distinguish -0.0 from +0.0. - Node* test = _gvn.transform(new BoolNode(cmp, BoolTest::le)); - - Node* if_pow = generate_slow_guard(test, nullptr); - Node* value_sqrt = _gvn.transform(new SqrtDNode(C, control(), base)); - phi->init_req(1, value_sqrt); - region->init_req(1, control()); - - if (if_pow != nullptr) { - set_control(if_pow); - address target = StubRoutines::dpow() != nullptr ? StubRoutines::dpow() : - CAST_FROM_FN_PTR(address, SharedRuntime::dpow); - const TypePtr* no_memory_effects = nullptr; - Node* trig = make_runtime_call(RC_LEAF, OptoRuntime::Math_DD_D_Type(), target, "POW", - no_memory_effects, base, top(), exp, top()); - Node* value_pow = _gvn.transform(new ProjNode(trig, TypeFunc::Parms+0)); -#ifdef ASSERT - Node* value_top = _gvn.transform(new ProjNode(trig, TypeFunc::Parms+1)); - assert(value_top == top(), "second value must be top"); -#endif - phi->init_req(2, value_pow); - region->init_req(2, _gvn.transform(new ProjNode(trig, TypeFunc::Control))); - } - - C->set_has_split_ifs(true); // Has chance for split-if optimization - set_control(_gvn.transform(region)); - record_for_igvn(region); - set_result(_gvn.transform(phi)); - return true; - } - } - - return StubRoutines::dpow() != nullptr ? - runtime_math(OptoRuntime::Math_DD_D_Type(), StubRoutines::dpow(), "dpow") : - runtime_math(OptoRuntime::Math_DD_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::dpow), "POW"); + CallNode* pow = new PowDNode(C, base, exp); + set_predefined_input_for_runtime_call(pow); + pow = _gvn.transform(pow)->as_CallLeafPure(); + set_predefined_output_for_runtime_call(pow); + Node* result = _gvn.transform(new ProjNode(pow, TypeFunc::Parms + 0)); + record_for_igvn(pow); + set_result(result); + return true; } //------------------------------inline_math_native----------------------------- @@ -6919,9 +6875,9 @@ return true; } -//----------------------------inline_reference_get---------------------------- +//----------------------------inline_reference_get0---------------------------- // public T java.lang.ref.Reference.get(); -bool LibraryCallKit::inline_reference_get() { +bool LibraryCallKit::inline_reference_get0() { const int referent_offset = java_lang_ref_Reference::referent_offset(); // Get the argument: @@ -6930,7 +6886,8 @@ DecoratorSet decorators = IN_HEAP | ON_WEAK_OOP_REF; Node* result = load_field_from_object(reference_obj, "referent", "Ljava/lang/Object;", - decorators, /*is_static*/ false, nullptr); + decorators, /*is_static*/ false, + env()->Reference_klass()); if (result == nullptr) return false; // Add memory barrier to prevent commoning reads from this field @@ -6953,7 +6910,8 @@ DecoratorSet decorators = IN_HEAP | AS_NO_KEEPALIVE; decorators |= (is_phantom ? ON_PHANTOM_OOP_REF : ON_WEAK_OOP_REF); Node* referent = load_field_from_object(reference_obj, "referent", "Ljava/lang/Object;", - decorators, /*is_static*/ false, nullptr); + decorators, /*is_static*/ false, + env()->Reference_klass()); if (referent == nullptr) return false; // Add memory barrier to prevent commoning reads from this field @@ -7032,8 +6990,6 @@ assert(tinst != nullptr, "obj is null"); assert(tinst->is_loaded(), "obj is not loaded"); fromKls = tinst->instance_klass(); - } else { - assert(is_static, "only for static field access"); } ciField* field = fromKls->get_field_by_name(ciSymbol::make(fieldName), ciSymbol::make(fieldTypeString), diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/library_call.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/library_call.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/library_call.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/library_call.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -300,7 +300,7 @@ bool inline_bitshuffle_methods(vmIntrinsics::ID id); bool inline_compare_unsigned(vmIntrinsics::ID id); bool inline_divmod_methods(vmIntrinsics::ID id); - bool inline_reference_get(); + bool inline_reference_get0(); bool inline_reference_refersTo0(bool is_phantom); bool inline_reference_clear0(bool is_phantom); bool inline_Class_cast(); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/loopPredicate.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/loopPredicate.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/loopPredicate.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/loopPredicate.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -456,10 +456,10 @@ } }; -//------------------------------is_range_check_if ----------------------------------- -// Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format -// Note: this function is particularly designed for loop predication. We require load_range -// and offset to be loop invariant computed on the fly by "invar" +// Returns true if the predicate has the form +// scale*iv + offset = 0. +// Note: This is used by Loop Predication and PhaseIdealLoop::extract_long_range_check(). bool IdealLoopTree::is_range_check_if(IfProjNode* if_success_proj, PhaseIdealLoop *phase, BasicType bt, Node *iv, Node *&range, Node *&offset, jlong &scale) const { IfNode* iff = if_success_proj->in(0)->as_If(); @@ -517,20 +517,23 @@ return false; } range = cmp->in(2); + + // Now we check the condition R >= 0 from the method comment. if (range->Opcode() != Op_LoadRange) { const TypeInteger* tinteger = phase->_igvn.type(range)->isa_integer(bt); if (tinteger == nullptr || tinteger->empty() || tinteger->lo_as_long() < 0) { - // Allow predication on positive values that aren't LoadRanges. - // This allows optimization of loops where the length of the - // array is a known value and doesn't need to be loaded back - // from the array. + // R is not proven to be non-negative. Bail out. return false; } } else { + // R = LoadRange are always non-negative. assert(bt == T_INT, "no LoadRange for longs"); } scale = 0; offset = nullptr; + // Now check the form + // scale*iv + offset is_scaled_iv_plus_offset(cmp->in(1), iv, bt, &scale, &offset)) { return false; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/loopTransform.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/loopTransform.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/loopTransform.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/loopTransform.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1048,8 +1048,6 @@ } break; case Op_CountTrailingZerosV: case Op_CountLeadingZerosV: - case Op_LoadVectorGather: - case Op_LoadVectorGatherMasked: case Op_ReverseV: case Op_RoundVF: case Op_RoundVD: @@ -2245,8 +2243,15 @@ //----------------------------------is_iv------------------------------------ // Return true if exp is the value (of type bt) of the given induction var. -// This grammar of cases is recognized, where X is I|L according to bt: -// VIV[iv] = iv | (CastXX VIV[iv]) | (ConvI2X VIV[iv]) +// On success, we guarantee this form: +// if bt = T_INT (implies iv is int): +// exp = iv +// if bt = T_LONG and iv is long: +// exp = iv +// if bt = T_LONG and iv is int: +// exp = ConvI2L(iv) +// +// See grammar specification in PhaseIdealLoop::is_scaled_iv_plus_offset(). bool PhaseIdealLoop::is_iv(Node* exp, Node* iv, BasicType bt) { exp = exp->uncast(); if (exp == iv && iv->bottom_type()->isa_integer(bt)) { @@ -2261,88 +2266,129 @@ //------------------------------is_scaled_iv--------------------------------- // Return true if exp is a constant times the given induction var (of type bt). -// The multiplication is either done in full precision (exactly of type bt), -// or else bt is T_LONG but iv is scaled using 32-bit arithmetic followed by a ConvI2L. -// This grammar of cases is recognized, where X is I|L according to bt: -// SIV[iv] = VIV[iv] | (CastXX SIV[iv]) -// | (MulX VIV[iv] ConX) | (MulX ConX VIV[iv]) -// | (LShiftX VIV[iv] ConI) -// | (ConvI2L SIV[iv]) -- a "short-scale" can occur here; note recursion -// | (SubX 0 SIV[iv]) -- same as MulX(iv, -scale); note recursion -// | (AddX SIV[iv] SIV[iv]) -- sum of two scaled iv; note recursion -// | (SubX SIV[iv] SIV[iv]) -- difference of two scaled iv; note recursion -// VIV[iv] = [either iv or its value converted; see is_iv() above] -// On success, the constant scale value is stored back to *p_scale. -// The value (*p_short_scale) reports if such a ConvI2L conversion was present. -bool PhaseIdealLoop::is_scaled_iv(Node* exp, Node* iv, BasicType bt, jlong* p_scale, bool* p_short_scale, int depth) { - BasicType exp_bt = bt; - exp = exp->uncast(); //strip casts - assert(exp_bt == T_INT || exp_bt == T_LONG, "unexpected int type"); - if (is_iv(exp, iv, exp_bt)) { +// On success, we guarantee this form: +// if bt = T_INT (implies iv is int): +// exp = MulI( iv, p_scale) where p_scale is int +// if bt = T_LONG and iv is long: +// exp = MulL( iv, p_scale) +// if bt = T_LONG and iv is int: +// exp = MulL(ConvI2L(iv), p_scale) +// where the constant scale value is stored back to *p_scale unless null. +// The scaling is always done in full precision (exactly of type bt). +// See grammar specification in PhaseIdealLoop::is_scaled_iv_plus_offset(). +bool PhaseIdealLoop::is_scaled_iv(Node* exp, Node* iv, BasicType bt, jlong* p_scale, int depth) { + exp = exp->uncast(); // Strip casts. + assert(bt == T_INT || bt == T_LONG, "unexpected int type"); + if (is_iv(exp, iv, bt)) { + // if bt = T_INT (implies iv is int): + // exp = iv = MulI( iv, p_scale=1) where p_scale=1 is trivially an int + // if bt = T_LONG and iv is long: + // exp = iv = MulL( iv, p_scale=1) + // if bt = T_LONG and iv is int: + // exp = ConvI2L(iv) = MulL(ConvI2L(iv), p_scale=1) if (p_scale != nullptr) { *p_scale = 1; } - if (p_short_scale != nullptr) { - *p_short_scale = false; - } return true; } - if (exp_bt == T_LONG && iv->bottom_type()->isa_int() && exp->Opcode() == Op_ConvI2L) { - exp = exp->in(1); - exp_bt = T_INT; + if (bt == T_LONG && iv->bottom_type()->isa_int() && exp->Opcode() == Op_ConvI2L) { + // Risk for short scaling: avoid long range-check transformations, because + // the current implementation (transform_long_range_checks) does not protect + // against overflow. + return false; } int opc = exp->Opcode(); int which = 0; // this is which subexpression we find the iv in // Can't use is_Mul() here as it's true for AndI and AndL - if (opc == Op_Mul(exp_bt)) { - if ((is_iv(exp->in(which = 1), iv, exp_bt) && exp->in(2)->is_Con()) || - (is_iv(exp->in(which = 2), iv, exp_bt) && exp->in(1)->is_Con())) { + if (opc == Op_Mul(bt)) { + // We need to test both ways because the multiplication node may not have + // been canonicalized yet, for example after successful loop predication. + if ((is_iv(exp->in(which = 1), iv, bt) && exp->in(2)->is_Con()) || + (is_iv(exp->in(which = 2), iv, bt) && exp->in(1)->is_Con())) { Node* factor = exp->in(which == 1 ? 2 : 1); // the other argument - jlong scale = factor->find_integer_as_long(exp_bt, 0); + jlong scale = factor->find_integer_as_long(bt, 0); if (scale == 0) { - return false; // might be top + return false; // find_integer_as_long may have failed, value might be top. } + // if bt = T_INT (implies iv is int): + // exp->in(which) = iv + // Note: find_integer_as_long ensures that scale is int + // -> which = 1: exp = MulI( iv, scale) where scale is int + // -> which = 2: exp = MulI(scale, iv) = MulI( iv, scale) where scale is int + // if bt = T_LONG and iv is long: + // exp->in(which) = iv + // -> which = 1: exp = MulL( iv, scale) + // -> which = 2: exp = MulL(scale, iv) = MulL( iv, scale) + // if bt = T_LONG and iv is int: + // exp->in(which) = ConvI2L(iv) + // -> which = 1: exp = MulL(ConvI2L(iv), scale) + // -> which = 2: exp = MulL(scale, ConvI2L(iv)) = MulL(ConvI2L(iv), scale) if (p_scale != nullptr) { *p_scale = scale; } - if (p_short_scale != nullptr) { - // (ConvI2L (MulI iv K)) can be 64-bit linear if iv is kept small enough... - *p_short_scale = (exp_bt != bt && scale != 1); - } return true; } - } else if (opc == Op_LShift(exp_bt)) { - if (is_iv(exp->in(1), iv, exp_bt) && exp->in(2)->is_Con()) { + } else if (opc == Op_LShift(bt)) { + if (is_iv(exp->in(1), iv, bt) && exp->in(2)->is_Con()) { jint shift_amount = exp->in(2)->find_int_con(min_jint); if (shift_amount == min_jint) { - return false; // might be top + return false; // find_int_con may have failed, value might be top. } jlong scale; - if (exp_bt == T_INT) { + if (bt == T_INT) { + // LShiftI(x, shift_amount) = MulI(x, LShiftI(1, shift_amount)) = MulI(x, scale) + // Note: scale is guaranteed to be an int scale = java_shift_left((jint)1, (juint)shift_amount); - } else if (exp_bt == T_LONG) { + } else if (bt == T_LONG) { + // LShiftL(x, shift_amount) = MulL(x, LShiftL(1L, shift_amount)) = MulL(x, scale) scale = java_shift_left((jlong)1, (julong)shift_amount); } + // if bt = T_INT (implies iv is int): + // exp->in(1) = iv + // exp = LShiftI( iv, shift_amount) = MulI( iv, scale) where scale is int + // if bt = T_LONG and iv is long: + // exp->in(1) = iv + // exp = LShiftL( iv, shift_amount) = MulL( iv, scale) + // if bt = T_LONG and iv is int: + // exp->in(1) = ConvI2L(iv) + // exp = LShiftL(ConvI2L(iv), shift_amount) = MulL(ConvI2L(iv), scale) if (p_scale != nullptr) { *p_scale = scale; } - if (p_short_scale != nullptr) { - // (ConvI2L (MulI iv K)) can be 64-bit linear if iv is kept small enough... - *p_short_scale = (exp_bt != bt && scale != 1); - } return true; } - } else if (opc == Op_Add(exp_bt)) { + } else if (opc == Op_Add(bt)) { jlong scale_l = 0; jlong scale_r = 0; - bool short_scale_l = false; - bool short_scale_r = false; if (depth == 0 && - is_scaled_iv(exp->in(1), iv, exp_bt, &scale_l, &short_scale_l, depth + 1) && - is_scaled_iv(exp->in(2), iv, exp_bt, &scale_r, &short_scale_r, depth + 1)) { - // AddX(iv*K1, iv*K2) => iv*(K1+K2) + is_scaled_iv(exp->in(1), iv, bt, &scale_l, depth + 1) && + is_scaled_iv(exp->in(2), iv, bt, &scale_r, depth + 1)) { + // We know that: + // AddI(MulI(x, scale_l), MulI(x, scale_r)) = MulI(x, scale=AddI(scale_l, scale_r)) where scale is int + // AddL(MulL(x, scale_l), MulL(x, scale_r)) = MulL(x, scale=AddL(scale_l, scale_r)) + // + // if bt = T_INT (implies iv is int): + // e1 = exp->in(1) = MulI(iv, scale_l) where scale_l is int + // e2 = exp->in(2) = MulI(iv, scale_r) where scale_r is int + // exp = AddI(e1, e2) = MulI(iv, scale=AddI(scale_l, scale_r)) where scale is int + // if bt = T_LONG and iv is long: + // e1 = exp->in(1) = MulL(iv, scale_l) + // e2 = exp->in(2) = MulL(iv, scale_r) + // exp = AddL(e1, e2) = MulL(iv, scale=AddL(scale_l, scale_r)) + // if bt = T_LONG and iv is int: + // e1 = exp->in(1) = MulL(ConvI2L(iv), scale_l) + // e2 = exp->in(2) = MulL(ConvI2L(iv), scale_r) + // exp = AddL(e1, e2) = MulL(ConvI2L(iv), scale=AddL(scale_l, scale_r)) + // + // For the scale computation, we could have used the same type case + // distinction as in LShift above. But instead, we compute in long for + // all cases. We need to show that this is OK if bt=T_INT. + // We would have computed + // scale = AddI(scale_l, scale_r) + // which is equivalent to the long addition if the long addition stays + // within (min_jint, max_jint]. jlong scale_sum = java_add(scale_l, scale_r); - if (scale_sum > max_signed_integer(exp_bt) || scale_sum <= min_signed_integer(exp_bt)) { + if (scale_sum > max_signed_integer(bt) || scale_sum <= min_signed_integer(bt)) { // This logic is shared by int and long. For int, the result may overflow // as we use jlong to compute so do the check here. Long result may also // overflow but that's fine because result wraps. @@ -2351,41 +2397,76 @@ if (p_scale != nullptr) { *p_scale = scale_sum; } - if (p_short_scale != nullptr) { - *p_short_scale = short_scale_l && short_scale_r; - } return true; } - } else if (opc == Op_Sub(exp_bt)) { - if (exp->in(1)->find_integer_as_long(exp_bt, -1) == 0) { - jlong scale = 0; - if (depth == 0 && is_scaled_iv(exp->in(2), iv, exp_bt, &scale, p_short_scale, depth + 1)) { - // SubX(0, iv*K) => iv*(-K) - if (scale == min_signed_integer(exp_bt)) { + } else if (opc == Op_Sub(bt)) { + if (exp->in(1)->find_integer_as_long(bt, -1) == 0) { + jlong scale_r = 0; + if (depth == 0 && is_scaled_iv(exp->in(2), iv, bt, &scale_r, depth + 1)) { + // We know that: + // SubI(0, MulI(x, scale_r)) = MulI(x, scale=SubI(0, scale_r)) where scale is int + // SubL(0, MulL(x, scale_r)) = MulL(x, scale=SubL(0, scale_r)) + // + // if bt = T_INT (implies iv is int): + // e2 = exp->in(2) = MulI(iv, scale_r) where scale_r is int + // exp = SubI(0, e2) = MulI(iv, scale=SubI(0, scale_r)) where scale is int + // if bt = T_LONG and iv is long: + // e2 = exp->in(2) = MulL(iv, scale_r) + // exp = SubL(0, e2) = MulL(iv, scale=SubL(0, scale_r)) + // if bt = T_LONG and iv is int: + // e2 = exp->in(2) = MulL(ConvI2L(iv), scale_r) + // exp = SubL(0, e2) = MulL(ConvI2L(iv), scale=SubL(0, scale_r)) + // + // Again, we could have used bt-sensitive computations as for LShift. + // Instead, we compute in all cases + // scale = SubL(0, scale_r) + // How is this correct for bt=T_INT? + // We know that the input scale is in the int range. + // And so as long as the input scale != min_jint, the + // computation in long is equivalent, since neither the int nor + // the long computation would overflow. + if (scale_r == min_signed_integer(bt)) { // This should work even if -K overflows, but let's not. return false; } - scale = java_multiply(scale, (jlong)-1); + jlong scale_neg = java_multiply(scale_r, (jlong)-1); if (p_scale != nullptr) { - *p_scale = scale; - } - if (p_short_scale != nullptr) { - // (ConvI2L (MulI iv K)) can be 64-bit linear if iv is kept small enough... - *p_short_scale = *p_short_scale || (exp_bt != bt && scale != 1); + *p_scale = scale_neg; } return true; } } else { jlong scale_l = 0; jlong scale_r = 0; - bool short_scale_l = false; - bool short_scale_r = false; if (depth == 0 && - is_scaled_iv(exp->in(1), iv, exp_bt, &scale_l, &short_scale_l, depth + 1) && - is_scaled_iv(exp->in(2), iv, exp_bt, &scale_r, &short_scale_r, depth + 1)) { - // SubX(iv*K1, iv*K2) => iv*(K1-K2) + is_scaled_iv(exp->in(1), iv, bt, &scale_l, depth + 1) && + is_scaled_iv(exp->in(2), iv, bt, &scale_r, depth + 1)) { + // We know that: + // SubI(MulI(x, scale_l), MulI(x, scale_r)) = MulI(x, scale=SubI(scale_l, scale_r)) where scale is int + // SubL(MulL(x, scale_l), MulL(x, scale_r)) = MulL(x, scale=SubL(scale_l, scale_r)) + // + // if bt = T_INT (implies iv is int): + // e1 = exp->in(1) = MulI(iv, scale_l) where scale_l is int + // e2 = exp->in(2) = MulI(iv, scale_r) where scale_r is int + // exp = SubI(e1, e2) = MulI(iv, scale=SubI(scale_l, scale_r)) where scale is int + // if bt = T_LONG and iv is long: + // e1 = exp->in(1) = MulL(iv, scale_l) + // e2 = exp->in(2) = MulL(iv, scale_r) + // exp = SubL(e1, e2) = MulL(iv, scale=SubL(scale_l, scale_r)) + // if bt = T_LONG and iv is int: + // e1 = exp->in(1) = MulL(ConvI2L(iv), scale_l) + // e2 = exp->in(2) = MulL(ConvI2L(iv), scale_r) + // exp = SubL(e1, e2) = MulL(ConvI2L(iv), scale=SubL(scale_l, scale_r)) + // + // For the scale computation, we could have used the same type case + // distinction as in LShift above. But instead, we compute in long for + // all cases. We need to show that this is OK if bt=T_INT. + // We would have computed + // scale = SubI(scale_l, scale_r) + // which is equivalent to the long subtraction if the long subtraction + // stays within (min_jint, max_jint]. jlong scale_diff = java_subtract(scale_l, scale_r); - if (scale_diff > max_signed_integer(exp_bt) || scale_diff <= min_signed_integer(exp_bt)) { + if (scale_diff > max_signed_integer(bt) || scale_diff <= min_signed_integer(bt)) { // This logic is shared by int and long. For int, the result may // overflow as we use jlong to compute so do the check here. Long // result may also overflow but that's fine because result wraps. @@ -2394,9 +2475,6 @@ if (p_scale != nullptr) { *p_scale = scale_diff; } - if (p_short_scale != nullptr) { - *p_short_scale = short_scale_l && short_scale_r; - } return true; } } @@ -2406,27 +2484,75 @@ } //-------------------------is_scaled_iv_plus_offset-------------------------- -// Return true if exp is a simple linear transform of the given induction var. +// Return true if exp is a simple affine transform of the given induction var. // The scale must be constant and the addition tree (if any) must be simple. -// This grammar of cases is recognized, where X is I|L according to bt: +// On success, we guarantee this form: +// if bt = T_INT (implies iv is int): +// exp = AddI(MulI( iv, p_scale), p_offset) where p_scale is int +// if bt = T_LONG and iv is long: +// exp = AddL(MulL( iv, p_scale), p_offset) +// if bt = T_LONG and iv is int: +// exp = AddL(MulL(ConvI2L(iv), p_scale), p_offset) +// where: +// - the constant scale value is stored back to *p_scale unless null, and +// - the offset (perhaps a synthetic AddX or SubX node) is stored to *p_offset unless null. +// To avoid looping, the match is depth-limited. +// +// This grammar of cases is recognized, where X is I (int) or L (long) according +// to bt. CastXX operations are also accepted, but omitted for conciseness: +// +// is_iv(): +// +// IV[iv,I] = iv, if iv is int +// IV[iv,L] = iv, if iv is long +// | ConvI2L(iv), if iv is int +// +// is_scaled_iv(): // -// OIV[iv] = SIV[iv] | (CastXX OIV[iv]) -// | (AddX SIV[iv] E) | (AddX E SIV[iv]) -// | (SubX SIV[iv] E) | (SubX E SIV[iv]) -// SSIV[iv] = (ConvI2X SIV[iv]) -- a "short scale" might occur here -// SIV[iv] = [a possibly scaled value of iv; see is_scaled_iv() above] +// SIV0[iv,X] = IV[iv,X] +// | MulX(IV[iv,X], ConX), if get_con(ConX) != 0 (ConX is top or MulX is non canonical) +// | MulX(ConX, IV[iv,X]), if get_con(ConX) != 0 (ConX is top or MulX is non canonical) +// | LShiftX(IV[iv,X], ConI), if get_con(ConI) != min_jint (ConI is top or LShiftX is non canonical) // -// On success, the constant scale value is stored back to *p_scale unless null. -// Likewise, the addend (perhaps a synthetic AddX node) is stored to *p_offset. -// Also, (*p_short_scale) reports if a ConvI2L conversion was seen after a MulI, -// meaning bt is T_LONG but iv was scaled using 32-bit arithmetic. -// To avoid looping, the match is depth-limited, and so may fail to match the grammar to complex expressions. -bool PhaseIdealLoop::is_scaled_iv_plus_offset(Node* exp, Node* iv, BasicType bt, jlong* p_scale, Node** p_offset, bool* p_short_scale, int depth) { +// SIV[iv,X] = SIV0[iv,X] +// | e:AddX(SIV0[iv,X], SIV0[iv,X]), if min_jX < scale(e) <= max_jX +// | SubX(0, e:SIV0[iv,X]), if scale(e) != min_jX +// | e:SubX(SIV0[iv,X], SIV0[iv,X]), if min_jX < scale(e) <= max_jX +// +// is_scaled_iv_plus_offset(): +// +// OSIV0[iv,X] = SIV[iv,X] +// | AddX(SIV[iv,X], e) +// | AddX(e, SIV[iv,X]) +// | SubX(SIV[iv,X], e) +// | SubX(e1, e2:SIV[iv,X]), if scale(e2) != min_jX +// +// OSIV1[iv,X] = OSIV0[iv,X] +// | AddX(OSIV0[iv,X], ConX) +// | AddX(ConX, OSIV0[iv,X]) +// +// OSIV[iv,X] = OSIV1[iv,X] +// | AddX(OSIV1[iv,X], ConX) +// | AddX(ConX, OSIV1[iv,X]) +// +// where scale(IV[iv,X]) = 1L +// scale(MulX(_, ConX)) = get_con(ConX) +// scale(MulX(ConX, _)) = get_con(ConX) +// scale(LShiftX(_, ConI)) = java_shift_left((jX)1, get_con(ConI)) +// scale(AddX(e1:SIV0, e2:SIV0)) = java_add(scale(e1), scale(e2)) +// scale(SubX(0, e:SIV0)) = java_multiply(scale(e), -1L) +// scale(SubX(e1:SIV0, e2:SIV0)) = java_subtract(scale(e1), scale(e2)) +bool PhaseIdealLoop::is_scaled_iv_plus_offset(Node* exp, Node* iv, BasicType bt, jlong* p_scale, Node** p_offset, int depth) { assert(bt == T_INT || bt == T_LONG, "unexpected int type"); jlong scale = 0; // to catch result from is_scaled_iv() - BasicType exp_bt = bt; exp = exp->uncast(); - if (is_scaled_iv(exp, iv, exp_bt, &scale, p_short_scale)) { + if (is_scaled_iv(exp, iv, bt, &scale)) { + // if bt = T_INT (implies iv is int): + // exp = MulI( iv, scale) = AddI(MulI( iv, scale), offset=0) where scale is int + // if bt = T_LONG and iv is long: + // exp = MulL( iv, scale) = AddL(MulL( iv, scale), offset=0) + // if bt = T_LONG and iv is int: + // exp = MulL(ConvI2L(iv), scale) = AddL(MulL(ConvI2L(iv), scale), offset=0) if (p_scale != nullptr) { *p_scale = scale; } @@ -2436,58 +2562,109 @@ } return true; } - if (exp_bt != bt) { - // We would now be matching inputs like (ConvI2L exp:(AddI (MulI iv S) E)). - // It's hard to make 32-bit arithmetic linear if it overflows. Although we do - // cope with overflowing multiplication by S, it would be even more work to - // handle overflowing addition of E. So we bail out here on ConvI2L input. - return false; - } int opc = exp->Opcode(); - int which = 0; // this is which subexpression we find the iv in - Node* offset = nullptr; - if (opc == Op_Add(exp_bt)) { - // Check for a scaled IV in (AddX (MulX iv S) E) or (AddX E (MulX iv S)). - if (is_scaled_iv(exp->in(which = 1), iv, bt, &scale, p_short_scale) || - is_scaled_iv(exp->in(which = 2), iv, bt, &scale, p_short_scale)) { - offset = exp->in(which == 1 ? 2 : 1); // the other argument + int which = 0; // Input index of the subexpression we find the IV in. + Node* offset_other = nullptr; // Offset subexpression (the other input). + if (opc == Op_Add(bt)) { + jlong scale_which = 0; // Scale of the IV subexpression. + // Check for a scaled IV in AddX(MulX(iv, S), E) or AddX(E, MulX(iv, S)). + if (is_scaled_iv(exp->in(which = 1), iv, bt, &scale_which) || + is_scaled_iv(exp->in(which = 2), iv, bt, &scale_which)) { + offset_other = exp->in(which == 1 ? 2 : 1); // The other argument. + // if bt = T_INT (implies iv is int): + // exp->in(which) = MulI( iv, scale_which) where scale_which is int + // -> which = 1: exp = AddI(MulI( iv, scale_which), offset_other) where scale_which is int + // -> which = 2: exp = AddI(offset_other, MulI( iv, scale_which)) = AddI(MulI( iv, scale_which), offset_other) where scale_which is int + // if bt = T_LONG and iv is long: + // exp->in(which) = MulL( iv, scale_which) + // -> which = 1: exp = AddL(MulL( iv, scale_which), offset_other) + // -> which = 2: exp = AddL(offset_other, MulL( iv, scale_which)) = AddL(MulL( iv, scale_which), offset_other) + // if bt = T_LONG and iv is int: + // exp->in(which) = MulL(ConvI2L(iv), scale_which) + // -> which = 1: exp = AddL(MulL(ConvI2L(iv), scale_which), offset_other) + // -> which = 2: exp = AddL(offset_other, MulL(ConvI2L(iv), scale_which)) = AddL(MulL(ConvI2L(iv), scale_which), offset_other) if (p_scale != nullptr) { - *p_scale = scale; + *p_scale = scale_which; } if (p_offset != nullptr) { - *p_offset = offset; + *p_offset = offset_other; } return true; } - // Check for more addends, like (AddX (AddX (MulX iv S) E1) E2), etc. - if (is_scaled_iv_plus_extra_offset(exp->in(1), exp->in(2), iv, bt, p_scale, p_offset, p_short_scale, depth) || - is_scaled_iv_plus_extra_offset(exp->in(2), exp->in(1), iv, bt, p_scale, p_offset, p_short_scale, depth)) { + // Check for more addends, like AddX(AddX(MulX(iv, S), E1), E2), etc. + if (is_scaled_iv_plus_extra_offset(exp->in(1), exp->in(2), iv, bt, p_scale, p_offset, depth) || + is_scaled_iv_plus_extra_offset(exp->in(2), exp->in(1), iv, bt, p_scale, p_offset, depth)) { + // See proof in is_scaled_iv_plus_extra_offset. return true; } - } else if (opc == Op_Sub(exp_bt)) { - if (is_scaled_iv(exp->in(which = 1), iv, bt, &scale, p_short_scale) || - is_scaled_iv(exp->in(which = 2), iv, bt, &scale, p_short_scale)) { - // Match (SubX SIV[iv] E) as if (AddX SIV[iv] (SubX 0 E)), and - // match (SubX E SIV[iv]) as if (AddX E (SubX 0 SIV[iv])). - offset = exp->in(which == 1 ? 2 : 1); // the other argument + } else if (opc == Op_Sub(bt)) { + jlong scale_which = 0; // Scale of the IV subexpression. + if (is_scaled_iv(exp->in(which = 1), iv, bt, &scale_which) || + is_scaled_iv(exp->in(which = 2), iv, bt, &scale_which)) { + offset_other = exp->in(which == 1 ? 2 : 1); // The other argument. + // if bt = T_INT (implies iv is int): + // exp->in(which) = MulI(iv, scale_which) where scale_which is int + // if which=1: + // exp = SubI(MulI( iv, scale_which), offset_other ) + // = AddI(MulI( iv, scale_which), offset=SubI(0, offset_other)) + // if which=2: + // exp = SubI(offset_other, MulI( iv, scale_which )) + // = AddI(offset_other, MulI( iv, scale=SubI(0, scale_which))) + // = AddI(MulI( iv, scale=SubI(0, scale_which)), offset_other) + // + // if bt = T_LONG and iv is long: + // exp->in(which) = MulL(iv, scale_which) + // if which=1: + // exp = SubL(MulL( iv, scale_which), offset_other ) + // = AddL(MulL( iv, scale_which), offset=SubL(0, offset_other)) + // if which=2: + // exp = SubL(offset_other, MulL( iv, scale_which )) + // = AddL(offset_other, MulL( iv, scale=SubL(0, scale_which))) + // = AddL(MulL( iv, scale=SubL(0, scale_which)), offset_other) + // + // if bt = T_LONG and iv is int: + // exp->in(which) = MulL(ConvI2L(iv), scale_which) + // if which=1: + // exp = SubL(MulL(ConvI2L(iv), scale_which), offset_other ) + // = AddL(MulL(ConvI2L(iv), scale_which), offset=SubL(0, offset_other)) + // if which=2: + // exp = SubL(offset_other, MulL(ConvI2L(iv), scale_which )) + // = AddL(offset_other, MulL(ConvI2L(iv), scale=SubL(0, scale_which))) + // = AddL(MulL(ConvI2L(iv), scale=SubL(0, scale_which)), offset_other) + // + // Match SubX(SIV[iv], E) as if AddX(SIV[iv], SubX(0, E)), and + // match SubX(E, SIV[iv]) as if AddX(E, SubX(0, SIV[iv])). + // + // Let's compute the scale: + // which=1: scale= scale_which + // which=2: scale=SubX(0, scale_which) + // We could have used the bt case distinction for SubX(0, scale_which), + // but instead we compute it in long for both cases. For int, this + // can only lead to a wrong result (i.e. go out of int range) for + // min_jint, so we exclude that case. + jlong scale_maybe_neg = scale_which; if (which == 2) { // We can't handle a scale of min_jint (or min_jlong) here as -1 * min_jint = min_jint - if (scale == min_signed_integer(bt)) { + if (scale_which == min_signed_integer(bt)) { return false; // cannot negate the scale of the iv } - scale = java_multiply(scale, (jlong)-1); + // scale = SubL(0, scale_which) = MulL(scale_which, -1) + scale_maybe_neg = java_multiply(scale_which, (jlong)-1); } if (p_scale != nullptr) { - *p_scale = scale; + *p_scale = scale_maybe_neg; } + // Now let's compute the offset: + // which=1: offset=SubX(0, offset_other) + // which=2: offset= offset_other if (p_offset != nullptr) { + Node* offset_maybe_neg = offset_other; if (which == 1) { // must negate the extracted offset - Node* zero = integercon(0, exp_bt); - Node *ctrl_off = get_ctrl(offset); - offset = SubNode::make(zero, offset, exp_bt); - register_new_node(offset, ctrl_off); + Node* zero = integercon(0, bt); + offset_maybe_neg = SubNode::make(zero, offset_other, bt); + register_new_node(offset_maybe_neg, get_ctrl(offset_other)); } - *p_offset = offset; + *p_offset = offset_maybe_neg; } return true; } @@ -2496,26 +2673,54 @@ } // Helper for is_scaled_iv_plus_offset(), not called separately. -// The caller encountered (AddX exp1 offset3) or (AddX offset3 exp1). -// Here, exp1 is inspected to see if it is a simple linear transform of iv. -// If so, the offset3 is combined with any other offset2 from inside exp1. +// The caller encountered AddX(exp1, offset3) or AddX(offset3, exp1). +// Here, exp1 is inspected to see if it is a simple affine transform of iv. +// If so, the (constant) offset3 is combined with any other offset2 from inside exp1. +// +// We assume the input form is equivalent to: +// if bt = T_INT: +// exp = AddI(exp1, offset3) +// if bt = T_LONG: +// exp = AddL(exp1, offset3) +// +// On success, we guarantee this form: +// if bt = T_INT (implies iv is int): +// exp = AddI(MulI( iv, p_scale), p_offset) where p_scale is int +// if bt = T_LONG and iv is long: +// exp = AddL(MulL( iv, p_scale), p_offset) +// if bt = T_LONG and iv is int: +// exp = AddL(MulL(ConvI2L(iv), p_scale), p_offset) +// bool PhaseIdealLoop::is_scaled_iv_plus_extra_offset(Node* exp1, Node* offset3, Node* iv, BasicType bt, jlong* p_scale, Node** p_offset, - bool* p_short_scale, int depth) { + int depth) { // By the time we reach here, it is unlikely that exp1 is a simple iv*K. - // If is a linear iv transform, it is probably an add or subtract. + // If it is an affine iv transform, it is probably an add or subtract. // Let's collect the internal offset2 from it. Node* offset2 = nullptr; if (offset3->is_Con() && depth < 2 && is_scaled_iv_plus_offset(exp1, iv, bt, p_scale, - &offset2, p_short_scale, depth+1)) { + &offset2, depth+1)) { + // We know that: + // AddI(AddI(x, offset2), offset3) = AddI(x, offset=AddI(offset2, offset3)) + // AddL(AddL(x, offset2), offset3) = AddL(x, offset=AddL(offset2, offset3)) + // + // if bt = T_INT (implies iv is int): + // exp1 = AddI(MulI( iv, p_scale), offset2) where p_scale is int + // -> exp = AddI(AddI(MulI( iv, p_scale), offset2), offset3) = AddI(MulI( iv, p_scale), offset=AddI(offset2, offset3)) + // if bt = T_LONG and iv is long: + // exp1 = AddL(MulL( iv, p_scale), offset2) + // -> exp = AddL(AddL(MulL( iv, p_scale), offset2), offset3) = AddL(MulL( iv, p_scale), offset=AddL(offset2, offset3)) + // if bt = T_LONG and iv is int: + // exp1 = AddL(MulL(ConvI2L(iv), p_scale), offset2) + // -> exp = AddL(AddL(MulL(ConvI2L(iv), p_scale), offset2), offset3) = AddL(MulL(ConvI2L(iv), p_scale), offset=AddL(offset2, offset3)) + // if (p_offset != nullptr) { - Node* ctrl_off2 = get_ctrl(offset2); - Node* offset = AddNode::make(offset2, offset3, bt); - register_new_node(offset, ctrl_off2); - *p_offset = offset; + Node* offset_sum = AddNode::make(offset2, offset3, bt); + register_new_node(offset_sum, get_ctrl(offset2)); + *p_offset = offset_sum; } return true; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/loopnode.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/loopnode.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/loopnode.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/loopnode.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1147,11 +1147,16 @@ return true; } +// This method extracts long range checks and computes the reduced iteration count (reduced_iters_limit) such that all +// extracted long range checks can be transformed. In particular, we check that +// - reduced_iters_limit * ABS(scale) <= original_iters_limit < max_jint +// - we have the proper form "scale*iv + offset _body.size(); i++) { Node* c = loop->_body.at(i); if (c->is_IfProj() && c->in(0)->is_RangeCheck()) { @@ -1166,6 +1171,7 @@ scale != min_jlong && original_iters_limit / ABS(scale) >= min_iters * ABS(stride_con)) { assert(scale == (jint)scale, "scale should be an int"); + // Ensure: reduced_iters_limit * ABS(scale) <= original_iters_limit < max_jint reduced_iters_limit = MIN2(reduced_iters_limit, original_iters_limit/ABS(scale)); range_checks.push(c); } @@ -1176,138 +1182,1056 @@ return checked_cast(reduced_iters_limit); } -// One execution of the inner loop covers a sub-range of the entire iteration range of the loop: [A,Z), aka [A=init, -// Z=limit). If the loop has at least one trip (which is the case here), the iteration variable i always takes A as its -// first value, followed by A+S (S is the stride), next A+2S, etc. The limit is exclusive, so that the final value B of -// i is never Z. It will be B=Z-1 if S=1, or B=Z+1 if S=-1. - -// If |S|>1 the formula for the last value B would require a floor operation, specifically B=floor((Z-sgn(S)-A)/S)*S+A, -// which is B=Z-sgn(S)U for some U in [1,|S|]. So when S>0, i ranges as i:[A,Z) or i:[A,B=Z-U], or else (in reverse) -// as i:(Z,A] or i:[B=Z+U,A]. It will become important to reason about this inclusive range [A,B] or [B,A]. - -// Within the loop there may be many range checks. Each such range check (R.C.) is of the form 0 <= i*K+L < R, where K -// is a scale factor applied to the loop iteration variable i, and L is some offset; K, L, and R are loop-invariant. -// Because R is never negative (see below), this check can always be simplified to an unsigned check i*K+L 0), where the limit is -// chosen to prevent various cases of 32-bit overflow (including multiplications j*K below). In the sub-loop the -// logical value i is offset from j by a 64-bit constant C, so i ranges in i:C+[0,Z_2). - -// For S<0, j ranges (in reverse!) through j:[-|B_2|,0] or (-|Z_2|,0]. For either sign of S, we can say i=j+C and j -// ranges through 32-bit ranges [A_2,B_2] or [B_2,A_2] (A_2=0 of course). - -// The disjoint union of all the C+[A_2,B_2] ranges from the sub-loops must be identical to the whole range [A,B]. -// Assuming S>0, the first C must be A itself, and the next C value is the previous C+B_2, plus S. If |S|=1, the next -// C value is also the previous C+Z_2. In each sub-loop, j counts from j=A_2=0 and i counts from C+0 and exits at -// j=B_2 (i=C+B_2), just before it gets to i=C+Z_2. Both i and j count up (from C and 0) if S>0; otherwise they count -// down (from C and 0 again). - -// Returning to range checks, we see that each i*K+L 0 and K>0), Q_min=A_2*K+Q and Q_max=Q (if S<0 and K>0), -// Q_min=B_2*K+Q and Q_max=Q if (S>0 and K<0), Q_min=Q and Q_max=A_2*K+Q (if S<0 and K<0) - -// Note that the first R.C. value is always Q=(S*K>0 ? Q_min : Q_max). Also Q_{min,max} = Q + {min,max}(A_2*K,B_2*K). -// If S*K>0 then, as the loop iterations progress, each R.C. value i*K+L = j*K+Q goes up from Q=Q_min towards Q_max. -// If S*K<0 then j*K+Q starts at Q=Q_max and goes down towards Q_min. - -// Case A: Some Negatives (but no overflow). -// Number line: -// |s64_min . . . 0 . . . s64_max| -// | . Q_min..Q_max . 0 . . . . | s64 negative -// | . . . . R=0 R< R< R< R< | (against R values) -// | . . . Q_min..0..Q_max . . . | small mixed -// | . . . . R R R< R< R< | (against R values) -// -// R values which are out of range (>Q_max+1) are reduced to max(0,Q_max+1). They are marked on the number line as R<. -// -// So, if Q_min 0 (R.C.E. steps upward) -// j*K + s32_trunc(Q_max) R R R< R< | (against R values) -// | . . . . 0 . Q_min..Q_max . | s64 positive -// | . . . . R> R> R R R< | (against R values) -// -// R values which are out of range (Q_max+1) are reduced as marked: R> up to Q_min, R< down to Q_max+1. -// Then the whole comparison is shifted left by Q_min, so it can take place at zero, which is a nice 32-bit value. -// -// So, if both Q_min, Q_max+1 >=s64 0, then use this test: -// j*K + 0 0 -// More generally: -// j*K + Q - Q_min R> R> R> R | (against R values) -// -// In this case, Q_min >s64 Q_max+1, even though the mathematical values of Q_min and Q_max+1 are correctly ordered. -// The formulas from the previous case can be used, except that the bad upper bound Q_max is replaced by max_jlong. -// (In fact, we could use any replacement bound from R to max_jlong inclusive, as the input to the clamp function.) -// -// So if Q_min >=s64 0 but Q_max+1 0 -// More generally: -// j*K + Q - Q_min H, it returns L not H. -// -// All of the formulas above can be merged into a single one: -// L_clamp = Q_min < 0 ? 0 : Q_min --whether and how far to left-shift -// H_clamp = Q_max+1 < Q_min ? max_jlong : Q_max+1 -// = Q_max+1 < 0 && Q_min >= 0 ? max_jlong : Q_max+1 -// Q_first = Q = (S*K>0 ? Q_min : Q_max) = (C*K+L) -// R_clamp = clamp(R, L_clamp, H_clamp) --reduced dynamic range -// replacement R.C.: -// j*K + Q_first - L_clamp = min_iters * ABS(stride_con) (KI-1) +// where +// K = scale +// min_iters = 2 +// 0 < original_iters_limit < max_jint +// ABS(stride_con) > 0 +// From (KI-1) +// min_iters * ABS(stride_con) = 2 * ABS(stride_con) <= original_iters_limit / ABS(K) +// then +// 2 * ABS(stride_con) * ABS(K) <= original_iters_limit +// and +// 0 <= ABS(K) <= original_iters_limit < max_jint +// +// It follows that K is indeed an int32_t (KI). +// +// Condition (R0) +// -------------- +// In PhaseIdealLoop::extract_long_range_check(), we check IdealLoopTree::is_range_check_if() which guarantees that +// R >= 0 +// because R is either a LoadRange or an integer that is non-negative (R0). +// +// Conditions (P-lo), (P-hi), (Q-lo), (Q-hi), and (Q-lo-hi) +// -------------------------------------------------------- +// j is to be the induction variable of an int counted loop (i.e. the inner iv). +// From PhaseIdealLoop::extract_long_range_check() and K = scale, we reduce the iterations so that: +// reduced_iters_limit * ABS(K) <= original_iters_limit < max_jint (Q1) +// +// By the fundamentals of an int counted loop, we have: +// j_min, j_max being int32_t values +// such that +// SI(j_min) <= SI(j) <= SI(j_max) (Q2) +// +// Furthermore, due to how we construct the int counted loop, we also have +// 0 <= SI(j_max) - SI(j_min) <= reduced_iters_limit (Q3) +// +// This means that: +// +// For K > 0, we multiply K to (Q2) +// SI(j_min) * K <= SI(j) * K <= SI(j_max) * K +// and to (Q3) +// 0 <= SI(j_max) * K - SI(j_min) * K <= reduced_iters_limit * K +// < max_jint (apply (Q1)) +// and we get +// 0 < SI(j_max) * K - SI(j_min) * K + 1 <= max_jint (Q4) +// +// For K < 0, we multiply K to (Q2) +// SI(j_min) * K >= SI(j) * K >= SI(j_max) * K +// and to (Q3) +// 0 <= SI(j_min) * K - SI(j_max) * K <= reduced_iters_limit * -K +// < max_jint (apply (Q1)) +// and we get +// 0 < SI(j_min) * K - SI(j_max) * K + 1 <= max_jint (Q5) +// +// Since the multiplication of int32_t values must be an int64_t value, we can choose: +// (P-lo): P_lo such that SL(P_lo) is the smallest value of "SI(j) * K" +// (P-hi): P_hi such that SL(P_hi) is the largest value of "SI(j) * K" plus 1. +// +// This means that: +// +// For K > 0, we have: +// SL(P_lo) = SI(j_min) * K +// SL(P_hi) = SI(j_max) * K + 1 +// which implies +// SL(P_lo) = SI(j_min) * K <= SI(j) * K <= SI(j_max) * K + 1 = SL(P_hi) +// Starting from (Q4) +// 0 < SI(j_max) * K - SI(j_min) * K + 1 <= max_jint +// we get +// 0 < SL(P_hi) - SL(P_lo) <= max_jint (Q6) +// +// For K < 0, we have: +// SL(P_lo) = SI(j_max) * K +// SL(P_hi) = SI(j_min) * K + 1 +// which implies +// SL(P_lo) = SI(j_max) * K <= SI(j) * K <= SI(j_min) * K + 1 = SL(P_hi) +// Starting from (Q5) +// 0 < SI(j_min) * K - SI(j_max) * K + 1 <= max_jint +// we get +// 0 < SL(P_hi) - SL(P_lo) <= max_jint (Q7) +// +// As a result, from (Q6) and (Q7), we see that +// 0 < SL(P_hi) - SL(P_lo) <= max_jint (Q8) +// +// From (P-lo) +// SL(P_lo) <= SI(j) * K +// and (P-hi) +// SL(P_hi) >= SI(j) * K + 1 +// and (Q8) follows +// 0 <= SI(j) * K - SL(P_lo) +// < SL(P_hi) - SL(P_lo) +// <= max_jint (Q9) +// +// Since SI(j) and K are int32_t values, their multiplication +// SI(j) * K +// cannot overflow the int64_t range and therefore +// SI(j) * K = SL(MulL(ConvI2L(j), K)) (Q10) +// +// Starting from (Q9) +// 0 <= SI(j) * K - SL(P_lo) < SL(P_hi) - SL(P_lo) <= max_jint +// it follows with (Q10) +// 0 <= SL(MulL(ConvI2L(j), K)) - SL(P_lo) < SL(P_hi) - SL(P_lo) <= max_jint (Q11) +// +// From (Q9) +// 0 <= SL(P_hi) - SL(P_lo) <= max_jint +// it follows that SubL(P_hi, P_lo) does not overflow the signed long domain: +// SL(SubL(P_hi, P_lo)) = SL(P_hi) - SL(P_lo) (Q12) +// and from (Q11) +// SubL(MulL(ConvI2L(j), K), P_lo) +// does not overflow the signed long domain: +// SL(SubL(MulL(ConvI2L(j), K), P_lo) = SL(MulL(ConvI2L(j), K)) - SL(P_lo) (Q13) +// +// From (Q11) +// 0 <= SL(MulL(ConvI2L(j), K)) - SL(P_lo) < SL(P_hi) - SL(P_lo) <= max_jint +// we apply (Q13) +// 0 <= SL(SubL(MulL(ConvI2L(j), K), P_lo)) < SL(P_hi) - SL(P_lo) <= max_jint +// and apply (Q12) +// 0 <= SubL(MulL(ConvI2L(j), K), P_lo) < SubL(P_hi, P_lo) <= max_jint (Q14) +// +// Note that we can do a simple reassociation of SubL if x, y, and z are int64_t: +// SubL(x, y) = SubL(AddL(x, z), AddL(y, z)) (Q15) +// We apply (Q15) to both sides of (Q14) +// 0 <= SubL( MulL(ConvI2L(j), K), P_lo)) < SubL( P_hi, P_lo) <= max_jint +// and get +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), AddL(P_lo, Q)) < SubL(AddL(P_hi, Q), AddL(P_lo, Q)) <= max_jint (Q16) +// +// We can insert +// Q_lo = AddL(P_lo, Q) (Q-lo) +// and +// Q_hi = AddL(P_hi, Q) (Q-hi) +// in (Q16) and get (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo ) < SubL(Q_hi, Q_lo) <= max_jint +// +// Condition (LHS) +// --------------- +// We ensure with +// PhaseIdealLoop::extract_long_range_check() -> PhaseIdealLoop::is_range_check_if() +// that we indeed have the form +// AddL(MulL(ConvI2L(j), K), Q) (done with PhaseIdealLoop::is_scaled_iv_plus_offset()) +// for the long range check with R (R0): +// LHS = CmpUL(AddL(MulL(ConvI2L(j), K), Q), R) +// +// +// We have our conditions +// (KI): K is an int32_t constant +// (P-lo): P_lo: The smallest value of "j * K" (i.e. the smallest value of the inner scaled iv), an int64_t value +// (P-hi): P_hi: The largest value of "j * K" (i.e. the largest value of the inner scaled iv) plus 1, an int64_t value +// (Q-lo): Q_lo = AddL(P_lo, Q), an int64_t value +// (Q-hi): Q_hi = AddL(P_hi, Q), an int64_t value +// (R0): R is an int64_t value such that R >= 0 +// (Q-lo-hi): 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) < SubL(Q_hi, Q_lo) <= max_jint +// (LHS): LHS = CmpUL(AddL(MulL(ConvI2L(j), K), Q), R) +// and define the additional variables +// (JI): j is the inner iv, an int32_t value (actually further clamped by the possible values of the inner iv) +// (QL): Q is an int64_t value +// (L-clamp): L_clamp = MaxL(Q_lo, 0) +// (H-clamp): H_clamp = Q_hi < Q_lo ? max_jlong : Q_hi +// (R-clamp): R_clamp = MaxL(MinL(R, H_clamp), L_clamp) +// and our target int range check as +// RHS = CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, L_clamp))), ConvL2I(SubL(R_clamp, L_clamp))) +// +// +// Now that we established our conditions and definitions, we prove that +// (LHS < 0) == (RHS < 0) +// which means that we can safely replace the long range check (LHS) with the int range check (RHS). +// +// +// Proof +// ===== +// Before starting with the proof, we start with some definitions and lemmas relevant for the proof. +// +// Definitions +// =========== +// Given x, y being int64_t values, we have: +// (CmpL-SL): CmpL(x, y) = Cmp(SL(x), SL(y)) +// (CmpUL-UL): CmpUL(x, y) = Cmp(UL(x), UL(y)) +// +// Given x, y being int64_t values with x < 0 and y >= 0: +// (CmpUL-gt): CmpUL(x, y) > 0 +// +// Given x being an int32_t value: +// (CmpU-gte-zero): CmpU(x, 0) >= 0 +// +// When the following AddL/SubL do not overflow, then: +// (AddL-SL-no-overflow): SL(AddL(x, y)) = SL(x) + SL(y) +// (SubL-UL-no-overflow): UL(SubL(x, y)) = UL(x) - UL(y) +// +// When x, y < 0, then +// (SubL-no-overflow): SubL(x, y) does not overflow the long signed domain +// +// No-Overflow-Lemmas +// ================== +// SubL-pos-no-overflow +// -------------------- +// When x, y >= 0, both being int64_t values, then +// SubL(x, y) +// does not overflow the long signed domain. +// +// Proof: +// max_jlong >= SL(x) - 0 +// > SL(x) - 1 +// > ... +// > SL(x) - max_jlong +// > min_jlong +// +// We refer to this lemma with (SubL-pos-no-overflow). +// +// AddL-no-overflow +// ---------------- +// When x <= 0 and y >= 0, both being int64_t values, then +// AddL(x, y) +// does not overflow the long signed domain. +// +// Proof: +// min_jlong <= SL(x) + 0 +// < SL(x) + 1 +// < ... +// < SL(x) + max_jlong +// <= max_jlong +// +// We refer to this lemma with (AddL-no-overflow). +// +// Lemma 1 +// ======= +// For x being an int64_t value such that min_jint <= x <= max_jint +// x = ConvI2L(ConvL2I(x)) +// +// Proof: +// If 0 <= x <= max_jint, the upper 33 bits of x are 0s. +// ConvL2I(x) truncates 32 bits, leaving a value with the highest bit being 0. +// ConvI2L(ConvL2I(x)) signed extends this value, filling the 32 upper bits of the result with 0. +// As a result, x and ConvI2L(ConvL2I(x)) have the same 32 lower bits, and their 32 upper bits are all 0, +// which means x == ConvI2L(ConvL2I(x)). +// +// Otherwise, min_jint <= x < 0, the upper 33 bits of x are 1s. +// ConvL2I(x) truncates 32 bits, leaving a value with the highest bit being 1. +// ConvI2L(ConvL2I(x)) signed extends this value, filling the 32 upper bits of the result with 1. +// As a result, x and ConvI2L(ConvL2I(x)) have the same 32 lower bits, and their 32 upper bits are all 1, which means x == ConvI2L(ConvL2I(x)) +// +// Lemma 2 +// ======= +// Fox x being an int32_t value +// x = ConvL2I(ConvI2L(x)) +// +// Proof: +// ConvL2I(ConvI2L(x)) extends x with 32 bits, then truncates those without touching the 32 lower bits. As a result, x == ConvL2I(ConvI2L(x)) +// +// Lemma 3 +// ======= +// For x, y being int32_t values +// CmpU(x, y) = CmpUL(ConvI2L(x), ConvI2L(y)) +// +// Proof: +// This is because +// UL(ConvI2L(0)) < UL(ConvI2L(1)) < UL(ConvI2L(2)) < ... < UL(ConvI2L(max_jint)) +// < UL(ConvI2L(min_jint)) < ... < UL(ConvI2L(-1)) +// is the same ordering as +// UI(0) < UI(1) < UI(2) < ... < UI(max_jint) < UI(min_jint) < ... < UI(-1) +// +// Lemma 4 +// ======= +// For x, y being int64_t values +// ConvL2I(AddL/SubL/MulL(x, y)) == AddI/SubI/MulI(ConvL2I(x), ConvL2I(y)) +// +// Proof: +// UI(ConvL2I(AddL(x, y))) == UL(AddL(x, y)) mod 2^32 (because UI(ConvL2I(v)) == UL(v) mod 2^32) +// == ((UL(x) + UL(y)) mod 2^64) mod 2^32 (because UL(AddL(u, v)) == (UL(u) + UL(v)) mod 2^64) +// == (UL(x) + UL(y)) mod 2^32 (because (v mod 2^64) mod 2^32 == v mod 2^32) +// == ((UL(x) mod 2^32) + (UL(y) mod 2^32)) mod 2^32 (because (u + v) mod 2^32 == ((u mod 2^32) + (v mod 2^32)) mod 2^32) +// == (UI(ConvL2I(x)) + UI(ConvL2I(y))) mod 2^32 (because UI(ConvL2I(v)) == UL(v) mod 2^32) +// == UI(AddI(ConvL2I(x), ConvL2I(y))) (because UI(AddI(u, v)) == (UI(u) + UI(v)) mod 2^32) +// +// Which means ConvL2I(AddL(x, y)) == AddI(ConvL2I(x), ConvL2I(y)) (because UI(u) == UI(v) necessarily implies u == v) +// +// Lemma 5 +// ======= +// For x, y, z being int64_t values such that AddL(x, z) and AddL(y, z) do not under-/overflow the signed long domain. +// CmpL(x, y) == CmpL(AddL(x, z), AddL(y, z)) +// +// Proof: +// This means that: +// CmpL(AddL(x, z), AddL(y, z)) = Cmp(SL(AddL(x, z)), SL(AddL(y, z)) (apply (CmpL-SL)) +// = Cmp(SL(x) + SL(z), SL(y) + SL(z)) (apply (AddL-SL-no-overflow))) +// = Cmp(S(x), S(y)) (because Cmp(u + t, v + t) == Cmp(u, v)) +// = CmpL(x, z) (apply (CmpL-SL)) +// +// Lemma 6 +// ======= +// For x, y, z being int64_t values such that SubL(x, z) and SubL(y, z) do not under-/overflow the unsigned long domain +// CmpUL(x, y) == CmpUL(SubL(x, z), SubL(y, z)) +// +// Proof: +// This means that: +// CmpUL(SubL(x, z), SubL(y, z)) = Cmp(UL(SubL(x, z)), UL(SubL(y, z))) (apply (CmpL-SL)) +// = Cmp(U(x) - U(z), U(y) - U(z)) (apply (SubL-UL-no-overflow)) +// = Cmp(U(x), U(y)) (because Cmp(u - t, v - t) == Cmp(u, v)) +// = CmpUL(x, y) (apply (CmpL-SL)) +// +// Lemma 7 +// ======= +// For x, y, z being int64_t values such that x < y, y >= 0, z >= 0 +// CmpUL(x, z) = CmpUL(x, MinL(y, z)) +// +// Proof: +// If y > z (trivial): +// CmpUL(x, z) = CmpUL(x, MinL(y, z)) +// = CmpUL(x, z) +// +// If y <= z: +// CmpUL(x, z) = CmpUL(x, MinL(y, z)) +// = CmpUL(x, y) +// +// We now show that for all x, the above equation is true. +// +// Case x >= 0: +// From all case assumptions, we have: +// 0 <= x < y <= z +// We can directly convert to unsigned +// 0 <=u x = 0 +// - 4. Q_hi < 0 < Q_lo +// for which we all need to show that +// (LHS < 0) == (RHS < 0) +// +// Case 1 and 3 can actually be improved: +// Case 1: Q_lo, Q_hi <= 0 -> Q_lo < Q_hi <= 0 +// Case 3: Q_lo, Q_hi >= 0 -> 0 <= Q_lo < Q_hi +// +// Proof by Contradiction: +// If Q_lo = Q_hi: +// SubL(Q_hi, Q_lo) = SubL(Q_hi, Q_hi) = 0 +// which violates (Q-lo-hi) +// 0 < SubL(Q_hi, Q_lo) <= max_jint +// +// If Q_lo > Q_hi: +// Case 1: Q_hi < Q_lo <= 0 +// Case 3: 0 <= Q_hi < Q_lo +// then +// min_jlong <= SubL(Q_hi, Q_lo) < 0 +// in both cases which violates (Q-lo-hi) +// +// +// We use the improved cases 1 and 3 in the following when proving +// (LHS < 0) == (RHS < 0) +// for all 4 cases for Q_hi and Q_lo: +// +// +// Case 1: Q_lo < Q_hi <= 0 +// ======================== +// We can simplify the given clamp values: +// L_clamp = MaxL(Q_lo, 0) +// = 0 +// H_clamp = Q_hi < Q_lo ? max_jlong : Q_hi +// = Q_hi +// R_clamp = MaxL(MinL(R, H_clamp), L_clamp) +// = MaxL(MinL(R, Q_hi ), 0) +// = MaxL(Q_hi, 0) (because R >= 0, Q_hi < 0) +// = 0 (because Q_hi < 0) +// +// +// From (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) < SubL(Q_hi, Q_lo) +// together with Q_lo < 0 (Case 1), we see that +// AddL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), Q_lo) +// ---------------- >= 0 ------------------ --- < 0 --- +// and +// AddL(SubL(Q_hi, Q_lo), Q_lo) +// ----- > 0 ----- --- < 0 --- +// both cannot not overflow the signed long domain (1-no-overflow) due to (AddL-no-overflow). +// +// The form (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) < SubL(Q_hi, Q_lo) <= max_jint +// can also be written as +// CmpL( SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), SubL(Q_hi, Q_lo)) < 0 +// with (1-no-overflow), we can apply Lemma 5 and add Q_lo to both sides +// CmpL(AddL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), Q_lo), AddL(SubL(Q_hi, Q_lo), Q_lo)) < 0 +// cancel out the Q_lo terms +// CmpL( AddL(MulL(ConvI2L(j), K), Q), Q_hi) < 0 +// and with (Case 1) see that +// AddL(MulL(ConvI2L(j), K), Q) < Q_hi <= 0 (1a) +// +// From (1a), we know that +// a = AddL(MulL(ConvI2L(j), K), Q) < 0 +// and from (R0) that +// b = R >= 0 +// which satisfies (CmpUL-gt) and we can conclude that +// LHS = CmpUL(AddL(MulL(ConvI2L(j), K), Q), R) > 0 +// ----------- = a ----------- --- = b --- +// +// Inserting the simplified L_clamp and R_clamp from above, we get for RHS +// RHS == CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, L_clamp))), ConvL2I(SubL(R_clamp, L_clamp))) +// == CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, 0))), ConvL2I(SubL(0, 0))) +// == CmpU(AddI(MulI(j, K), ConvL2I( Q )), 0) +// == CmpU(c , 0) +// >= 0 (apply (CmpU-gte-zero)) +// +// +// We showed that +// LHS > 0 +// and +// RHS >= 0 +// and therefore proved that +// (LHS < 0) == (RHS < 0) == false +// +// +// Case 2: Q_lo < 0 < Q_hi +// ======================= +// We can simplify the given clamp values: +// L_clamp = MaxL(Q_lo, 0) +// = 0 +// H_clamp = Q_hi < Q_lo ? max_jlong : Q_hi +// = Q_hi +// R_clamp = MaxL(MinL(R, H_clamp), L_clamp) +// = MaxL(MinL(R, Q_hi ), 0) +// = MinL(R, Q_hi) (because R, Q_hi >= 0) +// +// +// Looking at (Case 2): +// Q_hi > 0 > Q_lo +// we have a constrained positive difference +// 0 < SL(Q_hi) - SL(Q_lo) +// <= max_jlong + (-min_jlong) +// = (2 * max_jlong) + 1 +// = 2^64 - 1 +// +// If +// 0 < SL(Q_hi) - SL(Q_lo) <= max_jlong +// then we don't have an overflow of SubL(Q_hi, Q_lo). +// +// If +// max_jlong < SL(Q_hi) - SL(Q_lo) <= 2^64 - 1 +// then SubL(Q_hi, Q_lo) leads to exactly one overflow. The result is always negative: +// SubL(Q_hi, Q_lo) = TruncL(SL(Q_hi) - SL(Q_lo)) = SL(Q_hi) - SL(Q_lo) - 2^64 < 0 +// This case is impossible as it violates (Q-lo-hi) +// 0 < SubL(Q_hi, Q_lo) +// We conclude that SubL(Q_hi, Q_lo) does not overflow the signed long domain (2a-no-overflow). +// +// +// From (Q-lo-hi) and (2a-no-overflow), we get +// max_jint >= SubL(Q_hi, Q_lo) +// = SL(SubL(Q_hi, Q_lo)) +// = SL(Q_hi) - SL(Q_lo) (2a) +// +// Moreover, from (Case 2), we get +// Q_hi > 0 +// SL(Q_hi) > 0 (2b) +// and +// Q_lo < 0 +// SL(Q_lo) < 0 (2c) +// +// It follows for Q_lo +// SL(Q_lo) = SL(Q_hi) - (SL(Q_hi) - SL(Q_lo)) +// > 0 - (SL(Q_hi) - SL(Q_lo)) (apply (2b)) +// >= 0 - max_jint (apply (2a)) +// = -max_jint +// and as a result +// Q_lo > -max_jint (2e) +// +// It follows for Q_hi +// SL(Q_hi) = (SL(Q_hi) - SL(Q_lo)) + SL(Q_lo) +// <= max_jint + SL(Q_lo) (apply (2a)) +// < max_jint (apply (2c)) +// and as a result +// Q_hi < max_jint (2f) +// +// With (2e) (2f), and (Case 2), we see that Q_lo and Q_hi fit into the 32-bit integer range: +// -max_jint < Q_lo < 0 < Q_hi < max_jint (2g) +// +// +// From (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) < SubL(Q_hi, Q_lo) <= max_jint +// together with Q_lo < 0 (Case 2), we see that neither adding Q_lo to the left side +// AddL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), Q_lo) +// ---------------- >= 0 ------------------ --- < 0 --- +// nor to the right side +// AddL(SubL(Q_hi, Q_lo), Q_lo) +// ----- > 0 ----- --- < 0 --- +// can overflow the signed long domain (2b-no-overflow). +// +// +// The form (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) < SubL(Q_hi, Q_lo) <= max_jint +// can also be written as +// CmpL( SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), SubL(Q_hi, Q_lo)) < 0 +// with (2b-no-overflow), we can apply Lemma 5 to add Q_lo +// CmpL(AddL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), Q_lo), AddL(SubL(Q_hi, Q_lo), Q_lo)) < 0 +// cancel out the Q_lo terms +// CmpL( AddL(MulL(ConvI2L(j), K), Q), Q_hi) < 0 +// and with (Case 2) and (2f) see that +// AddL(MulL(ConvI2L(j), K), Q) < Q_hi < max_jint (2h) +// +// +// From (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) +// we see that neither adding Q_lo to the left side +// AddL(0, Q_lo) = Q_lo +// nor to the right side (already shown with (2b-no-overflow)) +// AddL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), Q_lo) +// can overflow the signed long domain (2c-no-overflow). +// +// +// The form (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) < SubL(Q_hi, Q_lo) <= max_jint +// can also be written as +// CmpL( 0, SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo)) <= 0 +// with (2c-no-overflow), we can apply Lemma 5 to add Q_lo +// CmpL(AddL(0, Q_lo), AddL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), Q_lo)) <= 0 +// cancel out the Q_lo terms and simplify +// CmpL( Q_lo , AddL( MulL(ConvI2L(j), K), Q)) <= 0 +// and with (Case 2) and (2e) see that +// AddL(MulL(ConvI2L(j), K), Q) >= Q_lo > -max_jint (2i) +// +// +// Putting (2h) and (2i) together, we see that the AddL actually fits into the 32-bit integer range +// -max_jint < Q_lo <= AddL(MulL(ConvI2L(j), K), Q) < Q_hi < max_jint (2j) +// +// With (2j) and (R0), we also conclude +// -max_jint < MinL(Q_hi, R) < max_jint (2k) +// +// We notice with +// (2h): x = AddL(MulL(ConvI2L(j), K), Q) < Q_hi +// (Case 2): y = Q_hi > 0 +// (R0): z = R >= 0 +// that Lemma 7 can be applied +// LHS = CmpUL( AddL(MulL(ConvI2L(j), K), Q), R) +// ------------------ x ----------------- -- z -- +// = CmpUL( AddL(MulL(ConvI2L(j), K), Q), MinL(Q_hi, R)) +// ------------------ x ----------------- -- y -- -- z -- +// apply Lemma 1 to add ConvI2L-ConvL2I to both sides of CmpUL because they both fit into an int32_t ((2j) and (2k)) +// LHS = CmpUL(ConvI2L(ConvL2I(AddL(MulL(ConvI2L(j), K), Q))), ConvI2L(ConvL2I(MinL(Q_hi, R)))) +// apply Lemma 3 to transform to CmpU because both sides of CmpUL are int32_t values +// = CmpU ( ConvL2I(AddL(MulL(ConvI2L(j), K), Q)) , ConvL2I(MinL(Q_hi, R)) +// apply Lemma 4 twice to move the ConvL2I inwards +// = CmpU ( AddI(ConvL2I( MulL(ConvI2L(j), K)), ConvL2I(Q)), ConvL2I(MinL(Q_hi, R))) +// = CmpU ( AddI(MulI( ConvL2I(ConvI2L(j)), ConvL2I(K)), ConvL2I(Q)), ConvL2I(MinL(Q_hi, R))) +// apply Lemma 2 to remove the ConvL2I-ConvI2L due to (JI) and simplify K due to (KI) +// = CmpU ( AddI(MulI( j, K), ConvL2I(Q)), ConvL2I(MinL(Q_hi, R))) +// we now add a minus 0 on Q and MinL() +// = CmpU( AddI(MulI( j, K), ConvL2I(SubL(Q, 0))), ConvL2I(SubL(MinL(Q_hi, R), 0))) +// and eventually insert the simplified L_clamp and R_clamp values +// = CmpU( AddI(MulI( j, K), ConvL2I(SubL(Q, L_clamp))), ConvL2I(SubL(R_clamp, L_clamp))) +// which is equivalent to the definition of RHS +// +// +// We proved that +// LHS = RHS +// and thus +// (LHS < 0) == (RHS < 0) +// +// +// Case 3: 0 <= Q_lo < Q_hi +// ======================== +// We can simplify the given clamp values: +// L_clamp = MaxL(Q_lo, 0) +// = Q_lo +// H_clamp = Q_hi < Q_lo ? max_jlong : Q_hi +// = Q_hi +// R_clamp = MaxL(MinL(R, H_clamp), L_clamp) +// = MaxL(MinL(R, Q_hi), Q_lo) +// +// RHS = CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, L_clamp))), ConvL2I(SubL(R_clamp, L_clamp))) +// = CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(MaxL(MinL(R, Q_hi), Q_lo), Q_lo))) +// +// Let's first look at both SubL of (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) < SubL(Q_hi, Q_lo) <= max_jint +// +// We see with (SubL-pos-no-overflow) and (Case 3) that +// SubL(Q_hi, Q_lo) +// does not overflow the signed long domain. Therefore, adding +// Q_lo >= 0 (from Case 3) +// to the right side +// AddL(SubL(Q_hi, Q_lo), Q_lo) = Q_hi +// does not overflow the signed long domain and therefore adding +// Q_lo >= 0 (from Case 3) +// to the left side SubL +// AddL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) Q_lo) < AddL(SubL(Q_hi, Q_lo), Q_lo) +// also does not overflow the signed long domain (3a-no-overflow). +// +// +// The form (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) < SubL(Q_hi, Q_lo) <= max_jint +// can also be written as +// CmpL( SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), SubL(Q_hi, Q_lo)) < 0 +// with (3a-no-overflow), we can apply Lemma 5 and add Q_lo to both sides without overflow +// CmpL(AddL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), Q_lo), AddL(SubL(Q_hi, Q_lo), Q_lo)) < 0 +// cancel out the Q_lo terms +// CmpL( AddL(MulL(ConvI2L(j), K), Q), Q_hi) < 0 +// and see that +// AddL(MulL(ConvI2L(j), K), Q) < Q_hi (3a) +// +// +// From (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) +// we see that neither adding Q_lo to the left side +// AddL(0, Q_lo) = Q_lo +// nor to the right side (3a-no-overflow) +// AddL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), Q_lo) +// can overflow the signed long domain (3b-no-overflow). +// +// +// The form (Q-lo-hi) +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) < SubL(Q_hi, Q_lo) <= max_jint +// can also be written as +// CmpL( 0, SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo)) <= 0 +// with (3b-no-overflow), we can apply Lemma 5 and add Q_lo to both sides without overflow +// CmpL(AddL(0, Q_lo), AddL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), Q_lo)) <= 0 +// cancel out the Q_lo terms and simplify +// CmpL( Q_lo , AddL( MulL(ConvI2L(j), K), Q)) <= 0 +// and seee that +// AddL(MulL(ConvI2L(j), K), Q) >= Q_lo (3b) +// +// +// Putting (3a) and (3b) together, we see that +// 0 <= Q_lo <= AddL(MulL(ConvI2L(j), K), Q) < Q_hi (3c) +// +// Looking at the definition of LHS +// LHS = CmpUL(AddL(MulL(ConvI2L(j), K), Q), R) +// we have 3 cases for R with respect to Q_lo and Q_hi: +// 3-R1: 0 <= R <= Q_lo +// 3-R2: 0 <= Q_lo < R < Q_hi +// 3-R3: 0 <= Q_lo < Q_hi <= R +// +// We need to prove for all three cases that (LHS < 0) == (RHS < 0) +// +// 3-R1: 0 <= R <= Q_lo +// -------------------- +// Combining (3-R1) and (3c), we have +// 0 <= R <= Q_lo <= AddL(MulL(ConvI2L(j), K), Q) < Q_hi +// and conclude +// LHS = CmpUL(AddL(MulL(ConvI2L(j), K), Q), R) +// >= 0 +// +// From the definition of RHS +// RHS = CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(MaxL(MinL(R, Q_hi), Q_lo), Q_lo))) +// we know from (3-R1) that R < Q_hi: +// RHS = CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(MaxL( R , Q_lo), Q_lo))) +// and R <= Q_lo: +// RHS = CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL( Q_lo , Q_lo))) +// = CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), 0) +// = CmpU(c , 0) +// >= 0 (apply (CmpU-gte-zero)) +// +// +// We showed that +// LHS >= 0 +// and +// RHS >= 0 +// and therefore proved that +// (LHS < 0) == (RHS < 0) == false +// +// +// 3-R2: 0 <= Q_lo < R < Q_hi +// -------------------------- +// From (Q-lo-hi) +// 0 <= SubL(Q_hi, Q_lo) <= max_jint +// and (3-R2), we see that subtracting Q_lo from R +// 0 < SubL(R, Q_lo) < SubL(Q_hi, Q_lo) <= max_jint (3d) +// does not overflow the unsigned long domain (3-R2a-no-overflow). +// +// Further, we know from (3c) +// 0 <= Q_lo <= AddL(MulL(ConvI2L(j), K), Q) +// that subtracting Q_lo +// 0 <= SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) <= AddL(MulL(ConvI2L(j), K), Q) +// does also not overflow the unsigned long domain (3-R2b-no-overflow). +// +// We can now apply several lemmas and transformations to show the equivalence of LHS and RHS +// LHS = CmpUL( AddL(MulL(ConvI2L(j), K), Q), R) +// apply Lemma 6 to add SubL to both sides because both SubL do not overflow ((3-R2a-no-overflow) and (3-R2b-no-overflow)) +// LHS = CmpUL( SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), SubL(R, Q_lo)) +// apply Lemma 1 to add ConvI2L-ConvL2I because both sides of CmpUL are int32_t values ((Q-lo-hi) + (3d)) +// LHS = CmpUL(ConvI2L(ConvL2I(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo)), ConvI2L( ConvL2I(SubL(R, Q_lo))))) +// apply Lemma 3 to transform to CmpU because both sides of CmpUL are int32_t values +// LHS = CmpU (ConvL2I( SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo)), ConvL2I(SubL(R, Q_lo))) +// apply Lemma 4 twice to move the ConvL2I inwards +// LHS = CmpU (AddI(ConvL2I( MulL(ConvI2L(j), K )), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(R, Q_lo))) +// = CmpU (AddI(MulI(ConvL2I( ConvI2L(j)), ConvL2I(K)), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(R, Q_lo))) +// apply Lemma 2 to remove the ConvL2I-ConvI2L due to (JI) and simplify K due to (KI) +// LHS = CmpU (AddI(MulI( j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(R, Q_lo))) +// and space it differently +// LHS = CmpU (AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL( R , Q_lo))) +// apply R > Q_lo (3-R2) to add an equivalent MaxL for R +// LHS = CmpU (AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(MaxL( R , Q_lo), Q_lo))) +// apply R < Q_hi (3-R2) to add an equivlanet MinL for R +// LHS = CmpU (AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(MaxL(MinL(R, Q_hi), Q_lo), Q_lo))) +// which is equivalent to the definition of RHS +// +// +// We proved that +// LHS = RHS +// and thus +// (LHS < 0) == (RHS < 0) +// +// +// 3-R3: 0 <= Q_lo < Q_hi <= R +// -------------------------- +// From (3-R3) and (3c), we know that +// 0 <= AddL(MulL(ConvI2L(j), K), Q) < Q_hi <= R +// 0 <= AddL(MulL(ConvI2L(j), K), Q) < R +// and therefore +// LHS = CmpUL(AddL(MulL(ConvI2L(j), K), Q), R) +// < 0 +// +// +// From the definition of +// RHS = CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(MaxL(MinL(R, Q_hi), Q_lo), Q_lo))) +// we know from (3-R3) that R >= Q_hi: +// RHS = CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(MaxL( Q_hi, Q_lo), Q_lo))) +// and Q_lo < Q_hi: +// RHS = CmpU(AddI(MulI(j, K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL( Q_hi, Q_lo))) +// apply Lemma 2 to j due to (JI) +// RHS = CmpU(AddI(MulI(ConvL2I(ConvI2L(j)), K), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(Q_hi, Q_lo))) +// apply Lemma 4 twice to move the ConvL2I outwards +// RHS = CmpU(AddI(ConvL2I(MulL(ConvI2L(j), K)), ConvL2I(SubL(Q, Q_lo))), ConvL2I(SubL(Q_hi, Q_lo))) +// CmpU(ConvL2I(AddL(MulL(ConvI2L(j), K), SubL(Q, Q_lo))), ConvL2I(SubL(Q_hi, Q_lo))) +// ------- x -------- -- y -- -- z -- +// reassociated AddL/SubL +// AddL(x, SubL(y, z)) = SubL(AddL(x, y), z) +// and space it differently as +// RHS = CmpU (ConvL2I( SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo)), ConvL2I( SubL(Q_hi, Q_lo))) +// ------- x -------- -- y -- -- z -- +// apply Lemma 3 to transform to CmpUL form because both sides are int32_t values due to (Q-lo-hi) +// RHS = CmpUL(ConvI2L(ConvL2I(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo))), ConvI2L(ConvL2I(SubL(Q_hi, Q_lo)))) +// apply Lemma 1 to remove both ConvI2L-ConvL2I because the inner values are int32_t due to (Q-lo-hi) +// RHS = CmpUL( SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), SubL(Q_hi, Q_lo)) +// and see with (Q-lo-hi) that +// RHS < 0 +// +// We showed that +// LHS < 0 +// and +// RHS < 0 +// and therefore proved that +// (LHS < 0) == (RHS < 0) == true +// +// +// Case 4: Q_hi < 0 < Q_lo +// ======================= +// We can simplify the given clamp values: +// L_clamp = MaxL(Q_lo, 0) +// = Q_lo +// H_clamp = Q_hi < Q_lo ? max_jlong : Q_hi +// = max_jlong +// R_clamp = MaxL(MinL(R, H_clamp), L_clamp) +// = MaxL(MinL(R, max_jlong), Q_lo) +// = MaxL(R, Q_lo) (because R <= max_jlong (R0)) +// +// And insert them into the definition of +// RHS = CmpU(AddI(MulI( j, K), ConvL2I(SubL(Q, L_clamp))), ConvL2I(SubL(R_clamp, L_clamp))) +// = CmpU(AddI(MulI( j, K), ConvL2I(SubL(Q, Q_lo)), ConvL2I(SubL(MaxL(R, Q_lo), Q_lo)))) +// apply Lemma 2 to add ConvL2I-ConvI2L due to (JI) +// RHS = CmpU(AddI(MulI(ConvL2I(ConvI2L(j)), K), ConvL2I(SubL(Q, Q_lo)), ConvL2I(SubL(MaxL(R, Q_lo), Q_lo))) +// apply Lemma 4 twice to move the ConvL2I outwards: +// RHS = CmpU(AddI(ConvL2I(MulL(ConvI2L(j), K)), ConvL2I(SubL(Q, Q_lo)), ConvL2I(SubL(MaxL(R, Q_lo), Q_lo))) +// = CmpU(ConvL2I(AddL(MulL(ConvI2L(j), K), SubL(Q, Q_lo))), ConvL2I(SubL(MaxL(R, Q_lo), Q_lo))) +// ------- x -------- -- y -- -- z -- +// reassociate AddL/SubL +// AddL(x, SubL(y, z)) = SubL(AddL(x, y), z) +// and space it differently as +// RHS = CmpU(ConvL2I( SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo)), C onvL2I(SubL(MaxL(R, Q_lo), Q_lo))) +// ------- x -------- -- y -- -- z -- +// apply Lemma 3 to transform to CmpUL form because both sides are int32_t values with ConvL2I +// RHS = CmpUL(ConvI2L(ConvL2I(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo))), ConvI2L(ConvL2I(SubL(MaxL(R, Q_lo), Q_lo)))) +// apply Lemma 1 to remove the left ConvI2L-ConvL2I because the inner value is int32_t due to (Q-lo-hi) +// RHS = CmpUL( SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), ConvI2L(ConvL2I(SubL(MaxL(R, Q_lo), Q_lo)))) +// +// +// To remove the right-side ConvI2L-ConvL2I, we first need to show that +// SubL(MaxL(R, Q_lo), Q_lo) +// is an int32_t value +// +// SubL is an int32_t +// ------------------ +// (Case 4) +// Q_hi < 0 < Q_lo +// is equivalent to +// 0 u 0 +// does not overflow the unsigned long domain and thus +// UL(Q_hi) - UL(Q_lo) = UL(SubL(Q_hi, Q_lo)) (4b) +// +// It also follows that +// Q_hi u> max_jlong +// UL(Q_hi) > max_jlong (4c) +// +// From (R0) +// 0 <= R <= max_jlong +// and (Case 4) +// 0 <= Q_lo <= max_jlong +// we see that +// 0 <= MaxL(R, Q_lo) <= max_jlong (4d) +// +// We notice that +// 0 < Q_lo <= MaxL(R, Q_lo) +// which means that +// 0 <= SubL(MaxL(R, Q_lo), Q_lo) +// does not overflow the unsigned long domain (4b-no-overflow) +// +// +// With (4b-no-overflow), we get +// 0 <= SubL(MaxL(R, Q_lo), Q_lo) +// = UL(SubL(MaxL(R, Q_lo), Q_lo)) +// = UL(MaxL(R, Q_lo)) - UL(Q_lo) +// <= max_jlong - UL(Q_lo) (apply (4d)) +// < UL(Q_hi) - UL(Q_lo) (apply (4c)) +// = UL(SubL(Q_hi, Q_lo)) (apply (4b)) +// <= UL(max_jint) (apply (Q-lo-hi)) +// = max_jint +// and thus showed that +// 0 <= SubL(MaxL(R, Q_lo), Q_lo) < max_jint (4e) +// indeed fits into an int32_t. +// +// +// Thus, we can apply Lemma 1 to remove the second ConvI2L-ConvL2I as well +// RHS = CmpUL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), ConvI2L(ConvL2I(SubL(MaxL(R, Q_lo), Q_lo)))) +// RHS = CmpUL(SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo), SubL(MaxL(R, Q_lo), Q_lo)) +// +// We now want to remove the SubL on both sides with Lemma 6. We already showed with (4e) that the right SubL does +// not overflow. Which leaves us by showing that the left SubL does not overflow. +// +// +// No Overflow of Left SubL +// ------------------------ +// Consider the subtraction +// UL(x - Q_lo) +// which only overflows if +// x = Q_lo +// 4-R2: R < Q_lo +// +// We need to prove for both cases that (LHS < 0) == (RHS < 0) +// +// 4-R1: R >= Q_lo +// --------------- +// Starting from (4g) +// RHS = CmpUL(AddL(MulL(ConvI2L(j), K), Q), MaxL(R, Q_lo)) +// = CmpUL(AddL(MulL(ConvI2L(j), K), Q), R) +// = LHS +// +// which implies (LHS < 0) == (RHS < 0) +// +// 4-R2: R < Q_lo +// --------------- +// Starting from (4g) +// RHS = CmpUL(AddL(MulL(ConvI2L(j), K), Q), MaxL(R, Q_lo)) +// = CmpUL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) +// +// From (4c-no-overflow), we know, that +// SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) +// does not overflow and with (Q-lo-hi) +// 0 < SubL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) < max_jint +// it follows that +// 0 =u Q_lo (4h) +// must hold and therefore +// RHS = CmpUL(AddL(MulL(ConvI2L(j), K), Q), Q_lo) >= 0 +// +// From (4-R2) and (R0) we know +// 0 <= R < Q_lo +// which is the same as +// R 0 +// +// We showed that +// LHS > 0 +// and +// RHS >= 0 +// and therefore proved that +// (LHS < 0) == (RHS < 0) == false +// +// We proved that the transformation is valid under the stated pre-conditions. void PhaseIdealLoop::transform_long_range_checks(int stride_con, const Node_List &range_checks, Node* outer_phi, Node* inner_iters_actual_int, Node* inner_phi, Node* iv_add, LoopNode* inner_head) { @@ -1328,150 +2252,195 @@ // could be shared and have already been taken care of continue; } - bool short_scale = false; - bool ok = is_scaled_iv_plus_offset(rc_cmp->in(1), iv_add, T_LONG, &scale, &offset, &short_scale); + bool ok = is_scaled_iv_plus_offset(rc_cmp->in(1), iv_add, T_LONG, &scale, &offset); assert(ok, "inconsistent: was tested before"); + // Because is_scaled_iv_plus_offset is successful, we know that + // rc_cmp->in(1) is semantically equivalent to either: + // AddL(MulL(iv_add, scale), offset), if iv_add is long; or + // AddL(MulL(ConvI2L(iv_add), scale), offset), if iv_add is int. + // See the equivalence proof in PhaseIdealLoop::is_scaled_iv_plus_offset and + // functions called therein. Node* range = rc_cmp->in(2); Node* c = rc->in(0); Node* entry_control = inner_head->in(LoopNode::EntryControl); Node* R = range; Node* K = longcon(scale); - Node* L = offset; - - if (short_scale) { - // This converts: - // (int)i*K + L u64 (long)max_jint and still is C, int_zero, inner_iters_actual_int, int_stride); - register_new_node(B_2, entry_control); - B_2 = new SubINode(B_2, int_stride); - register_new_node(B_2, entry_control); - B_2 = new ConvI2LNode(B_2); - register_new_node(B_2, entry_control); - - Node* Q_max = new MulLNode(B_2, K); - register_new_node(Q_max, entry_control); - Q_max = new AddLNode(Q_max, Q_first); - register_new_node(Q_max, entry_control); - + // Last iteration, j = last, where + // last = ((iter_count - 1) * stride + init) + // = ( iter_count * stride + init) - stride + // = LoopLimitNode(init, limit, stride ) - stride + // = LoopLimitNode(0, inner_iters_actual_int, int_stride) - stride + // which is used to get + // Q_last = (j * K) + Q + // = (last * K) + Q + // = (LoopLimitNode(0, inner_iters_actual_int, int_stride) - stride * K) + Q (def. of last) + // = (LoopLimitNode(0, inner_iters_actual_int, int_stride) - stride * K) + (C * K) + L (def. of Q) + // = (LoopLimitNode(0, inner_iters_actual_int, int_stride) - stride * K) + Q_first (def. of Q_first) + Node* last = new LoopLimitNode(this->C, int_zero, inner_iters_actual_int, int_stride); + register_new_node(last, entry_control); + last = new SubINode(last, int_stride); + register_new_node(last, entry_control); + last = new ConvI2LNode(last); + register_new_node(last, entry_control); + + Node* Q_last = new MulLNode(last, K); + register_new_node(Q_last, entry_control); + Q_last = new AddLNode(Q_last, Q_first); + register_new_node(Q_last, entry_control); + + // We define Q_lo and Q_hi now from Q_first, Q_last, P_lo, and P_hi: + // + // If Q_first < Q_last (which is the case if scale * stride_con > 0): + // Q_lo = P_lo + Q (def. Q_lo) + // = 0 * K + Q (def. P_lo) + // = Q + // = Q_first + // and + // Q_hi = P_hi + Q (def. Q_hi) + // = last * K + 1 + Q (def. P_hi) + // = last * K + Q + 1 + // = Q_last + 1 + // If Q_first > Q_last (which is the case if scale * stride_con < 0): + // Q_lo = P_lo + Q (def. Q_lo) + // = last * K + Q (def. P_lo) + // = Q_last + // and + // Q_hi = P_hi + Q (def. Q_hi) + // = 0 * K + 1 + Q (def. P_hi) + // = 0 * K + Q + 1 + // = Q_first + 1 + Node* Q_lo = Q_first; + Node* Q_hi = Q_last; if (scale * stride_con < 0) { - swap(Q_min, Q_max); + swap(Q_lo, Q_hi); } - // Now, mathematically, Q_max > Q_min, and they are close enough so that (Q_max-Q_min) fits in 32 bits. - // L_clamp = Q_min < 0 ? 0 : Q_min - Node* Q_min_cmp = new CmpLNode(Q_min, long_zero); - register_new_node(Q_min_cmp, entry_control); - Node* Q_min_bool = new BoolNode(Q_min_cmp, BoolTest::lt); - register_new_node(Q_min_bool, entry_control); - Node* L_clamp = new CMoveLNode(Q_min_bool, Q_min, long_zero, TypeLong::LONG); + // Q_lo is now correct. Add plus one to get the correct Q_hi value as defined above as well: + Q_hi = new AddLNode(Q_hi, long_one); + register_new_node(Q_hi, entry_control); + + // Let's next define all clamp values: + // + // First, we compute + // L_clamp = Q_lo < 0 ? 0 : Q_lo + Node* Q_lo_cmp = new CmpLNode(Q_lo, long_zero); + register_new_node(Q_lo_cmp, entry_control); + Node* Q_lo_bool = new BoolNode(Q_lo_cmp, BoolTest::lt); + register_new_node(Q_lo_bool, entry_control); + Node* L_clamp = new CMoveLNode(Q_lo_bool, Q_lo, long_zero, TypeLong::LONG); register_new_node(L_clamp, entry_control); - // (This could also be coded bitwise as L_clamp = Q_min & ~(Q_min>>63).) - - Node* Q_max_plus_one = new AddLNode(Q_max, long_one); - register_new_node(Q_max_plus_one, entry_control); + // (This could also be coded bitwise as L_clamp = Q_lo & ~(Q_lo>>63).) - // H_clamp = Q_max+1 < Q_min ? max_jlong : Q_max+1 - // (Because Q_min and Q_max are close, the overflow check could also be encoded as Q_max+1 < 0 & Q_min >= 0.) + // Next, we compute + // H_clamp = Q_hi< Q_lo ? max_jlong : Q_hi Node* max_jlong_long = longcon(max_jlong); - Node* Q_max_cmp = new CmpLNode(Q_max_plus_one, Q_min); - register_new_node(Q_max_cmp, entry_control); - Node* Q_max_bool = new BoolNode(Q_max_cmp, BoolTest::lt); - register_new_node(Q_max_bool, entry_control); - Node* H_clamp = new CMoveLNode(Q_max_bool, Q_max_plus_one, max_jlong_long, TypeLong::LONG); + Node* Q_hi_cmp = new CmpLNode(Q_hi, Q_lo); + register_new_node(Q_hi_cmp, entry_control); + Node* Q_hi_bool = new BoolNode(Q_hi_cmp, BoolTest::lt); + register_new_node(Q_hi_bool, entry_control); + Node* H_clamp = new CMoveLNode(Q_hi_bool, Q_hi, max_jlong_long, TypeLong::LONG); register_new_node(H_clamp, entry_control); - // (This could also be coded bitwise as H_clamp = ((Q_max+1)<<1 | M)>>>1 where M = (Q_max+1)>>63 & ~Q_min>>63.) + // (This could also be coded bitwise as H_clamp = ((Q_hi)<<1 | M)>>>1 where M = (Q_hi)>>63 & ~Q_lo>>63.) + + // Finally, we compute + // R_clamp = MaxL(MinL(R, H_clamp), L_clamp) + Node* R_clamp = clamp(R, L_clamp, H_clamp); + + // Now we have everything together to transform the long range check: + // (i * K) + L = 0 - // and also: R_2 = clamp(R, L_clamp, Q_max+1) - L_clamp if Q_min < Q_max+1 (no overflow) - // or else: R_2 = clamp(R, L_clamp, *no limit*)- L_clamp if Q_max+1 < Q_min (overflow) - Node* R_2 = clamp(R, L_clamp, H_clamp); - R_2 = new SubLNode(R_2, L_clamp); - register_new_node(R_2, entry_control); - R_2 = new ConvL2INode(R_2, TypeInt::POS); - register_new_node(R_2, entry_control); - - // L_2 = Q_first - L_clamp - // We are subtracting L_clamp from both sides of the 0, then Q_first == 0 and the R.C. expression at -L_clamp and steps upward to Q_max-L_clamp. - // If S*K<0, then Q_first != 0 and the R.C. expression starts high and steps downward to Q_min-L_clamp. - Node* L_2 = new SubLNode(Q_first, L_clamp); - register_new_node(L_2, entry_control); - L_2 = new ConvL2INode(L_2, TypeInt::INT); - register_new_node(L_2, entry_control); - - // Transform the range check using the computed values L_2/R_2 - // from: i*K + L (scale)); Node* scaled_iv = new MulINode(inner_phi, K); register_new_node(scaled_iv, c); - Node* scaled_iv_plus_offset = new AddINode(scaled_iv, L_2); + Node* scaled_iv_plus_offset = new AddINode(scaled_iv, L2); register_new_node(scaled_iv_plus_offset, c); - Node* new_rc_cmp = new CmpUNode(scaled_iv_plus_offset, R_2); + Node* new_rc_cmp = new CmpUNode(scaled_iv_plus_offset, R2); register_new_node(new_rc_cmp, c); _igvn.replace_input_of(rc_bol, 1, new_rc_cmp); } } -Node* PhaseIdealLoop::clamp(Node* R, Node* L, Node* H) { - Node* min = MaxNode::signed_min(R, H, TypeLong::LONG, _igvn); +Node* PhaseIdealLoop::clamp(Node* R, Node* L_clamp, Node* H_clamp) { + Node* min = MaxNode::signed_min(R, H_clamp, TypeLong::LONG, _igvn); set_subtree_ctrl(min, true); - Node* max = MaxNode::signed_max(L, min, TypeLong::LONG, _igvn); + Node* max = MaxNode::signed_max(L_clamp, min, TypeLong::LONG, _igvn); set_subtree_ctrl(max, true); return max; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/loopnode.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/loopnode.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/loopnode.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/loopnode.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -1386,12 +1386,12 @@ void do_unroll( IdealLoopTree *loop, Node_List &old_new, bool adjust_min_trip ); // Return true if exp is a constant times an induction var - bool is_scaled_iv(Node* exp, Node* iv, BasicType bt, jlong* p_scale, bool* p_short_scale, int depth = 0); + bool is_scaled_iv(Node* exp, Node* iv, BasicType bt, jlong* p_scale, int depth = 0); bool is_iv(Node* exp, Node* iv, BasicType bt); - // Return true if exp is a scaled induction var plus (or minus) constant - bool is_scaled_iv_plus_offset(Node* exp, Node* iv, BasicType bt, jlong* p_scale, Node** p_offset, bool* p_short_scale = nullptr, int depth = 0); + // Return true if exp is a scaled induction var plus (or minus) an offset + bool is_scaled_iv_plus_offset(Node* exp, Node* iv, BasicType bt, jlong* p_scale, Node** p_offset, int depth = 0); bool is_scaled_iv_plus_offset(Node* exp, Node* iv, int* p_scale, Node** p_offset) { jlong long_scale; if (is_scaled_iv_plus_offset(exp, iv, T_INT, &long_scale, p_offset)) { @@ -1404,10 +1404,10 @@ return false; } // Helper for finding more complex matches to is_scaled_iv_plus_offset. - bool is_scaled_iv_plus_extra_offset(Node* exp1, Node* offset2, Node* iv, + bool is_scaled_iv_plus_extra_offset(Node* exp1, Node* offset3, Node* iv, BasicType bt, jlong* p_scale, Node** p_offset, - bool* p_short_scale, int depth); + int depth); // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted IfTrueNode* create_new_if_for_predicate(const ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry, @@ -1790,7 +1790,7 @@ void try_sink_out_of_loop(Node* n); - Node* clamp(Node* R, Node* L, Node* H); + Node* clamp(Node* R, Node* L_clamp, Node* H_clamp); bool safe_for_if_replacement(const Node* dom) const; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/macro.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/macro.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/macro.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/macro.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -2484,6 +2484,7 @@ assert(n->Opcode() == Op_LoopLimit || n->Opcode() == Op_ModD || n->Opcode() == Op_ModF || + n->Opcode() == Op_PowD || n->is_OpaqueNotNull() || n->is_OpaqueInitializedAssertionPredicate() || n->Opcode() == Op_MaxL || @@ -2637,22 +2638,11 @@ default: switch (n->Opcode()) { case Op_ModD: - case Op_ModF: { - bool is_drem = n->Opcode() == Op_ModD; - CallNode* mod_macro = n->as_Call(); - CallNode* call = new CallLeafNode(mod_macro->tf(), - is_drem ? CAST_FROM_FN_PTR(address, SharedRuntime::drem) - : CAST_FROM_FN_PTR(address, SharedRuntime::frem), - is_drem ? "drem" : "frem", TypeRawPtr::BOTTOM); - call->init_req(TypeFunc::Control, mod_macro->in(TypeFunc::Control)); - call->init_req(TypeFunc::I_O, mod_macro->in(TypeFunc::I_O)); - call->init_req(TypeFunc::Memory, mod_macro->in(TypeFunc::Memory)); - call->init_req(TypeFunc::ReturnAdr, mod_macro->in(TypeFunc::ReturnAdr)); - call->init_req(TypeFunc::FramePtr, mod_macro->in(TypeFunc::FramePtr)); - for (unsigned int i = 0; i < mod_macro->tf()->domain()->cnt() - TypeFunc::Parms; i++) { - call->init_req(TypeFunc::Parms + i, mod_macro->in(TypeFunc::Parms + i)); - } - _igvn.replace_node(mod_macro, call); + case Op_ModF: + case Op_PowD: { + CallLeafPureNode* call_macro = n->as_CallLeafPure(); + CallLeafPureNode* call = call_macro->inline_call_leaf_pure_node(); + _igvn.replace_node(call_macro, call); transform_later(call); break; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/matcher.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/matcher.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/matcher.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/matcher.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -2517,22 +2517,7 @@ n->del_req(3); break; } - case Op_LoadVectorGather: - if (is_subword_type(n->bottom_type()->is_vect()->element_basic_type())) { - Node* pair = new BinaryNode(n->in(MemNode::ValueIn), n->in(MemNode::ValueIn+1)); - n->set_req(MemNode::ValueIn, pair); - n->del_req(MemNode::ValueIn+1); - } - break; case Op_LoadVectorGatherMasked: - if (is_subword_type(n->bottom_type()->is_vect()->element_basic_type())) { - Node* pair2 = new BinaryNode(n->in(MemNode::ValueIn + 1), n->in(MemNode::ValueIn + 2)); - Node* pair1 = new BinaryNode(n->in(MemNode::ValueIn), pair2); - n->set_req(MemNode::ValueIn, pair1); - n->del_req(MemNode::ValueIn+2); - n->del_req(MemNode::ValueIn+1); - break; - } // fall-through case Op_StoreVectorScatter: { Node* pair = new BinaryNode(n->in(MemNode::ValueIn), n->in(MemNode::ValueIn+1)); n->set_req(MemNode::ValueIn, pair); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/memnode.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/memnode.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/memnode.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/memnode.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1585,11 +1585,15 @@ intptr_t ignore = 0; Node* base = AddPNode::Ideal_base_and_offset(address, phase, ignore); + if (base == nullptr) { + return false; + } + if (base->is_CastPP()) { base = base->in(1); } - if (req() > 3 || base == nullptr || !base->is_Phi()) { + if (req() > 3 || !base->is_Phi()) { return false; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/multnode.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/multnode.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/multnode.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/multnode.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -120,6 +120,10 @@ if (bottom_type() == Type::MEMORY) { // in(0) might be a narrow MemBar; otherwise we will report TypePtr::BOTTOM Node* ctrl = in(0); + if (ctrl->Opcode() == Op_Tuple) { + // Jumping over Tuples: the i-th projection of a Tuple is the i-th input of the Tuple. + ctrl = ctrl->in(_con); + } if (ctrl == nullptr) return nullptr; // node is dead const TypePtr* adr_type = ctrl->adr_type(); #ifdef ASSERT @@ -163,6 +167,15 @@ assert(_con < t->is_tuple()->cnt(), "ProjNode::_con must be in range"); } +//------------------------------Identity--------------------------------------- +Node* ProjNode::Identity(PhaseGVN* phase) { + if (in(0) != nullptr && in(0)->Opcode() == Op_Tuple) { + // Jumping over Tuples: the i-th projection of a Tuple is the i-th input of the Tuple. + return in(0)->in(_con); + } + return this; +} + //------------------------------Value------------------------------------------ const Type* ProjNode::Value(PhaseGVN* phase) const { if (in(0) == nullptr) return Type::TOP; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/multnode.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/multnode.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/multnode.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/multnode.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -82,6 +82,7 @@ virtual const Type *bottom_type() const; virtual const TypePtr *adr_type() const; virtual bool pinned() const; + virtual Node* Identity(PhaseGVN* phase); virtual const Type* Value(PhaseGVN* phase) const; virtual uint ideal_reg() const; virtual const RegMask &out_RegMask() const; @@ -105,4 +106,49 @@ ProjNode* other_if_proj() const; }; +/* Tuples are used to avoid manual graph surgery. When a node with Proj outputs (such as a call) + * must be removed and its ouputs replaced by its input, or some other value, we can make its + * ::Ideal return a tuple of what we want for each output: the ::Identity of output Proj will + * take care to jump over the Tuple and directly pick up the right input of the Tuple. + * + * For instance, if a function call is proven to have no side effect and return the constant 0, + * we can replace it with the 6-tuple: + * (control input, IO input, memory input, frame ptr input, return addr input, Con:0) + * all the output projections will pick up the input of the now gone call, except for the result + * projection that is replaced by 0. + * + * Using TupleNode avoid manual graph surgery and leave that to our expert surgeon: IGVN. + * Since the user of a Tuple are expected to be Proj, when creating a tuple during idealization, + * the output Proj should be enqueued for IGVN immediately after, and the tuple should not survive + * after the current IGVN. + */ +class TupleNode : public MultiNode { + const TypeTuple* _tf; + + template + static void make_helper(TupleNode* tn, uint i, Node* node, NN... nn) { + tn->set_req(i, node); + make_helper(tn, i + 1, nn...); + } + + static void make_helper(TupleNode*, uint) {} + +public: + TupleNode(const TypeTuple* tf) : MultiNode(tf->cnt()), _tf(tf) {} + + int Opcode() const override; + const Type* bottom_type() const override { return _tf; } + + /* Give as many `Node*` as you want in the `nn` pack: + * TupleNode::make(tf, input1) + * TupleNode::make(tf, input1, input2, input3, input4) + */ + template + static TupleNode* make(const TypeTuple* tf, NN... nn) { + TupleNode* tn = new TupleNode(tf); + make_helper(tn, 0, nn...); + return tn; + } +}; + #endif // SHARE_OPTO_MULTNODE_HPP diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/node.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/node.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/node.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/node.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -991,18 +991,22 @@ //---------------------------uncast_helper------------------------------------- Node* Node::uncast_helper(const Node* p, bool keep_deps) { #ifdef ASSERT + // If we end up traversing more nodes than we actually have, + // it is definitely an infinite loop. + uint max_depth = Compile::current()->unique(); uint depth_count = 0; const Node* orig_p = p; #endif while (true) { #ifdef ASSERT - if (depth_count >= K) { + if (depth_count++ >= max_depth) { orig_p->dump(4); - if (p != orig_p) + if (p != orig_p) { p->dump(1); + } + fatal("infinite loop in Node::uncast_helper"); } - assert(depth_count++ < K, "infinite loop in Node::uncast_helper"); #endif if (p == nullptr || p->req() != 2) { break; @@ -1216,6 +1220,9 @@ } else if ((is_IfFalse() || is_IfTrue()) && n->is_If()) { // See IfNode::fold_compares return true; + } else if (n->Opcode() == Op_XorV || n->Opcode() == Op_XorVMask) { + // Condition for XorVMask(VectorMaskCmp(x,y,cond), MaskAll(true)) ==> VectorMaskCmp(x,y,ncond) + return true; } else { return false; } @@ -2946,23 +2953,13 @@ bool Node::is_div_or_mod(BasicType bt) const { return Opcode() == Op_Div(bt) || Opcode() == Op_Mod(bt) || Opcode() == Op_UDiv(bt) || Opcode() == Op_UMod(bt); } -bool Node::is_pure_function() const { - switch (Opcode()) { - case Op_ModD: - case Op_ModF: - return true; - default: - return false; - } -} - // `maybe_pure_function` is assumed to be the input of `this`. This is a bit redundant, // but we already have and need maybe_pure_function in all the call sites, so // it makes it obvious that the `maybe_pure_function` is the same node as in the caller, // while it takes more thinking to realize that a locally computed in(0) must be equal to // the local in the caller. bool Node::is_data_proj_of_pure_function(const Node* maybe_pure_function) const { - return Opcode() == Op_Proj && as_Proj()->_con == TypeFunc::Parms && maybe_pure_function->is_pure_function(); + return Opcode() == Op_Proj && as_Proj()->_con == TypeFunc::Parms && maybe_pure_function->is_CallLeafPure(); } //============================================================================= diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/node.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/node.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/node.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/node.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -54,6 +54,7 @@ class CallJavaNode; class CallLeafNode; class CallLeafNoFPNode; +class CallLeafPureNode; class CallNode; class CallRuntimeNode; class CallStaticJavaNode; @@ -673,6 +674,7 @@ DEFINE_CLASS_ID(CallRuntime, Call, 1) DEFINE_CLASS_ID(CallLeaf, CallRuntime, 0) DEFINE_CLASS_ID(CallLeafNoFP, CallLeaf, 0) + DEFINE_CLASS_ID(CallLeafPure, CallLeaf, 1) DEFINE_CLASS_ID(Allocate, Call, 2) DEFINE_CLASS_ID(AllocateArray, Allocate, 0) DEFINE_CLASS_ID(AbstractLock, Call, 3) @@ -907,6 +909,7 @@ DEFINE_CLASS_QUERY(CallJava) DEFINE_CLASS_QUERY(CallLeaf) DEFINE_CLASS_QUERY(CallLeafNoFP) + DEFINE_CLASS_QUERY(CallLeafPure) DEFINE_CLASS_QUERY(CallRuntime) DEFINE_CLASS_QUERY(CallStaticJava) DEFINE_CLASS_QUERY(Catch) @@ -1289,8 +1292,6 @@ bool is_div_or_mod(BasicType bt) const; - bool is_pure_function() const; - bool is_data_proj_of_pure_function(const Node* maybe_pure_function) const; //----------------- Printing, etc diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/parse2.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/parse2.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/parse2.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/parse2.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1097,11 +1097,11 @@ Node* Parse::floating_point_mod(Node* a, Node* b, BasicType type) { assert(type == BasicType::T_FLOAT || type == BasicType::T_DOUBLE, "only float and double are floating points"); - CallNode* mod = type == BasicType::T_DOUBLE ? static_cast(new ModDNode(C, a, b)) : new ModFNode(C, a, b); + CallLeafPureNode* mod = type == BasicType::T_DOUBLE ? static_cast(new ModDNode(C, a, b)) : new ModFNode(C, a, b); - Node* prev_mem = set_predefined_input_for_runtime_call(mod); - mod = _gvn.transform(mod)->as_Call(); - set_predefined_output_for_runtime_call(mod, prev_mem, TypeRawPtr::BOTTOM); + set_predefined_input_for_runtime_call(mod); + mod = _gvn.transform(mod)->as_CallLeafPure(); + set_predefined_output_for_runtime_call(mod); Node* result = _gvn.transform(new ProjNode(mod, TypeFunc::Parms + 0)); record_for_igvn(mod); return result; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/split_if.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/split_if.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/split_if.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/split_if.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -578,7 +578,7 @@ // Found an If getting its condition-code input from a Phi in the same block. // Split thru the Region. void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, RegionNode** new_true_region) { - + iff->as_If()->mark_projections_unsafe_for_fold_compare(); C->set_major_progress(); RegionNode *region = iff->in(0)->as_Region(); Node *region_dom = idom(region); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/subnode.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/subnode.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/subnode.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/subnode.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -328,7 +328,9 @@ // a simple char array where each element is the ASCII version of a 'mask' // enum from above. mask commute( ) const { return mask("032147658"[_test]-'0'); } - mask negate( ) const { return mask(_test^4); } + mask negate( ) const { return negate_mask(_test); } + // Return the negative mask for the given mask, for both signed and unsigned comparison. + static mask negate_mask(mask btm) { return mask(btm ^ 4); } bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le || _test == BoolTest::overflow); } bool is_less( ) const { return _test == BoolTest::lt || _test == BoolTest::le; } bool is_greater( ) const { return _test == BoolTest::gt || _test == BoolTest::ge; } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/vectorIntrinsics.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/vectorIntrinsics.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/vectorIntrinsics.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/vectorIntrinsics.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -266,7 +266,6 @@ is_supported = Matcher::match_rule_supported_vector_masked(sopc, num_elem, type); } } - is_supported |= Matcher::supports_vector_predicate_op_emulation(sopc, num_elem, type); if (!is_supported) { non_product_log_if_needed("Rejected vector mask predicate using (%s,%s,%d) because architecture does not support it", @@ -1265,8 +1264,8 @@ } // Check whether the predicated gather/scatter node is supported by architecture. - VectorMaskUseType mask = (VectorMaskUseType) (VecMaskUseLoad | VecMaskUsePred); - if (!arch_supports_vector(is_scatter ? Op_StoreVectorScatterMasked : Op_LoadVectorGatherMasked, num_elem, elem_bt, mask)) { + if (!arch_supports_vector(is_scatter ? Op_StoreVectorScatterMasked : Op_LoadVectorGatherMasked, num_elem, elem_bt, + (VectorMaskUseType) (VecMaskUseLoad | VecMaskUsePred))) { log_if_needed(" ** not supported: arity=%d op=%s vlen=%d etype=%s is_masked_op=1", is_scatter, is_scatter ? "scatterMasked" : "gatherMasked", num_elem, type2name(elem_bt)); @@ -1283,8 +1282,7 @@ } // Check that the vector holding indices is supported by architecture - // For sub-word gathers expander receive index array. - if (!is_subword_type(elem_bt) && !arch_supports_vector(Op_LoadVector, num_elem, T_INT, VecMaskNotUsed)) { + if (!arch_supports_vector(Op_LoadVector, num_elem, T_INT, VecMaskNotUsed)) { log_if_needed(" ** not supported: arity=%d op=%s/loadindex vlen=%d etype=int is_masked_op=%d", is_scatter, is_scatter ? "scatter" : "gather", num_elem, is_masked_op ? 1 : 0); @@ -1322,15 +1320,12 @@ return false; } - Node* index_vect = nullptr; const TypeInstPtr* vbox_idx_type = TypeInstPtr::make_exact(TypePtr::NotNull, vbox_idx_klass); - if (!is_subword_type(elem_bt)) { - index_vect = unbox_vector(argument(8), vbox_idx_type, T_INT, num_elem); - if (index_vect == nullptr) { - set_map(old_map); - set_sp(old_sp); - return false; - } + Node* index_vect = unbox_vector(argument(8), vbox_idx_type, T_INT, num_elem); + if (index_vect == nullptr) { + set_map(old_map); + set_sp(old_sp); + return false; } Node* mask = nullptr; @@ -1367,23 +1362,10 @@ set_memory(vstore, addr_type); } else { Node* vload = nullptr; - Node* index = argument(11); - Node* indexMap = argument(12); - Node* indexM = argument(13); if (mask != nullptr) { - if (is_subword_type(elem_bt)) { - Node* index_arr_base = array_element_address(indexMap, indexM, T_INT); - vload = gvn().transform(new LoadVectorGatherMaskedNode(control(), memory(addr), addr, addr_type, vector_type, index_arr_base, mask, index)); - } else { - vload = gvn().transform(new LoadVectorGatherMaskedNode(control(), memory(addr), addr, addr_type, vector_type, index_vect, mask)); - } + vload = gvn().transform(new LoadVectorGatherMaskedNode(control(), memory(addr), addr, addr_type, vector_type, index_vect, mask)); } else { - if (is_subword_type(elem_bt)) { - Node* index_arr_base = array_element_address(indexMap, indexM, T_INT); - vload = gvn().transform(new LoadVectorGatherNode(control(), memory(addr), addr, addr_type, vector_type, index_arr_base, index)); - } else { - vload = gvn().transform(new LoadVectorGatherNode(control(), memory(addr), addr, addr_type, vector_type, index_vect)); - } + vload = gvn().transform(new LoadVectorGatherNode(control(), memory(addr), addr, addr_type, vector_type, index_vect)); } Node* box = box_vector(vload, vbox_type, elem_bt, num_elem); set_result(box); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/vectornode.cpp openjdk-25-25.0.5+8/src/hotspot/share/opto/vectornode.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/vectornode.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/vectornode.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -2163,6 +2163,99 @@ return redundant_logical_identity(this); } +// Returns whether (XorV (VectorMaskCmp) -1) can be optimized by negating the +// comparison operation. +bool VectorMaskCmpNode::predicate_can_be_negated() { + switch (_predicate) { + case BoolTest::eq: + case BoolTest::ne: + // eq and ne also apply to floating-point special values like NaN and infinities. + return true; + case BoolTest::le: + case BoolTest::ge: + case BoolTest::lt: + case BoolTest::gt: + case BoolTest::ule: + case BoolTest::uge: + case BoolTest::ult: + case BoolTest::ugt: { + BasicType bt = vect_type()->element_basic_type(); + // For float and double, we don't know if either comparison operand is a + // NaN, NaN {le|ge|lt|gt} anything is false, resulting in inconsistent + // results before and after negation. + return is_integral_type(bt); + } + default: + return false; + } +} + +// This function transforms the following patterns: +// +// For integer types: +// (XorV (VectorMaskCmp src1 src2 cond) (Replicate -1)) +// => (VectorMaskCmp src1 src2 ncond) +// (XorVMask (VectorMaskCmp src1 src2 cond) (MaskAll m1)) +// => (VectorMaskCmp src1 src2 ncond) +// (XorV (VectorMaskCast (VectorMaskCmp src1 src2 cond)) (Replicate -1)) +// => (VectorMaskCast (VectorMaskCmp src1 src2 ncond)) +// (XorVMask (VectorMaskCast (VectorMaskCmp src1 src2 cond)) (MaskAll m1)) +// => (VectorMaskCast (VectorMaskCmp src1 src2 ncond)) +// cond can be eq, ne, le, ge, lt, gt, ule, uge, ult and ugt. +// ncond is the negative comparison of cond. +// +// For float and double types: +// (XorV (VectorMaskCast (VectorMaskCmp src1 src2 cond)) (Replicate -1)) +// => (VectorMaskCast (VectorMaskCmp src1 src2 ncond)) +// (XorVMask (VectorMaskCast (VectorMaskCmp src1 src2 cond)) (MaskAll m1)) +// => (VectorMaskCast (VectorMaskCmp src1 src2 ncond)) +// cond can be eq or ne. +Node* XorVNode::Ideal_XorV_VectorMaskCmp(PhaseGVN* phase, bool can_reshape) { + Node* in1 = in(1); + Node* in2 = in(2); + // Transformations for predicated vectors are not supported for now. + if (is_predicated_vector() || + in1->is_predicated_vector() || + in2->is_predicated_vector()) { + return nullptr; + } + + // XorV/XorVMask is commutative, swap VectorMaskCmp/VectorMaskCast to in1. + if (VectorNode::is_all_ones_vector(in1)) { + swap(in1, in2); + } + + bool with_vector_mask_cast = false; + // Required conditions: + // 1. VectorMaskCast and VectorMaskCmp should only have a single use, + // otherwise the optimization may be unprofitable. + // 2. The predicate of VectorMaskCmp should be negatable. + // 3. The second input should be an all true vector mask. + if (in1->Opcode() == Op_VectorMaskCast) { + if (in1->outcnt() != 1) { + return nullptr; + } + with_vector_mask_cast = true; + in1 = in1->in(1); + } + if (in1->Opcode() != Op_VectorMaskCmp || + in1->outcnt() != 1 || + !in1->as_VectorMaskCmp()->predicate_can_be_negated() || + !VectorNode::is_all_ones_vector(in2)) { + return nullptr; + } + + BoolTest::mask neg_cond = BoolTest::negate_mask((in1->as_VectorMaskCmp())->get_predicate()); + ConINode* predicate_node = phase->intcon(neg_cond); + const TypeVect* vt = in1->as_Vector()->vect_type(); + Node* res = new VectorMaskCmpNode(neg_cond, in1->in(1), in1->in(2), predicate_node, vt); + if (with_vector_mask_cast) { + // We optimized out a VectorMaskCast, regenerate one to ensure type correctness. + res = new VectorMaskCastNode(phase->transform(res), vect_type()); + } + return res; +} + Node* XorVNode::Ideal(PhaseGVN* phase, bool can_reshape) { // (XorV src src) => (Replicate zero) // (XorVMask src src) => (MaskAll zero) @@ -2176,6 +2269,11 @@ Node* zero = phase->transform(phase->zerocon(bt)); return VectorNode::scalar2vector(zero, length(), bt, bottom_type()->isa_vectmask() != nullptr); } + + Node* res = Ideal_XorV_VectorMaskCmp(phase, can_reshape); + if (res != nullptr) { + return res; + } return VectorNode::Ideal(phase, can_reshape); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/opto/vectornode.hpp openjdk-25-25.0.5+8/src/hotspot/share/opto/vectornode.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/opto/vectornode.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/opto/vectornode.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -1012,6 +1012,7 @@ XorVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1,in2,vt) {} virtual int Opcode() const; virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + Node* Ideal_XorV_VectorMaskCmp(PhaseGVN* phase, bool can_reshape); }; //------------------------------XorReductionVNode-------------------------------------- @@ -1117,26 +1118,16 @@ // Load Vector from memory via index map class LoadVectorGatherNode : public LoadVectorNode { public: - LoadVectorGatherNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt, Node* indices, Node* offset = nullptr) + LoadVectorGatherNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt, Node* indices) : LoadVectorNode(c, mem, adr, at, vt) { init_class_id(Class_LoadVectorGather); + assert(indices->bottom_type()->is_vect(), "indices must be in vector"); add_req(indices); - DEBUG_ONLY(bool is_subword = is_subword_type(vt->element_basic_type())); - assert(is_subword || indices->bottom_type()->is_vect(), "indices must be in vector"); - assert(is_subword || !offset, ""); - assert(req() == MemNode::ValueIn + 1, "match_edge expects that index input is in MemNode::ValueIn"); - if (offset) { - add_req(offset); - } + assert(req() == MemNode::ValueIn + 1, "match_edge expects that last input is in MemNode::ValueIn"); } virtual int Opcode() const; - virtual uint match_edge(uint idx) const { - return idx == MemNode::Address || - idx == MemNode::ValueIn || - ((is_subword_type(vect_type()->element_basic_type())) && - idx == MemNode::ValueIn + 1); - } + virtual uint match_edge(uint idx) const { return idx == MemNode::Address || idx == MemNode::ValueIn; } virtual int store_Opcode() const { // Ensure it is different from any store opcode to avoid folding when indices are used return -1; @@ -1254,23 +1245,20 @@ // Load Vector from memory via index map under the influence of a predicate register(mask). class LoadVectorGatherMaskedNode : public LoadVectorNode { public: - LoadVectorGatherMaskedNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt, Node* indices, Node* mask, Node* offset = nullptr) + LoadVectorGatherMaskedNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt, Node* indices, Node* mask) : LoadVectorNode(c, mem, adr, at, vt) { init_class_id(Class_LoadVectorGatherMasked); + assert(indices->bottom_type()->is_vect(), "indices must be in vector"); + assert(mask->bottom_type()->isa_vectmask(), "sanity"); add_req(indices); add_req(mask); assert(req() == MemNode::ValueIn + 2, "match_edge expects that last input is in MemNode::ValueIn+1"); - if (is_subword_type(vt->element_basic_type())) { - add_req(offset); - } } virtual int Opcode() const; virtual uint match_edge(uint idx) const { return idx == MemNode::Address || idx == MemNode::ValueIn || - idx == MemNode::ValueIn + 1 || - (is_subword_type(vect_type()->is_vect()->element_basic_type()) && - idx == MemNode::ValueIn + 2); } + idx == MemNode::ValueIn + 1; } virtual int store_Opcode() const { // Ensure it is different from any store opcode to avoid folding when indices and mask are used return -1; @@ -1684,6 +1672,7 @@ virtual bool cmp( const Node &n ) const { return VectorNode::cmp(n) && _predicate == ((VectorMaskCmpNode&)n)._predicate; } + bool predicate_can_be_negated(); BoolTest::mask get_predicate() { return _predicate; } #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/prims/jvm.cpp openjdk-25-25.0.5+8/src/hotspot/share/prims/jvm.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/prims/jvm.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/prims/jvm.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -3053,9 +3053,17 @@ } JVM_END +JVM_ENTRY(jobject, JVM_ReferenceGet(JNIEnv* env, jobject ref)) + oop ref_oop = JNIHandles::resolve_non_null(ref); + // PhantomReference has its own implementation of get(). + assert(!java_lang_ref_Reference::is_phantom(ref_oop), "precondition"); + oop referent = java_lang_ref_Reference::weak_referent(ref_oop); + return JNIHandles::make_local(THREAD, referent); +JVM_END + JVM_ENTRY(jboolean, JVM_ReferenceRefersTo(JNIEnv* env, jobject ref, jobject o)) oop ref_oop = JNIHandles::resolve_non_null(ref); - // PhantomReference has it's own implementation of refersTo(). + // PhantomReference has its own implementation of refersTo(). // See: JVM_PhantomReferenceRefersTo assert(!java_lang_ref_Reference::is_phantom(ref_oop), "precondition"); oop referent = java_lang_ref_Reference::weak_referent_no_keepalive(ref_oop); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp openjdk-25-25.0.5+8/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -25,6 +25,7 @@ #include "classfile/symbolTable.hpp" #include "interpreter/bytecodeStream.hpp" #include "memory/universe.hpp" +#include "oops/bsmAttribute.inline.hpp" #include "oops/constantPool.inline.hpp" #include "oops/fieldStreams.inline.hpp" #include "oops/instanceKlass.inline.hpp" @@ -389,29 +390,22 @@ // } bootstrap_methods[num_bootstrap_methods]; // } void JvmtiClassFileReconstituter::write_bootstrapmethod_attribute() { - Array* operands = cpool()->operands(); write_attribute_name_index("BootstrapMethods"); - int num_bootstrap_methods = ConstantPool::operand_array_length(operands); - - // calculate length of attribute - u4 length = sizeof(u2); // num_bootstrap_methods - for (int n = 0; n < num_bootstrap_methods; n++) { - u2 num_bootstrap_arguments = cpool()->operand_argument_count_at(n); - length += sizeof(u2); // bootstrap_method_ref - length += sizeof(u2); // num_bootstrap_arguments - length += (u4)sizeof(u2) * num_bootstrap_arguments; // bootstrap_arguments[num_bootstrap_arguments] - } + u4 length = sizeof(u2) + // Size of num_bootstrap_methods + // The rest of the data for the attribute is exactly the u2s in the data array. + sizeof(u2) * cpool()->bsm_entries().array_length(); write_u4(length); + int num_bootstrap_methods = cpool()->bsm_entries().number_of_entries(); // write attribute write_u2(checked_cast(num_bootstrap_methods)); for (int n = 0; n < num_bootstrap_methods; n++) { - u2 bootstrap_method_ref = cpool()->operand_bootstrap_method_ref_index_at(n); - u2 num_bootstrap_arguments = cpool()->operand_argument_count_at(n); - write_u2(bootstrap_method_ref); + BSMAttributeEntry* bsme = cpool()->bsm_attribute_entry(n); + u2 num_bootstrap_arguments = bsme->argument_count(); + write_u2(bsme->bootstrap_method_index()); write_u2(num_bootstrap_arguments); for (int arg = 0; arg < num_bootstrap_arguments; arg++) { - u2 bootstrap_argument = cpool()->operand_argument_index_at(n, arg); + u2 bootstrap_argument = bsme->argument(arg); write_u2(bootstrap_argument); } } @@ -798,7 +792,7 @@ if (type_anno != nullptr) { ++attr_count; // has RuntimeVisibleTypeAnnotations attribute } - if (cpool()->operands() != nullptr) { + if (!cpool()->bsm_entries().is_empty()) { ++attr_count; } if (ik()->nest_host_index() != 0) { @@ -843,7 +837,7 @@ if (ik()->record_components() != nullptr) { write_record_attribute(); } - if (cpool()->operands() != nullptr) { + if (!cpool()->bsm_entries().is_empty()) { write_bootstrapmethod_attribute(); } if (inner_classes_length > 0) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/prims/jvmtiRedefineClasses.cpp openjdk-25-25.0.5+8/src/hotspot/share/prims/jvmtiRedefineClasses.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/prims/jvmtiRedefineClasses.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/prims/jvmtiRedefineClasses.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -44,7 +44,8 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/annotations.hpp" -#include "oops/constantPool.hpp" +#include "oops/bsmAttribute.inline.hpp" +#include "oops/constantPool.inline.hpp" #include "oops/fieldStreams.inline.hpp" #include "oops/klass.inline.hpp" #include "oops/klassVtable.hpp" @@ -572,9 +573,9 @@ case JVM_CONSTANT_Dynamic: // fall through case JVM_CONSTANT_InvokeDynamic: { - // Index of the bootstrap specifier in the operands array + // Index of the bootstrap specifier in the BSM array int old_bs_i = scratch_cp->bootstrap_methods_attribute_index(scratch_i); - int new_bs_i = find_or_append_operand(scratch_cp, old_bs_i, merge_cp_p, + int new_bs_i = find_or_append_bsm_entry(scratch_cp, old_bs_i, merge_cp_p, merge_cp_length_p); // The bootstrap method NameAndType_info index int old_ref_i = scratch_cp->bootstrap_name_and_type_ref_index_at(scratch_i); @@ -590,10 +591,11 @@ ("Dynamic entry@%d name_and_type_index change: %d to %d", *merge_cp_length_p, old_ref_i, new_ref_i); } - if (scratch_cp->tag_at(scratch_i).is_dynamic_constant()) + if (scratch_cp->tag_at(scratch_i).is_dynamic_constant()) { (*merge_cp_p)->dynamic_constant_at_put(*merge_cp_length_p, new_bs_i, new_ref_i); - else + } else { (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, new_bs_i, new_ref_i); + } if (scratch_i != *merge_cp_length_p) { // The new entry in *merge_cp_p is at a different index than // the new entry in scratch_cp so we need to map the index values. @@ -659,101 +661,94 @@ } // end find_or_append_indirect_entry() -// Append a bootstrap specifier into the merge_cp operands that is semantically equal -// to the scratch_cp operands bootstrap specifier passed by the old_bs_i index. +// Append a bootstrap specifier into the merge_cp BSM entries that is semantically equal +// to the scratch_cp BSM entries' bootstrap specifier passed by the old_bs_i index. // Recursively append new merge_cp entries referenced by the new bootstrap specifier. -void VM_RedefineClasses::append_operand(const constantPoolHandle& scratch_cp, int old_bs_i, +int VM_RedefineClasses::append_bsm_entry(const constantPoolHandle& scratch_cp, const int old_bs_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p) { - u2 old_ref_i = scratch_cp->operand_bootstrap_method_ref_index_at(old_bs_i); + BSMAttributeEntry* old_bsme = scratch_cp->bsm_attribute_entry(old_bs_i); + u2 old_ref_i = old_bsme->bootstrap_method_index(); u2 new_ref_i = find_or_append_indirect_entry(scratch_cp, old_ref_i, merge_cp_p, merge_cp_length_p); if (new_ref_i != old_ref_i) { log_trace(redefine, class, constantpool) - ("operands entry@%d bootstrap method ref_index change: %d to %d", _operands_cur_length, old_ref_i, new_ref_i); + ("BSM attribute entry@%d bootstrap method ref_index change: %d to %d", _bsmae_iter.current_offset() - 1, old_ref_i, new_ref_i); } - Array* merge_ops = (*merge_cp_p)->operands(); - int new_bs_i = _operands_cur_length; - // We have _operands_cur_length == 0 when the merge_cp operands is empty yet. - // However, the operand_offset_at(0) was set in the extend_operands() call. - int new_base = (new_bs_i == 0) ? (*merge_cp_p)->operand_offset_at(0) - : (*merge_cp_p)->operand_next_offset_at(new_bs_i - 1); - u2 argc = scratch_cp->operand_argument_count_at(old_bs_i); - - ConstantPool::operand_offset_at_put(merge_ops, _operands_cur_length, new_base); - merge_ops->at_put(new_base++, new_ref_i); - merge_ops->at_put(new_base++, argc); - - for (int i = 0; i < argc; i++) { - u2 old_arg_ref_i = scratch_cp->operand_argument_index_at(old_bs_i, i); + const int new_bs_i = _bsmae_iter.current_offset(); + BSMAttributeEntry* new_bsme = + _bsmae_iter.reserve_new_entry(new_ref_i, old_bsme->argument_count()); + assert(new_bsme != nullptr, "must be"); + for (int i = 0; i < new_bsme->argument_count(); i++) { + u2 old_arg_ref_i = old_bsme->argument(i); u2 new_arg_ref_i = find_or_append_indirect_entry(scratch_cp, old_arg_ref_i, merge_cp_p, merge_cp_length_p); - merge_ops->at_put(new_base++, new_arg_ref_i); + new_bsme->set_argument(i, new_arg_ref_i); + if (new_arg_ref_i != old_arg_ref_i) { log_trace(redefine, class, constantpool) - ("operands entry@%d bootstrap method argument ref_index change: %d to %d", - _operands_cur_length, old_arg_ref_i, new_arg_ref_i); + ("BSM attribute entry@%d bootstrap method argument ref_index change: %d to %d", + _bsmae_iter.current_offset() - 1, old_arg_ref_i, new_arg_ref_i); } } - if (old_bs_i != _operands_cur_length) { - // The bootstrap specifier in *merge_cp_p is at a different index than - // that in scratch_cp so we need to map the index values. - map_operand_index(old_bs_i, new_bs_i); - } - _operands_cur_length++; -} // end append_operand() + // This is only for the logging + map_bsm_index(old_bs_i, new_bs_i); + return new_bs_i; +} // end append_bsm_entry() -int VM_RedefineClasses::find_or_append_operand(const constantPoolHandle& scratch_cp, +int VM_RedefineClasses::find_or_append_bsm_entry(const constantPoolHandle& scratch_cp, int old_bs_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p) { + const int max_offset_in_merge = _bsmae_iter.current_offset(); int new_bs_i = old_bs_i; // bootstrap specifier index - bool match = (old_bs_i < _operands_cur_length) && - scratch_cp->compare_operand_to(old_bs_i, *merge_cp_p, old_bs_i); + // Has the old_bs_i index been used already? Check if it's the same so we know + // whether or not a remapping is required. + bool match = (old_bs_i < max_offset_in_merge) && + scratch_cp->compare_bootstrap_entry_to(old_bs_i, *merge_cp_p, old_bs_i); if (!match) { // forward reference in *merge_cp_p or not a direct match - int found_i = scratch_cp->find_matching_operand(old_bs_i, *merge_cp_p, - _operands_cur_length); + int found_i = scratch_cp->find_matching_bsm_entry(old_bs_i, *merge_cp_p, + max_offset_in_merge); if (found_i != -1) { - guarantee(found_i != old_bs_i, "compare_operand_to() and find_matching_operand() disagree"); - // found a matching operand somewhere else in *merge_cp_p so just need a mapping + guarantee(found_i != old_bs_i, "compare_bootstrap_entry_to() and find_matching_bsm_entry() disagree"); + // found a matching BSM entry somewhere else in *merge_cp_p so just need a mapping new_bs_i = found_i; - map_operand_index(old_bs_i, found_i); + map_bsm_index(old_bs_i, found_i); } else { // no match found so we have to append this bootstrap specifier to *merge_cp_p - append_operand(scratch_cp, old_bs_i, merge_cp_p, merge_cp_length_p); - new_bs_i = _operands_cur_length - 1; + new_bs_i = append_bsm_entry(scratch_cp, old_bs_i, merge_cp_p, merge_cp_length_p); } } return new_bs_i; -} // end find_or_append_operand() +} // end find_or_append_bsm_entry() -void VM_RedefineClasses::finalize_operands_merge(const constantPoolHandle& merge_cp, TRAPS) { - if (merge_cp->operands() == nullptr) { +void VM_RedefineClasses::finalize_bsm_entries_merge(const constantPoolHandle& merge_cp, TRAPS) { + if (merge_cp->bsm_entries().number_of_entries() == 0) { return; } - // Shrink the merge_cp operands - merge_cp->shrink_operands(_operands_cur_length, CHECK); + // Finished extending the BSMAEs + merge_cp->end_extension(_bsmae_iter, CHECK); if (log_is_enabled(Trace, redefine, class, constantpool)) { // don't want to loop unless we are tracing int count = 0; - for (int i = 1; i < _operands_index_map_p->length(); i++) { - int value = _operands_index_map_p->at(i); + for (int i = 1; i < _bsm_index_map_p->length(); i++) { + int value = _bsm_index_map_p->at(i); if (value != -1) { - log_trace(redefine, class, constantpool)("operands_index_map[%d]: old=%d new=%d", count, i, value); + log_trace(redefine, class, constantpool)("bsm_index_map[%d]: old=%d new=%d", count, i, value); count++; } } } // Clean-up - _operands_index_map_p = nullptr; - _operands_cur_length = 0; - _operands_index_map_count = 0; -} // end finalize_operands_merge() + _bsm_index_map_p = nullptr; + _bsm_index_map_count = 0; + _bsmae_iter = BSMAttributeEntries::InsertionIterator(); +} // end finalize_bsmentries_merge() // Symbol* comparator for qsort // The caller must have an active ResourceMark. @@ -1270,26 +1265,26 @@ // Find new bootstrap specifier index value for old bootstrap specifier index // value by searching the index map. Returns unused index (-1) if there is // no mapped value for the old bootstrap specifier index. -int VM_RedefineClasses::find_new_operand_index(int old_index) { - if (_operands_index_map_count == 0) { +int VM_RedefineClasses::find_new_bsm_index(int old_index) { + if (_bsm_index_map_count == 0) { // map is empty so nothing can be found return -1; } - if (old_index == -1 || old_index >= _operands_index_map_p->length()) { + if (old_index == -1 || old_index >= _bsm_index_map_p->length()) { // The old_index is out of range so it is not mapped. // This should not happen in regular constant pool merging use. return -1; } - int value = _operands_index_map_p->at(old_index); + int value = _bsm_index_map_p->at(old_index); if (value == -1) { // the old_index is not mapped return -1; } return value; -} // end find_new_operand_index() +} // end find_new_bsm_index() // The bug 6214132 caused the verification to fail. @@ -1560,22 +1555,15 @@ // Map old_index to new_index as needed. -void VM_RedefineClasses::map_operand_index(int old_index, int new_index) { - if (find_new_operand_index(old_index) != -1) { - // old_index is already mapped - return; - } - +void VM_RedefineClasses::map_bsm_index(int old_index, int new_index) { if (old_index == new_index) { // no mapping is needed return; } - - _operands_index_map_p->at_put(old_index, new_index); - _operands_index_map_count++; - + _bsm_index_map_p->at_put(old_index, new_index); + _bsm_index_map_count++; log_trace(redefine, class, constantpool)("mapped bootstrap specifier at index %d to %d", old_index, new_index); -} // end map_index() +} // end map_bsm_index() // Merge old_cp and scratch_cp and return the results of the merge via @@ -1639,8 +1627,8 @@ } } // end for each old_cp entry - ConstantPool::copy_operands(old_cp, merge_cp_p, CHECK_false); - merge_cp_p->extend_operands(scratch_cp, CHECK_false); + ConstantPool::copy_bsm_entries(old_cp, merge_cp_p, CHECK_false); + _bsmae_iter = merge_cp_p->start_extension(scratch_cp, CHECK_false); // We don't need to sanity check that *merge_cp_length_p is within // *merge_cp_p bounds since we have the minimum on-entry check above. @@ -1737,7 +1725,7 @@ ("after pass 1b: merge_cp_len=%d, scratch_i=%d, index_map_len=%d", merge_cp_length_p, scratch_i, _index_map_count); } - finalize_operands_merge(merge_cp_p, CHECK_false); + finalize_bsm_entries_merge(merge_cp_p, CHECK_false); return true; } // end merge_constant_pools() @@ -1807,12 +1795,11 @@ _index_map_count = 0; _index_map_p = new intArray(scratch_cp->length(), scratch_cp->length(), -1); - _operands_cur_length = ConstantPool::operand_array_length(old_cp->operands()); - _operands_index_map_count = 0; - int operands_index_map_len = ConstantPool::operand_array_length(scratch_cp->operands()); - _operands_index_map_p = new intArray(operands_index_map_len, operands_index_map_len, -1); + _bsm_index_map_count = 0; + int bsm_data_len = scratch_cp->bsm_entries().array_length(); + _bsm_index_map_p = new intArray(bsm_data_len, bsm_data_len, -1); - // reference to the cp holder is needed for copy_operands() + // reference to the cp holder is needed for reallocating the BSM attribute merge_cp->set_pool_holder(scratch_class); bool result = merge_constant_pools(old_cp, scratch_cp, merge_cp, merge_cp_length, THREAD); @@ -3496,7 +3483,7 @@ smaller_cp->set_version(version); // attach klass to new constant pool - // reference to the cp holder is needed for copy_operands() + // reference to the cp holder is needed for reallocating the BSM attribute smaller_cp->set_pool_holder(scratch_class); smaller_cp->copy_fields(scratch_cp()); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/prims/jvmtiRedefineClasses.hpp openjdk-25-25.0.5+8/src/hotspot/share/prims/jvmtiRedefineClasses.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/prims/jvmtiRedefineClasses.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/prims/jvmtiRedefineClasses.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -363,11 +363,16 @@ int _index_map_count; intArray * _index_map_p; - // _operands_index_map_count is just an optimization for knowing if - // _operands_index_map_p contains any entries. - int _operands_cur_length; - int _operands_index_map_count; - intArray * _operands_index_map_p; + // _bsm_index_map_count is just an optimization for knowing if + // _bsm_index_map_p contains any entries. + int _bsm_index_map_count; + intArray * _bsm_index_map_p; + + // After merge_constant_pools "Pass 0", the BSMAttribute entries of merge_cp_p will have been expanded to fit + // scratch_cp's BSMAttribute entries as well. + // However, the newly acquired space will not have been filled in yet. + // To append to this new space, the iterator is used. + BSMAttributeEntries::InsertionIterator _bsmae_iter; // ptr to _class_count scratch_classes InstanceKlass** _scratch_classes; @@ -429,17 +434,18 @@ // Support for constant pool merging (these routines are in alpha order): void append_entry(const constantPoolHandle& scratch_cp, int scratch_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p); - void append_operand(const constantPoolHandle& scratch_cp, int scratch_bootstrap_spec_index, + // Returns the index of the appended BSM + int append_bsm_entry(const constantPoolHandle& scratch_cp, int scratch_bootstrap_spec_index, constantPoolHandle *merge_cp_p, int *merge_cp_length_p); - void finalize_operands_merge(const constantPoolHandle& merge_cp, TRAPS); + void finalize_bsm_entries_merge(const constantPoolHandle& merge_cp, TRAPS); u2 find_or_append_indirect_entry(const constantPoolHandle& scratch_cp, int scratch_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p); - int find_or_append_operand(const constantPoolHandle& scratch_cp, int scratch_bootstrap_spec_index, + int find_or_append_bsm_entry(const constantPoolHandle& scratch_cp, int scratch_bootstrap_spec_index, constantPoolHandle *merge_cp_p, int *merge_cp_length_p); u2 find_new_index(int old_index); - int find_new_operand_index(int old_bootstrap_spec_index); + int find_new_bsm_index(int old_bootstrap_spec_index); void map_index(const constantPoolHandle& scratch_cp, int old_index, int new_index); - void map_operand_index(int old_bootstrap_spec_index, int new_bootstrap_spec_index); + void map_bsm_index(int old_bootstrap_spec_index, int new_bootstrap_spec_index); bool merge_constant_pools(const constantPoolHandle& old_cp, const constantPoolHandle& scratch_cp, constantPoolHandle& merge_cp_p, int& merge_cp_length_p, TRAPS); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/prims/upcallLinker.cpp openjdk-25-25.0.5+8/src/hotspot/share/prims/upcallLinker.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/prims/upcallLinker.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/prims/upcallLinker.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -130,7 +130,7 @@ JNIHandleBlock::release_block(context->new_handles, thread); } -void UpcallLinker::handle_uncaught_exception(oop exception) { +void UpcallLinker::handle_uncaught_exception(oopDesc* exception) { tty->print_cr("Uncaught exception:"); Handle exception_h(Thread::current(), exception); java_lang_Throwable::print_stack_trace(exception_h, tty); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/prims/upcallLinker.hpp openjdk-25-25.0.5+8/src/hotspot/share/prims/upcallLinker.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/prims/upcallLinker.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/prims/upcallLinker.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -44,7 +44,7 @@ bool needs_return_buffer, int ret_buf_size); // public for stubGenerator - static void handle_uncaught_exception(oop exception); + static void handle_uncaught_exception(oopDesc* exception); }; #endif // SHARE_VM_PRIMS_UPCALLLINKER_HPP diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/prims/whitebox.cpp openjdk-25-25.0.5+8/src/hotspot/share/prims/whitebox.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/prims/whitebox.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/prims/whitebox.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -509,8 +509,16 @@ return ConcurrentGCBreakpoints::run_to(c_name); WB_END -WB_ENTRY(jboolean, WB_HasExternalSymbolsStripped(JNIEnv* env, jobject o)) -#if defined(HAS_STRIPPED_DEBUGINFO) +WB_ENTRY(jboolean, WB_ShipDebugInfoFull(JNIEnv* env, jobject o)) +#if defined(SHIP_DEBUGINFO_FULL) + return true; +#else + return false; +#endif +WB_END + +WB_ENTRY(jboolean, WB_ShipDebugInfoPublic(JNIEnv* env, jobject o)) +#if defined(SHIP_DEBUGINFO_PUBLIC) return true; #else return false; @@ -2794,7 +2802,8 @@ {CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize}, {CC"getHeapSpaceAlignment", CC"()J", (void*)&WB_GetHeapSpaceAlignment}, {CC"getHeapAlignment", CC"()J", (void*)&WB_GetHeapAlignment}, - {CC"hasExternalSymbolsStripped", CC"()Z", (void*)&WB_HasExternalSymbolsStripped}, + {CC"shipsFullDebugInfo", CC"()Z", (void*)&WB_ShipDebugInfoFull}, + {CC"shipsPublicDebugInfo", CC"()Z", (void*)&WB_ShipDebugInfoPublic}, {CC"countAliveClasses0", CC"(Ljava/lang/String;)I", (void*)&WB_CountAliveClasses }, {CC"getSymbolRefcount", CC"(Ljava/lang/String;)I", (void*)&WB_GetSymbolRefcount }, {CC"parseCommandLine0", diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/runtime/cpuTimeCounters.cpp openjdk-25-25.0.5+8/src/hotspot/share/runtime/cpuTimeCounters.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/runtime/cpuTimeCounters.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/runtime/cpuTimeCounters.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -121,8 +121,5 @@ } void ThreadTotalCPUTimeClosure::do_thread(Thread* thread) { - // The default code path (fast_thread_cpu_time()) asserts that - // pthread_getcpuclockid() and clock_gettime() must return 0. Thus caller - // must ensure the thread exists and has not terminated. _total += os::thread_cpu_time(thread); } diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/runtime/os.hpp openjdk-25-25.0.5+8/src/hotspot/share/runtime/os.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/runtime/os.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/runtime/os.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -974,10 +974,7 @@ // The thread_cpu_time() and current_thread_cpu_time() are only // supported if is_thread_cpu_time_supported() returns true. - // Thread CPU Time - return the fast estimate on a platform - // On Linux - fast clock_gettime where available - user+sys - // - otherwise: very slow /proc fs - user+sys - // On Windows - GetThreadTimes - user+sys + // Thread CPU Time - return the fast estimate on a platform - user+sys static jlong current_thread_cpu_time(); static jlong thread_cpu_time(Thread* t); diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/runtime/safefetch.hpp openjdk-25-25.0.5+8/src/hotspot/share/runtime/safefetch.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/runtime/safefetch.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/runtime/safefetch.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -31,8 +31,8 @@ // Safefetch allows to load a value from a location that's not known // to be valid. If the load causes a fault, the error value is returned. -#ifdef _WIN32 - // Windows uses Structured Exception Handling +#if defined(_WIN32) && !defined(_M_ARM64) + // Windows x86_64 uses Structured Exception Handling #include "safefetch_windows.hpp" #elif defined(ZERO) || defined (_AIX) // These platforms implement safefetch via Posix sigsetjmp/longjmp. diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/runtime/threads.cpp openjdk-25-25.0.5+8/src/hotspot/share/runtime/threads.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/runtime/threads.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/runtime/threads.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1366,10 +1366,24 @@ char buf[32]; st->print_raw_cr(os::local_time_string(buf, sizeof(buf))); - st->print_cr("Full thread dump %s (%s %s):", + st->print_cr("Full thread dump %s (%s %s)", VM_Version::vm_name(), VM_Version::vm_release(), VM_Version::vm_info_string()); + JDK_Version::current().to_string(buf, sizeof(buf)); + const char* runtime_name = JDK_Version::runtime_name() != nullptr ? + JDK_Version::runtime_name() : ""; + const char* runtime_version = JDK_Version::runtime_version() != nullptr ? + JDK_Version::runtime_version() : ""; + const char* vendor_version = JDK_Version::runtime_vendor_version() != nullptr ? + JDK_Version::runtime_vendor_version() : ""; + const char* jdk_debug_level = VM_Version::printable_jdk_debug_level() != nullptr ? + VM_Version::printable_jdk_debug_level() : ""; + + st->print_cr(" JDK version: %s%s%s (%s) (%sbuild %s)", runtime_name, + (*vendor_version != '\0') ? " " : "", vendor_version, + buf, jdk_debug_level, runtime_version); + st->cr(); #if INCLUDE_SERVICES diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/runtime/vmStructs.cpp openjdk-25-25.0.5+8/src/hotspot/share/runtime/vmStructs.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/runtime/vmStructs.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/runtime/vmStructs.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -56,6 +56,7 @@ #include "oops/array.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" +#include "oops/bsmAttribute.hpp" #include "oops/constMethod.hpp" #include "oops/constantPool.hpp" #include "oops/cpCache.hpp" @@ -172,10 +173,12 @@ nonstatic_field(ArrayKlass, _dimension, int) \ volatile_nonstatic_field(ArrayKlass, _higher_dimension, ObjArrayKlass*) \ volatile_nonstatic_field(ArrayKlass, _lower_dimension, ArrayKlass*) \ + nonstatic_field(BSMAttributeEntries, _offsets, Array*) \ + nonstatic_field(BSMAttributeEntries, _bootstrap_methods, Array*) \ + nonstatic_field(ConstantPool, _bsm_entries, BSMAttributeEntries) \ nonstatic_field(ConstantPool, _tags, Array*) \ nonstatic_field(ConstantPool, _cache, ConstantPoolCache*) \ nonstatic_field(ConstantPool, _pool_holder, InstanceKlass*) \ - nonstatic_field(ConstantPool, _operands, Array*) \ nonstatic_field(ConstantPool, _resolved_klasses, Array*) \ nonstatic_field(ConstantPool, _length, int) \ nonstatic_field(ConstantPool, _minor_version, u2) \ @@ -743,6 +746,7 @@ unchecked_nonstatic_field(Array, _data, sizeof(int)) \ unchecked_nonstatic_field(Array, _data, sizeof(u1)) \ unchecked_nonstatic_field(Array, _data, sizeof(u2)) \ + unchecked_nonstatic_field(Array, _data, sizeof(u4)) \ unchecked_nonstatic_field(Array, _data, sizeof(Method*)) \ unchecked_nonstatic_field(Array, _data, sizeof(Klass*)) \ unchecked_nonstatic_field(Array, _data, sizeof(ResolvedFieldEntry)) \ @@ -974,6 +978,7 @@ declare_toplevel_type(volatile Metadata*) \ \ declare_toplevel_type(DataLayout) \ + declare_toplevel_type(BSMAttributeEntries) \ \ /********/ \ /* Oops */ \ @@ -1502,13 +1507,13 @@ \ declare_constant(Symbol::max_symbol_length) \ \ - /***********************************************/ \ - /* ConstantPool* layout enum for InvokeDynamic */ \ - /***********************************************/ \ - \ - declare_constant(ConstantPool::_indy_bsm_offset) \ - declare_constant(ConstantPool::_indy_argc_offset) \ - declare_constant(ConstantPool::_indy_argv_offset) \ + /******************************************************/ \ + /* BSMAttributeEntry* - layout enum for InvokeDynamic */ \ + /******************************************************/ \ + \ + declare_constant(BSMAttributeEntry::_bsmi_offset) \ + declare_constant(BSMAttributeEntry::_argc_offset) \ + declare_constant(BSMAttributeEntry::_argv_offset) \ \ /***************************************/ \ /* JavaThreadStatus enum */ \ diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/sanitizers/ub.hpp openjdk-25-25.0.5+8/src/hotspot/share/sanitizers/ub.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/sanitizers/ub.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/sanitizers/ub.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -33,12 +33,9 @@ // Useful if the function or method is known to do something special or even 'dangerous', for // example causing desired signals/crashes. #ifdef UNDEFINED_BEHAVIOR_SANITIZER -#if defined(__clang__) +#if defined(__clang__) || defined(__GNUC__) #define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined","float-divide-by-zero"))) #endif -#if defined(__GNUC__) && !defined(__clang__) -#define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined"))) -#endif #endif #ifndef ATTRIBUTE_NO_UBSAN diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/utilities/debug.cpp openjdk-25-25.0.5+8/src/hotspot/share/utilities/debug.cpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/utilities/debug.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/utilities/debug.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -322,20 +322,20 @@ int Command::level = 0; -extern "C" DEBUGEXPORT void blob(CodeBlob* cb) { +extern "C" NOINLINE void blob(CodeBlob* cb) { Command c("blob"); cb->print(); } -extern "C" DEBUGEXPORT void dump_vtable(address p) { +extern "C" NOINLINE void dump_vtable(address p) { Command c("dump_vtable"); Klass* k = (Klass*)p; k->vtable().print(); } -extern "C" DEBUGEXPORT void nm(intptr_t p) { +extern "C" NOINLINE void nm(intptr_t p) { // Actually we look through all CodeBlobs (the nm name has been kept for backwards compatibility) Command c("nm"); CodeBlob* cb = CodeCache::find_blob((address)p); @@ -347,7 +347,7 @@ } -extern "C" DEBUGEXPORT void disnm(intptr_t p) { +extern "C" NOINLINE void disnm(intptr_t p) { Command c("disnm"); CodeBlob* cb = CodeCache::find_blob((address) p); if (cb != nullptr) { @@ -362,7 +362,7 @@ } -extern "C" DEBUGEXPORT void printnm(intptr_t p) { +extern "C" NOINLINE void printnm(intptr_t p) { char buffer[256]; os::snprintf_checked(buffer, sizeof(buffer), "printnm: " INTPTR_FORMAT, p); Command c(buffer); @@ -376,13 +376,13 @@ } -extern "C" DEBUGEXPORT void universe() { +extern "C" NOINLINE void universe() { Command c("universe"); Universe::print_on(tty); } -extern "C" DEBUGEXPORT void verify() { +extern "C" NOINLINE void verify() { // try to run a verify on the entire system // note: this may not be safe if we're not at a safepoint; for debugging, // this manipulates the safepoint settings to avoid assertion failures @@ -399,7 +399,7 @@ } -extern "C" DEBUGEXPORT void pp(void* p) { +extern "C" NOINLINE void pp(void* p) { Command c("pp"); FlagSetting fl(DisplayVMOutput, true); if (p == nullptr) { @@ -423,10 +423,7 @@ } } - -extern "C" DEBUGEXPORT void findpc(intptr_t x); - -extern "C" DEBUGEXPORT void ps() { // print stack +extern "C" NOINLINE void ps() { // print stack if (Thread::current_or_null() == nullptr) return; Command c("ps"); @@ -455,7 +452,7 @@ } } -extern "C" DEBUGEXPORT void pfl() { +extern "C" NOINLINE void pfl() { // print frame layout Command c("pfl"); JavaThread* p = JavaThread::active(); @@ -467,7 +464,7 @@ } } -extern "C" DEBUGEXPORT void psf() { // print stack frames +extern "C" NOINLINE void psf() { // print stack frames { Command c("psf"); JavaThread* p = JavaThread::active(); @@ -481,19 +478,19 @@ } -extern "C" DEBUGEXPORT void threads() { +extern "C" NOINLINE void threads() { Command c("threads"); Threads::print(false, true); } -extern "C" DEBUGEXPORT void psd() { +extern "C" NOINLINE void psd() { Command c("psd"); SystemDictionary::print(); } -extern "C" DEBUGEXPORT void pss() { // print all stacks +extern "C" NOINLINE void pss() { // print all stacks if (Thread::current_or_null() == nullptr) return; Command c("pss"); Threads::print(true, PRODUCT_ONLY(false) NOT_PRODUCT(true)); @@ -501,7 +498,7 @@ // #ifndef PRODUCT -extern "C" DEBUGEXPORT void debug() { // to set things up for compiler debugging +extern "C" NOINLINE void debug() { // to set things up for compiler debugging Command c("debug"); NOT_PRODUCT(WizardMode = true;) PrintCompilation = true; @@ -510,7 +507,7 @@ } -extern "C" DEBUGEXPORT void ndebug() { // undo debug() +extern "C" NOINLINE void ndebug() { // undo debug() Command c("ndebug"); PrintCompilation = false; PrintInlining = PrintAssembly = false; @@ -518,35 +515,35 @@ } -extern "C" DEBUGEXPORT void flush() { +extern "C" NOINLINE void flush() { Command c("flush"); tty->flush(); } -extern "C" DEBUGEXPORT void events() { +extern "C" NOINLINE void events() { Command c("events"); Events::print(); } -extern "C" DEBUGEXPORT Method* findm(intptr_t pc) { +extern "C" NOINLINE Method* findm(intptr_t pc) { Command c("findm"); nmethod* nm = CodeCache::find_nmethod((address)pc); return (nm == nullptr) ? (Method*)nullptr : nm->method(); } -extern "C" DEBUGEXPORT nmethod* findnm(intptr_t addr) { +extern "C" NOINLINE nmethod* findnm(intptr_t addr) { Command c("findnm"); return CodeCache::find_nmethod((address)addr); } -extern "C" DEBUGEXPORT void find(intptr_t x) { +extern "C" NOINLINE void find(intptr_t x) { Command c("find"); os::print_location(tty, x, false); } -extern "C" DEBUGEXPORT void findpc(intptr_t x) { +extern "C" NOINLINE void findpc(intptr_t x) { Command c("findpc"); os::print_location(tty, x, true); } @@ -557,21 +554,20 @@ // call findclass("java/lang/Object", 0x3) -> find j.l.Object and disasm all of its methods // call findmethod("*ang/Object*", "wait", 0xff) -> detailed disasm of all "wait" methods in j.l.Object // call findmethod("*ang/Object*", "wait:(*J*)V", 0x1) -> list all "wait" methods in j.l.Object that have a long parameter -extern "C" DEBUGEXPORT void findclass(const char* class_name_pattern, int flags) { +extern "C" NOINLINE void findclass(const char* class_name_pattern, int flags) { Command c("findclass"); ClassPrinter::print_flags_help(tty); ClassPrinter::print_classes(class_name_pattern, flags, tty); } -extern "C" DEBUGEXPORT void findmethod(const char* class_name_pattern, - const char* method_pattern, int flags) { +extern "C" NOINLINE void findmethod(const char* class_name_pattern, const char* method_pattern, int flags) { Command c("findmethod"); ClassPrinter::print_flags_help(tty); ClassPrinter::print_methods(class_name_pattern, method_pattern, flags, tty); } // Need method pointer to find bcp -extern "C" DEBUGEXPORT void findbcp(intptr_t method, intptr_t bcp) { +extern "C" NOINLINE void findbcp(intptr_t method, intptr_t bcp) { Command c("findbcp"); Method* mh = (Method*)method; if (!mh->is_native()) { @@ -582,7 +578,7 @@ } // check and decode a single u5 value -extern "C" DEBUGEXPORT u4 u5decode(intptr_t addr) { +extern "C" NOINLINE u4 u5decode(intptr_t addr) { Command c("u5decode"); u1* arr = (u1*)addr; size_t off = 0, lim = 5; @@ -599,9 +595,7 @@ // there is no limit on the count of items printed; the // printing stops when an null is printed or at limit. // See documentation for UNSIGNED5::Reader::print(count). -extern "C" DEBUGEXPORT intptr_t u5p(intptr_t addr, - intptr_t limit, - int count) { +extern "C" NOINLINE intptr_t u5p(intptr_t addr, intptr_t limit, int count) { Command c("u5p"); u1* arr = (u1*)addr; if (limit && limit < addr) limit = addr; @@ -614,10 +608,10 @@ // int versions of all methods to avoid having to type type casts in the debugger -void pp(intptr_t p) { pp((void*)p); } -void pp(oop p) { pp((void*)p); } +NOINLINE void pp(intptr_t p) { pp((void*)p); } +NOINLINE void pp(oop p) { pp((void*)p); } -extern "C" DEBUGEXPORT void help() { +extern "C" NOINLINE void help() { Command c("help"); tty->print_cr("basic"); tty->print_cr(" pp(void* p) - try to make sense of p"); @@ -674,7 +668,7 @@ } #ifndef PRODUCT -extern "C" DEBUGEXPORT void pns(void* sp, void* fp, void* pc) { // print native stack +extern "C" NOINLINE void pns(void* sp, void* fp, void* pc) { // print native stack Command c("pns"); static char buf[O_BUFLEN]; // Call generic frame constructor (certain arguments may be ignored) @@ -692,7 +686,7 @@ // WARNING: Only intended for use when debugging. Do not leave calls to // pns2() in committed source (product or debug). // -extern "C" DEBUGEXPORT void pns2() { // print native stack +extern "C" NOINLINE void pns2() { // print native stack Command c("pns2"); static char buf[O_BUFLEN]; address lastpc = nullptr; @@ -702,6 +696,43 @@ } #endif +// just an exported helper; to avoid link time elimination of the referenced functions +extern "C" JNIEXPORT void JVM_debug_helpers_keeper(void* p1, void* p2, void* p3, intptr_t ip, oop oh, address adr) { + blob((CodeBlob*)p1); + dump_vtable(adr); + nm(ip); + disnm(ip); + printnm(ip); + universe(); + verify(); + pp(p1); + ps(); + pfl(); + psf(); + threads(); + psd(); + pss(); + debug(); + ndebug(); + flush(); + events(); + findm(ip); + findnm(ip); + find(ip); + findpc(ip); + findclass("", 0); + findmethod("", "", 0); + findbcp(ip, ip); + u5decode(ip); + u5p(ip, ip, 0); + pp(ip); + pp(oh); + help(); +#ifndef PRODUCT + pns(p1, p2, p3); + pns2(); +#endif +} // Returns true iff the address p is readable and *(intptr_t*)p != errvalue extern "C" bool dbg_is_safe(const void* p, intptr_t errvalue) { diff -Nru openjdk-25-25.0.4.1+1/src/hotspot/share/utilities/ostream.hpp openjdk-25-25.0.5+8/src/hotspot/share/utilities/ostream.hpp --- openjdk-25-25.0.4.1+1/src/hotspot/share/utilities/ostream.hpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/hotspot/share/utilities/ostream.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -182,7 +182,7 @@ NONCOPYABLE(StreamIndentor); public: - StreamIndentor(outputStream* os, int indentation) : + StreamIndentor(outputStream* os, int indentation = 2) : _stream(os), _indentation(indentation), _old_autoindent(_stream->set_autoindent(true)) { diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -1603,8 +1603,9 @@ NIO_ACCESS.acquireSession(dst); try { Unsafe.getUnsafe().setMemory( - NIO_ACCESS.getBufferAddress(dst), - len + dst.position(), (byte) 0); + NIO_ACCESS.getBufferAddress(dst) + + dst.position(), + len, (byte) 0); } finally { NIO_ACCESS.releaseSession(dst); } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -527,6 +527,8 @@ } catch (DigestException e) { // This should never happen. throw new RuntimeException(e); + } finally { + mlKemH.reset(); } // The 2nd 32-byte `z` is copied into decapsKey System.arraycopy(kem_d_z, 32, decapsKey, @@ -562,7 +564,6 @@ var randomCoins = Arrays.copyOfRange(kHatAndRandomCoins, 32, 64); var cipherText = kPkeEncrypt(new K_PKE_EncryptionKey(encapsulationKey.keyBytes), randomMessage, randomCoins); - Arrays.fill(randomCoins, (byte) 0); byte[] sharedSecret = Arrays.copyOfRange(kHatAndRandomCoins, 0, 32); Arrays.fill(kHatAndRandomCoins, (byte) 0); @@ -613,6 +614,7 @@ var fakeResult = mlKemJ.digest(); var computedCipherText = kPkeEncrypt( new K_PKE_EncryptionKey(encapsKeyBytes), mCandidate, coins); + Arrays.fill(mCandidate, (byte)0); // The rest of this method implements the following in constant time // @@ -648,9 +650,11 @@ MessageDigest mlKemG; SHAKE256 mlKemJ; + int cbdInputLen = 64 * mlKem_eta1; + byte[] cbdInput = new byte[cbdInputLen]; try { mlKemG = MessageDigest.getInstance(HASH_G_NAME); - mlKemJ = new SHAKE256(64 * mlKem_eta1); + mlKemJ = new SHAKE256(cbdInputLen); } catch (NoSuchAlgorithmException e) { // This should never happen. throw new RuntimeException(e); @@ -671,22 +675,26 @@ int keyGenN = 0; byte[] prfSeed = new byte[sigma.length + 1]; System.arraycopy(sigma, 0, prfSeed, 0, sigma.length); - byte[] cbdInput; short[][] keyGenS = new short[mlKem_k][]; short[][] keyGenE = new short[mlKem_k][]; - for (int i = 0; i < mlKem_k; i++) { - prfSeed[sigma.length] = (byte) (keyGenN++); - mlKemJ.update(prfSeed); - cbdInput = mlKemJ.digest(); - keyGenS[i] = centeredBinomialDistribution(mlKem_eta1, cbdInput); - } - for (int i = 0; i < mlKem_k; i++) { - prfSeed[sigma.length] = (byte) (keyGenN++); - mlKemJ.update(prfSeed); - cbdInput = mlKemJ.digest(); - keyGenE[i] = centeredBinomialDistribution(mlKem_eta1, cbdInput); + try { + for (int i = 0; i < mlKem_k; i++) { + prfSeed[sigma.length] = (byte) (keyGenN++); + mlKemJ.update(prfSeed); + mlKemJ.digest(cbdInput, 0, cbdInputLen); + keyGenS[i] = centeredBinomialDistribution(mlKem_eta1, cbdInput); + } + for (int i = 0; i < mlKem_k; i++) { + prfSeed[sigma.length] = (byte) (keyGenN++); + mlKemJ.update(prfSeed); + mlKemJ.digest(cbdInput, 0, cbdInputLen); + keyGenE[i] = centeredBinomialDistribution(mlKem_eta1, cbdInput); + } + } catch (DigestException e) { + throw new ProviderException("Internal error", e); } Arrays.fill(sigma, (byte)0); + Arrays.fill(cbdInput, (byte)0); short[][] keyGenSHat = mlKemVectorNTT(keyGenS); mlKemVectorReduce(keyGenSHat); @@ -700,7 +708,6 @@ for (int i = 0; i < mlKem_k; i++) { encodePoly12(keyGenTHat[i], pkEncoded, i * ((ML_KEM_N * 12) / 8)); encodePoly12(keyGenSHat[i], skEncoded, i * ((ML_KEM_N * 12) / 8)); - Arrays.fill(keyGenEHat[i], (short) 0); Arrays.fill(keyGenSHat[i], (short) 0); } System.arraycopy(rho, 0, @@ -723,39 +730,61 @@ var encryptA = generateA(rho, true); short[][] encryptR = new short[mlKem_k][]; short[][] encryptE1 = new short[mlKem_k][]; + short[] encryptE2; int encryptN = 0; byte[] prfSeed = new byte[sigma.length + 1]; System.arraycopy(sigma, 0, prfSeed, 0, sigma.length); + Arrays.fill(sigma, (byte)0); - var kPkePRFeta1 = new SHAKE256(64 * mlKem_eta1); - var kPkePRFeta2 = new SHAKE256(64 * mlKem_eta2); - for (int i = 0; i < mlKem_k; i++) { - prfSeed[sigma.length] = (byte) (encryptN++); - kPkePRFeta1.update(prfSeed); - byte[] cbdInput = kPkePRFeta1.digest(); - encryptR[i] = centeredBinomialDistribution(mlKem_eta1, cbdInput); - } - for (int i = 0; i < mlKem_k; i++) { - prfSeed[sigma.length] = (byte) (encryptN++); + int cbdInput1Len = 64 * mlKem_eta1; + var kPkePRFeta1 = new SHAKE256(cbdInput1Len); + byte[] cbdInput1 = new byte[cbdInput1Len]; + int cbdInput2Len = 64 * mlKem_eta2; + var kPkePRFeta2 = new SHAKE256(cbdInput2Len); + byte[] cbdInput2 = new byte[cbdInput2Len]; + try { + for (int i = 0; i < mlKem_k; i++) { + prfSeed[sigma.length] = (byte) (encryptN++); + kPkePRFeta1.update(prfSeed); + kPkePRFeta1.digest(cbdInput1, 0, cbdInput1Len); + encryptR[i] = centeredBinomialDistribution(mlKem_eta1, cbdInput1); + } + for (int i = 0; i < mlKem_k; i++) { + prfSeed[sigma.length] = (byte) (encryptN++); + kPkePRFeta2.update(prfSeed); + kPkePRFeta2.digest(cbdInput2, 0, cbdInput2Len); + encryptE1[i] = centeredBinomialDistribution(mlKem_eta2, cbdInput2); + } + prfSeed[sigma.length] = (byte) encryptN; kPkePRFeta2.update(prfSeed); - byte[] cbdInput = kPkePRFeta2.digest(); - encryptE1[i] = centeredBinomialDistribution(mlKem_eta2, cbdInput); + kPkePRFeta2.digest(cbdInput2, 0, cbdInput2Len); + encryptE2 = centeredBinomialDistribution(mlKem_eta2, cbdInput2); + } catch (DigestException e) { + throw new ProviderException("Internal error", e); + } finally { + kPkePRFeta1.reset(); + kPkePRFeta2.reset(); + Arrays.fill(prfSeed, (byte)0); + Arrays.fill(cbdInput1, (byte)0); + Arrays.fill(cbdInput2, (byte)0); } - prfSeed[sigma.length] = (byte) encryptN; - kPkePRFeta2.reset(); - kPkePRFeta2.update(prfSeed); - byte[] cbdInput = kPkePRFeta2.digest(); - var encryptE2 = centeredBinomialDistribution(mlKem_eta2, cbdInput); var encryptRHat = mlKemVectorNTT(encryptR); var encryptUHat = mlKemMatrixVectorMuladd(encryptA, encryptRHat, zeroes); var encryptU = mlKemVectorInverseNTT(encryptUHat); encryptU = mlKemAddVec(encryptU, encryptE1); + + for (int i = 0; i < mlKem_k; i++) { + Arrays.fill(encryptE1[i], (short)0); + } + var encryptVHat = mlKemVectorScalarMult(encryptTHat, encryptRHat); var encryptV = mlKemInverseNTT(encryptVHat); encryptV = mlKemAddPoly(encryptV, encryptE2, decompressDecode(message)); var encryptC1 = encodeVector(mlKem_du, compressVector10_11(encryptU, mlKem_du)); var encryptC2 = encodePoly(mlKem_dv, compressPoly4_5(encryptV, mlKem_dv)); + Arrays.fill(encryptE2, (short)0); + Arrays.fill(encryptV, (short)0); byte[] result = new byte[encryptC1.length + encryptC2.length]; System.arraycopy(encryptC1, 0, @@ -783,9 +812,11 @@ Arrays.fill(decryptSHat[i], (short) 0); } decryptV = mlKemSubtractPoly(decryptV, decryptSU); + var result = encodeCompress(decryptV); Arrays.fill(decryptSU, (short) 0); + Arrays.fill(decryptV, (short) 0); - return encodeCompress(decryptV); + return result; } /* @@ -1363,22 +1394,16 @@ } } - // The intrinsic implementations assume that the input and output buffers - // are such that condensed can be read in 96-byte chunks and - // parsed can be written in 64 shorts chunks except for the last chunk - // that can be either 48 or 64 shorts. In other words, - // if (i - 1) * 64 < parsedLengths <= i * 64 then - // parsed.length should be either i * 64 or (i-1) * 64 + 48 and - // condensed.length should be at least index + i * 96. + // An intrinsic implementation assumes that the input and output buffers + // are such that condensed can be read in chunks of 192 bytes and + // parsed can be written in chunks of 128 shorts, so callers should allocate + // the condensed and parsed arrays accordingly, see the assert() private void twelve2Sixteen(byte[] condensed, int index, short[] parsed, int parsedLength) { - int i = parsedLength / 64; - int remainder = parsedLength - i * 64; - if (remainder != 0) { - i++; - } - assert ((remainder == 0) || (remainder == 48)) && - (index + i * 96 <= condensed.length); + int n = (parsedLength + 127) / 128; + assert ((parsed.length >= n * 128) && + (condensed.length >= index + n * 192)); + implKyber12To16(condensed, index, parsed, parsedLength); } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEParameterSpec; +import sun.security.util.PBKDF2Parameters; import sun.security.util.*; /** @@ -93,7 +94,7 @@ abstract class PBES2Parameters extends AlgorithmParametersSpi { private static final ObjectIdentifier pkcs5PBKDF2_OID = - ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); + ObjectIdentifier.of(KnownOIDs.PBKDF2); private static final ObjectIdentifier pkcs5PBES2_OID = ObjectIdentifier.of(KnownOIDs.PBES2); private static final ObjectIdentifier aes128CBC_OID = @@ -224,77 +225,32 @@ // next DerValue as the real PBES2-params. if (kdf.getTag() == DerValue.tag_ObjectId) { pBES2_params = pBES2_params.data.getDerValue(); + if (pBES2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBE parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } kdf = pBES2_params.data.getDerValue(); } - String kdfAlgo = parseKDF(kdf); - - if (pBES2_params.tag != DerValue.tag_Sequence) { - throw new IOException("PBE parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); - } - String cipherAlgo = parseES(pBES2_params.data.getDerValue()); - - this.pbes2AlgorithmName = "PBEWith" + kdfAlgo + "And" + cipherAlgo; - } - - private String parseKDF(DerValue keyDerivationFunc) throws IOException { - - if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { + if (!pkcs5PBKDF2_OID.equals(kdf.data.getOID())) { throw new IOException("PBE parameter parsing error: " + "expecting the object identifier for PBKDF2"); } - if (keyDerivationFunc.tag != DerValue.tag_Sequence) { + if (kdf.tag != DerValue.tag_Sequence) { throw new IOException("PBE parameter parsing error: " + "not an ASN.1 SEQUENCE tag"); } - DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue(); - if (pBKDF2_params.tag != DerValue.tag_Sequence) { - throw new IOException("PBE parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); - } - DerValue specified = pBKDF2_params.data.getDerValue(); - // the 'specified' ASN.1 CHOICE for 'salt' is supported - if (specified.tag == DerValue.tag_OctetString) { - salt = specified.getOctetString(); - } else { - // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported - throw new IOException("PBE parameter parsing error: " - + "not an ASN.1 OCTET STRING tag"); - } - iCount = pBKDF2_params.data.getInteger(); + DerValue pBKDF2_params = kdf.data.getDerValue(); - // keyLength INTEGER (1..MAX) OPTIONAL, - var ksDer = pBKDF2_params.data.getOptional(DerValue.tag_Integer); - if (ksDer.isPresent()) { - keysize = ksDer.get().getInteger() * 8; // keysize (in bits) - } + var kdfParams = new PBKDF2Parameters(pBKDF2_params); + String kdfAlgo = kdfParams.getPrfAlgo(); + salt = kdfParams.getSalt(); + iCount = kdfParams.getIterationCount(); + keysize = kdfParams.getKeyLength(); - // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 - String kdfAlgo; - var prfDer = pBKDF2_params.data.getOptional(DerValue.tag_Sequence); - if (prfDer.isPresent()) { - DerValue prf = prfDer.get(); - kdfAlgo_OID = prf.data.getOID(); - KnownOIDs o = KnownOIDs.findMatch(kdfAlgo_OID.toString()); - if (o == null || (!o.stdName().equals("HmacSHA1") && - !o.stdName().equals("HmacSHA224") && - !o.stdName().equals("HmacSHA256") && - !o.stdName().equals("HmacSHA384") && - !o.stdName().equals("HmacSHA512") && - !o.stdName().equals("HmacSHA512/224") && - !o.stdName().equals("HmacSHA512/256"))) { - throw new IOException("PBE parameter parsing error: " - + "expecting the object identifier for a HmacSHA key " - + "derivation function"); - } - kdfAlgo = o.stdName(); - prf.data.getOptional(DerValue.tag_Null); - prf.data.atEnd(); - } else { - kdfAlgo = "HmacSHA1"; - } - return kdfAlgo; + String cipherAlgo = parseES(pBES2_params.data.getDerValue()); + + this.pbes2AlgorithmName = "PBEWith" + kdfAlgo + "And" + cipherAlgo; } private String parseES(DerValue encryptionScheme) throws IOException { @@ -345,26 +301,9 @@ DerOutputStream pBES2_params = new DerOutputStream(); - DerOutputStream keyDerivationFunc = new DerOutputStream(); - keyDerivationFunc.putOID(pkcs5PBKDF2_OID); - - DerOutputStream pBKDF2_params = new DerOutputStream(); - pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING' - pBKDF2_params.putInteger(iCount); - - if (keysize > 0) { - pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets) - } - - DerOutputStream prf = new DerOutputStream(); - // algorithm is id-hmacWith - prf.putOID(kdfAlgo_OID); - // parameters is 'NULL' - prf.putNull(); - pBKDF2_params.write(DerValue.tag_Sequence, prf); - - keyDerivationFunc.write(DerValue.tag_Sequence, pBKDF2_params); - pBES2_params.write(DerValue.tag_Sequence, keyDerivationFunc); + // keysize encoded as octets + pBES2_params.writeBytes(PBKDF2Parameters.encode(salt, iCount, + keysize/8, kdfAlgo_OID)); DerOutputStream encryptionScheme = new DerOutputStream(); // algorithm is id-aes128-CBC or id-aes256-CBC diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java 2026-10-19 12:10:20.000000000 +0000 @@ -55,7 +55,7 @@ * @author Valerie Peng * */ -final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey { +public final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey { @java.io.Serial private static final long serialVersionUID = -2234868909660948157L; diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,25 +91,27 @@ (len == 0)) { // this can happen if input is really a padded buffer return 0; } - int idx = Math.addExact(off, len); - byte lastByte = in[idx - 1]; - int padValue = (int)lastByte & 0x0ff; - if ((padValue < 0x01) - || (padValue > blockSize)) { - return -1; - } - - int start = idx - padValue; - if (start < off) { - return -1; - } - for (int i = start; i < idx; i++) { - if (in[i] != lastByte) { - return -1; - } + int last = Math.addExact(off, len); + int padValue = in[last - 1] & 0x0ff; + // check padValue >= 1; negative if fail + int invalid = (padValue - 1); + // check padValue <= blockSize; negative if fail + invalid |= (blockSize - padValue); + + // check the last block for the padding bytes + for (int i = last - blockSize; i < last ; i++) { + // mask = 0 for the first (blockSize - padValue) bytes in the block + // otherwise, use 0xffff to preserve the value + int mask = (last - padValue - i - 1) >> 8 ; + int valueCheck = ((in[i] & 0x0ff) ^ padValue) & mask; + // again, assign negative value if fail + invalid |= -valueCheck; } - return start; + // convert 'invalid' to -1 when 'invalid' is not 0 + // right shifting by 8 should be sufficient since value range is small + invalid >>= 8; // 0 or -1 + return (invalid | (last - padValue)); } /** diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/lang/ref/Reference.java openjdk-25-25.0.5+8/src/java.base/share/classes/java/lang/ref/Reference.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/lang/ref/Reference.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/java/lang/ref/Reference.java 2026-10-19 12:10:20.000000000 +0000 @@ -357,11 +357,18 @@ * {@code null} if this reference object has been cleared * @see #refersTo */ - @IntrinsicCandidate public T get() { - return this.referent; + return get0(); } + /* Implementation of get(). This method exists to avoid making get() all + * of virtual, native, and intrinsic candidate. That could have the + * undesirable effect of having the native method used instead of the + * intrinsic when devirtualization fails. + */ + @IntrinsicCandidate + private native T get0(); + /** * Tests if the referent of this reference object is {@code obj}. * Using a {@code null} {@code obj} returns {@code true} if the diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/net/SocksSocketImpl.java openjdk-25-25.0.5+8/src/java.base/share/classes/java/net/SocksSocketImpl.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/net/SocksSocketImpl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/java/net/SocksSocketImpl.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,13 +143,27 @@ if (userName == null) return false; out.write(1); - out.write(userName.length()); - out.write(userName.getBytes(StandardCharsets.ISO_8859_1)); - if (password != null) { - out.write(password.length()); - out.write(password.getBytes(StandardCharsets.ISO_8859_1)); - } else + + var userNameBytes = userName.getBytes(StandardCharsets.ISO_8859_1); + // RFC 1929 allows usernames of at most 255 bytes + if (userNameBytes.length > 0xFF) { + throw new SocketException("SOCKS: username is too long"); + } + out.write(userNameBytes.length); + out.write(userNameBytes); + + if (password == null) { out.write(0); + } else { + var passwordBytes = password.getBytes(StandardCharsets.ISO_8859_1); + // RFC 1929 allows password of at most 255 bytes + if (passwordBytes.length > 0xFF) { + throw new SocketException("SOCKS: password is too long"); + } + out.write(passwordBytes.length); + out.write(passwordBytes); + } + out.flush(); byte[] data = new byte[2]; int i = readSocksReply(in, data, deadlineMillis); @@ -241,6 +255,15 @@ if (!(endpoint instanceof InetSocketAddress epoint)) throw new IllegalArgumentException("Unsupported address type"); + byte[] domainNameBytes = null; + if (epoint.isUnresolved()) { + domainNameBytes = epoint.getHostName().getBytes(StandardCharsets.ISO_8859_1); + // RFC 1928 allows FQDNs of at most 255 bytes + if (domainNameBytes.length > 0xFF) { + throw new SocketException("SOCKS: host name is too long"); + } + } + if (server == null) { // This is the general case // server is not null only when the socket was created with a @@ -366,8 +389,8 @@ /* Test for IPV4/IPV6/Unresolved */ if (epoint.isUnresolved()) { out.write(DOMAIN_NAME); - out.write(epoint.getHostName().length()); - out.write(epoint.getHostName().getBytes(StandardCharsets.ISO_8859_1)); + out.write(domainNameBytes.length); + out.write(domainNameBytes); out.write((epoint.getPort() >> 8) & 0xff); out.write((epoint.getPort() >> 0) & 0xff); } else if (epoint.getAddress() instanceof Inet6Address) { diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/security/Security.java openjdk-25-25.0.5+8/src/java.base/share/classes/java/security/Security.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/security/Security.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/java/security/Security.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; @@ -112,7 +113,7 @@ private static Path currentPath; - private static final Set activePaths = new HashSet<>(); + private static final List activePaths = new ArrayList<>(); static void loadAll() { // first load the master properties file to @@ -262,30 +263,40 @@ } } + private static void checkCyclicInclude(Path path) { + for (Path activePath : activePaths) { + try { + if (Files.isSameFile(path, activePath)) { + throw new InternalError( + "Cyclic include of '" + path + "'"); + } + } catch (IOException e) { + if (sdebug != null) { + sdebug.println("skipped exception when checking for " + + "cyclic inclusion of " + path + ":"); + e.printStackTrace(); + } + } + } + } + private static void loadFromPath(Path path, LoadingMode mode) throws IOException { - boolean isRegularFile = Files.isRegularFile(path); - if (isRegularFile) { - path = path.toRealPath(); - } else if (Files.isDirectory(path)) { + if (Files.isDirectory(path)) { throw new IOException("Is a directory"); - } else { - path = path.toAbsolutePath(); - } - if (activePaths.contains(path)) { - throw new InternalError("Cyclic include of '" + path + "'"); } try (InputStream is = Files.newInputStream(path)) { + checkCyclicInclude(path); reset(mode); Path previousPath = currentPath; - currentPath = isRegularFile ? path : null; + currentPath = Files.isRegularFile(path) ? path : null; activePaths.add(path); try { debugLoad(true, path); props.load(is); debugLoad(false, path); } finally { - activePaths.remove(path); + activePaths.removeLast(); currentPath = previousPath; } } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/text/SimpleDateFormat.java openjdk-25-25.0.5+8/src/java.base/share/classes/java/text/SimpleDateFormat.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/text/SimpleDateFormat.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/java/text/SimpleDateFormat.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; -import static java.text.DateFormatSymbols.*; +import java.time.ZoneOffset; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; @@ -57,6 +57,8 @@ import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.TimeZoneNameUtility; +import static java.text.DateFormatSymbols.*; + /** * {@code SimpleDateFormat} is a concrete class for formatting and * parsing dates in a locale-sensitive manner. It allows for formatting @@ -1293,15 +1295,22 @@ case PATTERN_ZONE_NAME: // 'z' if (current == null) { + TimeZone tz = calendar.getTimeZone(); + String tzid = tz.getID(); + int zoneOffset = calendar.get(Calendar.ZONE_OFFSET); + int dstOffset = calendar.get(Calendar.DST_OFFSET) + zoneOffset; + + // Check if an explicit metazone DST offset exists + String explicitDstOffset = TimeZoneNameUtility.explicitDstOffset(tzid); + boolean daylight = explicitDstOffset != null ? + dstOffset == ZoneOffset.of(explicitDstOffset).getTotalSeconds() * 1_000 : + dstOffset != zoneOffset; if (formatData.locale == null || formatData.isZoneStringsSet) { - int zoneIndex = - formatData.getZoneIndex(calendar.getTimeZone().getID()); + int zoneIndex = formatData.getZoneIndex(tzid); if (zoneIndex == -1) { - value = calendar.get(Calendar.ZONE_OFFSET) + - calendar.get(Calendar.DST_OFFSET); - buffer.append(ZoneInfoFile.toCustomID(value)); + buffer.append(ZoneInfoFile.toCustomID(dstOffset)); } else { - int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3; + int index = daylight ? 3 : 1; if (count < 4) { // Use the short name index++; @@ -1310,8 +1319,6 @@ buffer.append(zoneStrings[zoneIndex][index]); } } else { - TimeZone tz = calendar.getTimeZone(); - boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0); int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG); buffer.append(tz.getDisplayName(daylight, tzstyle, formatData.locale)); } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java openjdk-25-25.0.5+8/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -4505,7 +4505,11 @@ TemporalAccessor dt = context.getTemporal(); int type = GENERIC; if (!isGeneric) { - if (dt.isSupported(ChronoField.INSTANT_SECONDS)) { + // Check if an explicit metazone DST offset exists + String dstOffset = TimeZoneNameUtility.explicitDstOffset(zname); + if (dt.isSupported(OFFSET_SECONDS) && dstOffset != null) { + type = ZoneOffset.from(dt).equals(ZoneOffset.of(dstOffset)) ? DST : STD; + } else if (dt.isSupported(ChronoField.INSTANT_SECONDS)) { type = zone.getRules().isDaylightSavings(Instant.from(dt)) ? DST : STD; } else if (dt.isSupported(ChronoField.EPOCH_DAY) && dt.isSupported(ChronoField.NANO_OF_DAY)) { diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/util/zip/ZipFile.java openjdk-25-25.0.5+8/src/java.base/share/classes/java/util/zip/ZipFile.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/java/util/zip/ZipFile.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/java/util/zip/ZipFile.java 2026-10-19 12:10:20.000000000 +0000 @@ -1706,8 +1706,10 @@ this.cen = null; return; // only END header present } - if (end.cenlen > end.endpos) + // Validate END header + if (end.cenlen > end.endpos) { zerror("invalid END header (bad central directory size)"); + } long cenpos = end.endpos - end.cenlen; // position of CEN table // Get position of first local file (LOC) header, taking into // account that there may be a stub prefixed to the ZIP file. @@ -1715,18 +1717,22 @@ if (locpos < 0) { zerror("invalid END header (bad central directory offset)"); } - // read in the CEN if (end.cenlen > MAX_CEN_SIZE) { zerror("invalid END header (central directory size too large)"); } if (end.centot < 0 || end.centot > end.cenlen / CENHDR) { zerror("invalid END header (total entries count too large)"); } - cen = this.cen = new byte[(int)end.cenlen]; - if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen) { + // Validation ensures these are <= Integer.MAX_VALUE + int cenlen = Math.toIntExact(end.cenlen); + int centot = Math.toIntExact(end.centot); + + // read in the CEN + cen = this.cen = new byte[cenlen]; + if (readFullyAt(cen, 0, cen.length, cenpos) != cenlen) { zerror("read CEN tables failed"); } - this.total = Math.toIntExact(end.centot); + this.total = centot; } else { cen = this.cen; this.total = knownTotal; diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java openjdk-25-25.0.5+8/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -113,7 +113,10 @@ this.zipEntry = e; this.section = section(name.substring(0, i)); - this.name = name.substring(i+1); + this.name = name.substring(i + 1); + if (invalidEntryName(this.name)) { + throw new RuntimeException("invalid jmod entry: " + name); + } } /** @@ -168,6 +171,52 @@ return NAME_TO_SECTION.get(name); } + private static boolean invalidEntryName(String name) { + // JMOD entries are stored as section/name ZIP entries using '/' + // as the separator. Reject absolute paths, path names that contain + // '\' or '.' or '..' elements, and Windows drive-letter path elements. + if (name.startsWith("/") || name.indexOf('\\') >= 0) { + return true; + } + return hasDotOrDotDot(name) || hasWinDrive(name); + } + + private static boolean hasDotOrDotDot(String name) { + int index = 0; + while (index < name.length()) { + int start = index; + while (index < name.length() && name.charAt(index) != '/') { + index++; + } + if (name.charAt(start) == '.') { + int length = index - start; + if (length == 1 || (length == 2 && name.charAt(start + 1) == '.')) { + return true; + } + } + index++; + } + return false; + } + + private static boolean isWinDriveLetter(char c) { + return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); + } + + private static boolean hasWinDrive(String name) { + int i = 0; + while (i + 1 < name.length()) { + if (name.charAt(i + 1) == ':' && isWinDriveLetter(name.charAt(i))) { + return true; + } + i = name.indexOf('/', i); + if (i < 0) { + return false; + } + i++; + } + return false; + } } private final Path file; diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/module-info.java openjdk-25-25.0.5+8/src/java.base/share/classes/module-info.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/module-info.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/module-info.java 2026-10-19 12:10:20.000000000 +0000 @@ -318,6 +318,7 @@ exports sun.security.internal.spec to jdk.crypto.cryptoki; exports sun.security.jca to + java.security.sasl, java.smartcardio, jdk.crypto.cryptoki, jdk.naming.dns; diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -526,7 +526,7 @@ // ignore... } } - if (cmd.indexOf('\n') != -1) { + if (cmd.indexOf('\n') != -1 || cmd.indexOf('\r') != -1) { sun.net.ftp.FtpProtocolException ex = new sun.net.ftp.FtpProtocolException("Illegal FTP command"); ex.initCause(new IllegalArgumentException("Illegal carriage return")); diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/smtp/SmtpClient.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/smtp/SmtpClient.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/smtp/SmtpClient.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/smtp/SmtpClient.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, 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 @@ -74,7 +74,7 @@ } public void to(String s) throws IOException { - if (s.indexOf('\n') != -1) { + if (s.indexOf('\n') != -1 || s.indexOf('\r') != -1) { throw new IOException("Illegal SMTP command", new IllegalArgumentException("Illegal carriage return")); } @@ -120,7 +120,7 @@ } public void from(String s) throws IOException { - if (s.indexOf('\n') != -1) { + if (s.indexOf('\n') != -1 || s.indexOf('\r') != -1) { throw new IOException("Illegal SMTP command", new IllegalArgumentException("Illegal carriage return")); } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package sun.net.www.protocol.http; +import java.io.IOException; import java.net.PasswordAuthentication; import java.net.URL; import java.util.HashMap; @@ -428,9 +429,10 @@ * @param conn The connection to apply the header(s) to * @param p A source of header values for this connection, if needed. * @param raw The raw header field (if needed) - * @return true if all goes well, false if no headers were set. + * @throws IOException if no headers were set */ - public abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw); + public abstract void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) + throws IOException; /** * Check if the header indicates that the current auth. parameters are stale. diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,15 +125,13 @@ * @param conn The connection to apply the header(s) to * @param p A source of header values for this connection, if needed. * @param raw The raw header values for this connection, if needed. - * @return true if all goes well, false if no headers were set. */ @Override - public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { // no need to synchronize here: // already locked by s.n.w.p.h.HttpURLConnection assert conn.isLockHeldByCurrentThread(); conn.setAuthenticationProperty(getHeaderName(), getHeaderValue(null,null)); - return true; } /** diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -321,7 +321,11 @@ */ @Override public String getHeaderValue(URL url, String method) { - return getHeaderValueImpl(url.getFile(), method); + try { + return getHeaderValueImpl(url.getFile(), method); + } catch (IOException _) { + return null; + } } /** @@ -339,7 +343,11 @@ * @return the value of the HTTP header this authentication wants set */ String getHeaderValue(String requestURI, String method) { - return getHeaderValueImpl(requestURI, method); + try { + return getHeaderValueImpl(requestURI, method); + } catch (IOException _) { + return null; + } } /** @@ -369,10 +377,11 @@ * @param conn The connection to apply the header(s) to * @param p A source of header values for this connection, if needed. * @param raw Raw header values for this connection, if needed. - * @return true if all goes well, false if no headers were set. + * @throws IOException if no headers were set */ @Override - public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) + throws IOException { // no need to synchronize here: // already locked by s.n.w.p.h.HttpURLConnection assert conn.isLockHeldByCurrentThread(); @@ -380,14 +389,14 @@ params.setNonce (p.findValue("nonce")); params.setOpaque (p.findValue("opaque")); params.setQop (p.findValue("qop")); - params.setUserhash (Boolean.valueOf(p.findValue("userhash"))); + params.setUserhash (Boolean.parseBoolean(p.findValue("userhash"))); String charset = p.findValue("charset"); if (charset == null) { charset = "ISO_8859_1"; } else if (!charset.equalsIgnoreCase("UTF-8")) { // UTF-8 is only valid value. ISO_8859_1 represents default behavior // when the parameter is not set. - return false; + throw new IOException("Illegal charset in header"); } params.setCharset(charset.toUpperCase(Locale.ROOT)); @@ -405,7 +414,7 @@ } if (params.nonce == null || authMethod == null || pw == null || realm == null) { - return false; + throw new IOException("Server challenge incomplete"); } if (authMethod.length() >= 1) { // Method seems to get converted to all lower case elsewhere. @@ -415,8 +424,7 @@ + authMethod.substring(1).toLowerCase(Locale.ROOT); } - if (!setAlgorithmNames(p, params)) - return false; + setAlgorithmNames(p, params); // If authQop is true, then the server is doing RFC2617 and // has offered qop=auth. We do not support any other modes @@ -426,20 +434,17 @@ params.setNewCnonce(); } - String value = getHeaderValueImpl (uri, method); - if (value != null) { - conn.setAuthenticationProperty(getHeaderName(), value); - return true; - } else { - return false; - } + String value = getHeaderValueImpl(uri, method); + assert value != null; + conn.setAuthenticationProperty(getHeaderName(), value); } // Algorithm name is stored in two separate fields (of Paramaeters) // This allows for variations in digest algorithm name (aliases) // and also allow for the -sess variant defined in HTTP Digest protocol - // returns false if algorithm not supported - private static boolean setAlgorithmNames(HeaderParser p, Parameters params) { + // throws IOException if algorithm not supported + private static void setAlgorithmNames(HeaderParser p, Parameters params) + throws IOException { String algorithm = p.findValue("algorithm"); String digestName = algorithm; if (algorithm == null || algorithm.isEmpty()) { @@ -459,18 +464,17 @@ var oid = KnownOIDs.findMatch(digestName); if (oid == null) { log("unknown algorithm: " + algorithm); - return false; + throw new IOException("Unknown algorithm: " + algorithm); } digestName = oid.stdName(); params.setAlgorithm (algorithm); params.setDigestName (digestName); - return true; } /* Calculate the Authorization header field given the request URI * and based on the authorization information in params */ - private String getHeaderValueImpl (String uri, String method) { + private String getHeaderValueImpl (String uri, String method) throws IOException { String response; char[] passwd = pw.getPassword(); boolean qop = params.authQop(); @@ -479,11 +483,7 @@ String nonce = params.getNonce (); String algorithm = params.getAlgorithm (); String digest = params.getDigestName (); - try { - validateDigest(digest); - } catch (IOException e) { - return null; - } + validateDigest(digest); Charset charset = params.getCharset(); boolean userhash = params.getUserhash (); params.incrementNC (); @@ -505,7 +505,7 @@ digest, session, charset); } catch (CharacterCodingException | NoSuchAlgorithmException ex) { log(ex.getMessage()); - return null; + throw new IOException("Failed to compute digest", ex); } String ncfield = "\""; @@ -534,7 +534,7 @@ } } catch (CharacterCodingException | NoSuchAlgorithmException ex) { log(ex.getMessage()); - return null; + throw new IOException("Failed to compute user hash", ex); } String value = authMethod diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java 2026-10-19 12:10:20.000000000 +0000 @@ -61,6 +61,7 @@ import java.util.StringJoiner; import jdk.internal.access.JavaNetHttpCookieAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.util.Exceptions; import sun.net.NetProperties; import sun.net.NetworkClient; import sun.net.util.IPAddressUtil; @@ -1474,16 +1475,29 @@ /* in this case, only one header field will be present */ String raw = responses.findValue ("Proxy-Authenticate"); reset (); - if (!proxyAuthentication.setHeaders(this, - authhdr.headerParser(), raw)) { + try { + proxyAuthentication.setHeaders(this, + authhdr.headerParser(), raw); + } catch (IOException ex) { disconnectInternal(); - throw new IOException ("Authentication failure"); + if (Exceptions.enhancedNonSocketExceptions()) { + throw new IOException ("Authentication failure", ex); + } else { + throw new IOException ("Authentication failure"); + } } - if (serverAuthentication != null && srvHdr != null && - !serverAuthentication.setHeaders(this, - srvHdr.headerParser(), raw)) { - disconnectInternal (); - throw new IOException ("Authentication failure"); + if (serverAuthentication != null && srvHdr != null) { + try { + serverAuthentication.setHeaders(this, + srvHdr.headerParser(), raw); + } catch (IOException ex) { + disconnectInternal(); + if (Exceptions.enhancedNonSocketExceptions()) { + throw new IOException ("Authentication failure", ex); + } else { + throw new IOException ("Authentication failure"); + } + } } authObj = null; doingNTLMp2ndStage = false; @@ -1562,9 +1576,15 @@ } else { reset (); /* header not used for ntlm */ - if (!serverAuthentication.setHeaders(this, null, raw)) { + try { + serverAuthentication.setHeaders(this, null, raw); + } catch (IOException ex) { disconnectWeb(); - throw new IOException ("Authentication failure"); + if (Exceptions.enhancedNonSocketExceptions()) { + throw new IOException ("Authentication failure", ex); + } else { + throw new IOException ("Authentication failure"); + } } doingNTLM2ndStage = false; authObj = null; @@ -1954,10 +1974,16 @@ } else { String raw = responses.findValue ("Proxy-Authenticate"); reset (); - if (!proxyAuthentication.setHeaders(this, - authhdr.headerParser(), raw)) { + try { + proxyAuthentication.setHeaders(this, + authhdr.headerParser(), raw); + } catch (IOException ex) { disconnectInternal(); - throw new IOException ("Authentication failure"); + if (Exceptions.enhancedNonSocketExceptions()) { + throw new IOException ("Authentication failure", ex); + } else { + throw new IOException ("Authentication failure"); + } } authObj = null; doingNTLMp2ndStage = false; @@ -2221,7 +2247,9 @@ }; } if (ret != null) { - if (!ret.setHeaders(this, p, raw)) { + try { + ret.setHeaders(this, p, raw); + } catch (IOException e) { ret.disposeContext(); ret = null; } @@ -2378,7 +2406,9 @@ } } if (ret != null ) { - if (!ret.setHeaders(this, p, raw)) { + try { + ret.setHeaders(this, p, raw); + } catch (IOException e) { ret.disposeContext(); ret = null; } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,29 +168,24 @@ * @param p A source of header values for this connection, not used because * HeaderParser converts the fields to lower case, use raw instead * @param raw The raw header field. - * @return true if all goes well, false if no headers were set. + * @throws IOException if no headers were set */ @Override - public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) throws IOException { // no need to synchronize here: // already locked by s.n.w.p.h.HttpURLConnection assert conn.isLockHeldByCurrentThread(); - try { - String response; - byte[] incoming = null; - String[] parts = raw.split("\\s+"); - if (parts.length > 1) { - incoming = Base64.getDecoder().decode(parts[1]); - } - response = hci.scheme + " " + Base64.getEncoder().encodeToString( - incoming==null?firstToken():nextToken(incoming)); - - conn.setAuthenticationProperty(getHeaderName(), response); - return true; - } catch (IOException e) { - return false; + String response; + byte[] incoming = null; + String[] parts = raw.split("\\s+"); + if (parts.length > 1) { + incoming = Base64.getDecoder().decode(parts[1]); } + response = hci.scheme + " " + Base64.getEncoder().encodeToString( + incoming==null?firstToken():nextToken(incoming)); + + conn.setAuthenticationProperty(getHeaderName(), response); } /** diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/pkcs12/MacData.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/pkcs12/MacData.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/pkcs12/MacData.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/pkcs12/MacData.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,32 +25,58 @@ package sun.security.pkcs12; -import java.io.*; +import java.io.IOException; import java.security.*; +import java.security.spec.InvalidKeySpecException; +import static java.util.Locale.ENGLISH; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; -import sun.security.util.DerInputStream; -import sun.security.util.DerOutputStream; -import sun.security.util.DerValue; -import sun.security.x509.AlgorithmId; import sun.security.pkcs.ParsingException; +import sun.security.util.*; +import sun.security.x509.AlgorithmId; /** - * A MacData type, as defined in PKCS#12. + * The MacData type, as defined in PKCS#12. + * + * The ASN.1 definition is as follows: + * + *

+ *
+ * MacData ::= SEQUENCE {
+ *     mac        DigestInfo,
+ *     macSalt    OCTET STRING,
+ *     iterations INTEGER DEFAULT 1
+ *      -- Note: The default is for historical reasons and its use is
+ *      -- deprecated.
+ * }
+ *
+ * DigestInfo ::= SEQUENCE {
+ *     digestAlgorithm DigestAlgorithmIdentifier,
+ *     digest OCTET STRING
+ * }
+ *
+ * 
* * @author Sharon Liu */ class MacData { - private final String digestAlgorithmName; - private AlgorithmParameters digestAlgorithmParams; + private static final Debug debug = Debug.getInstance("pkcs12"); + private final String macAlgorithm; private final byte[] digest; private final byte[] macSalt; private final int iterations; - // the ASN.1 encoded contents of this class - private byte[] encoded = null; + // The following three fields are for PBMAC1. + private final int keyLength; + private final String kdfHmac; + private final String hmac; /** * Parses a PKCS#12 MAC data. @@ -70,103 +96,276 @@ // Parse the DigestAlgorithmIdentifier. AlgorithmId digestAlgorithmId = AlgorithmId.parse(digestInfo[0]); - this.digestAlgorithmName = digestAlgorithmId.getName(); - this.digestAlgorithmParams = digestAlgorithmId.getParameters(); + String digestAlgorithmName = digestAlgorithmId.getName(); + // Get the digest. this.digest = digestInfo[1].getOctetString(); - // Get the salt. - this.macSalt = macData[1].getOctetString(); + if (digestAlgorithmName.equals("PBMAC1")) { + PBMAC1Parameters algParams; + + algParams = new PBMAC1Parameters(digestAlgorithmId + .getEncodedParams()); - // Iterations is optional. The default value is 1. - if (macData.length > 2) { - this.iterations = macData[2].getInteger(); + this.iterations = algParams.getKdfParams().getIterationCount(); + this.macSalt = algParams.getKdfParams().getSalt(); + this.kdfHmac = algParams.getKdfParams().getPrfAlgo(); + this.keyLength = algParams.getKdfParams().getKeyLength(); + + // Implementations MUST NOT accept params that omit keyLength. + if (this.keyLength == -1) { + throw new IOException("error: missing keyLength field"); + } + this.hmac = algParams.getHmac(); + this.macAlgorithm = "pbewith" + this.kdfHmac + "and" + this.hmac; } else { - this.iterations = 1; + this.kdfHmac = null; + this.hmac = null; + this.keyLength = -1; + this.macSalt = macData[1].getOctetString(); + if (macData.length > 2) { + this.iterations = macData[2].getInteger(); + } else { + this.iterations = 1; + } + // Remove "-" from digest algorithm names + this.macAlgorithm = "hmacpbe" + + digestAlgorithmName.replace("-", ""); } } - MacData(String algName, byte[] digest, byte[] salt, int iterations) - throws NoSuchAlgorithmException - { - if (algName == null) - throw new NullPointerException("the algName parameter " + - "must be non-null"); - - AlgorithmId algid = AlgorithmId.get(algName); - this.digestAlgorithmName = algid.getName(); - this.digestAlgorithmParams = algid.getParameters(); - - if (digest == null) { - throw new NullPointerException("the digest " + - "parameter must be non-null"); - } else if (digest.length == 0) { - throw new IllegalArgumentException("the digest " + - "parameter must not be empty"); + /** + * Computes a MAC on the data. + * + * This is a two-step process: first generate a key and then use the + * key to generate the MAC. PBMAC1 and non-PBMAC1 keys use different + * key factories. PBMAC1 uses a pseudorandom function (kdfHmac) + * to generate keys while non-PBMAC1 does not. The MAC is computed + * according to the specified hmac algorithm. + * + * @param macAlgorithm the algorithm used to compute the MAC + * @param password the password used to generate the key + * @param params a PBEParameterSpec object + * @param data the data on which the MAC is computed + * @param kdfHmac the pseudorandom function used to compute the key + * for PBMAC1 + * @param hmac the algorithm used to compute the MAC + * @param keyLength the length of the key generated by the pseudorandom + * function + * + * @return the computed MAC as a byte array + * + * @exception NoSuchAlgorithmException if either kdfHmac or hmac is + * unknown to the Mac or SecretKeyFactory + */ + private static byte[] calculateMac(String macAlgorithm, char[] password, + PBEParameterSpec params, byte[] data, + String kdfHmac, String hmac, int keyLength) + throws InvalidAlgorithmParameterException, InvalidKeyException, + InvalidKeySpecException, NoSuchAlgorithmException { + SecretKeyFactory skf; + SecretKey pbeKey = null; + Mac m; + + PBEKeySpec keySpec; + + /* + * The Hmac has to be extracted from the algorithm name for + * PBMAC1 algorithms. For non-PBMAC1 macAlgorithms, the name + * and Hmac are the same. + * + * The prefix used in Algorithm names is guaranteed to be lowercase. + */ + if (macAlgorithm.startsWith("pbewith")) { + m = Mac.getInstance(hmac); + int len = keyLength == -1 ? m.getMacLength()*8 : keyLength; + skf = SecretKeyFactory.getInstance("PBKDF2With" +kdfHmac); + keySpec = new PBEKeySpec(password, params.getSalt(), + params.getIterationCount(), len); } else { - this.digest = digest.clone(); + m = Mac.getInstance(macAlgorithm); + skf = SecretKeyFactory.getInstance("PBE"); + keySpec = new PBEKeySpec(password); } - this.macSalt = salt; - this.iterations = iterations; + try { + pbeKey = skf.generateSecret(keySpec); + if (macAlgorithm.startsWith("pbewith")) { + m.init(pbeKey); + } else { + m.init(pbeKey, params); + } + m.update(data); + return m.doFinal(); + } finally { + keySpec.clearPassword(); + KeyUtil.destroySecretKeys(pbeKey); + } + } - // delay the generation of ASN.1 encoding until - // getEncoded() is called - this.encoded = null; + /** + * Verify Mac on the data. + * + * Calculate Mac on the data and compare with Mac found in input stream. + * + * @param password the password used to generate the key + * @param data the data on which the MAC is computed + * + * @exception UnrecoverableKeyException if calculated Mac and + * Mac found in input stream are different + */ + void verifyMac(char[] password, byte[] data) + throws InvalidAlgorithmParameterException, InvalidKeyException, + InvalidKeySpecException, NoSuchAlgorithmException, + UnrecoverableKeyException { + + byte[] macResult = calculateMac(this.macAlgorithm, password, + new PBEParameterSpec(this.macSalt, this.iterations), + data, this.kdfHmac, this.hmac, this.keyLength); + + if (debug != null) { + debug.println("Checking keystore integrity " + + "(" + this.macAlgorithm + " iterations: " + + this.iterations + ")"); + } + if (!MessageDigest.isEqual(this.digest, macResult)) { + throw new UnrecoverableKeyException("Failed PKCS12" + + " integrity checking"); + } } - String getDigestAlgName() { - return digestAlgorithmName; - } + /* + * Gathers parameters and generates a MAC of the data + * + * @param password the password used to generate the key + * @param data the data on which the MAC is computed + * @param macAlgorithm the algorithm used to compute the MAC + * @param macIterationCount the iteration count + * @param salt the salt + * + * @exception IOException if the MAC cannot be calculated + * + * @return the computed MAC as a byte array + */ + static byte[] generateMac(char[] passwd, byte[] data, + String macAlgorithm, int macIterationCount, byte[] salt) + throws IOException, NoSuchAlgorithmException { + final PBEParameterSpec params; + String algName; + String kdfHmac; + String hmac; + + macAlgorithm = macAlgorithm.toLowerCase(ENGLISH); + // The prefix used in Algorithm names is guaranteed to be lowercase. + if (macAlgorithm.startsWith("pbewith")) { + algName = "PBMAC1"; + kdfHmac = MacData.parseKdfHmac(macAlgorithm); + hmac = MacData.parseHmac(macAlgorithm); + if (hmac == null) { + hmac = kdfHmac; + } + } else if (macAlgorithm.startsWith("hmacpbe")) { + algName = macAlgorithm.substring(7); + kdfHmac = null; + hmac = macAlgorithm; + } else { + throw new ParsingException("unexpected algorithm '" + + macAlgorithm + "'"); + } + + params = new PBEParameterSpec(salt, macIterationCount); - byte[] getSalt() { - return macSalt; + try { + byte[] macResult = calculateMac(macAlgorithm, passwd, params, data, + kdfHmac, hmac, -1); + + DerOutputStream bytes = new DerOutputStream(); + bytes.write(encode(algName, macResult, params, kdfHmac, hmac, + macResult.length)); + return bytes.toByteArray(); + } catch (InvalidKeySpecException | InvalidKeyException | + InvalidAlgorithmParameterException e) { + throw new IOException("calculateMac failed: " + e, e); + } } - int getIterations() { - return iterations; + String getMacAlgorithm() { + return this.macAlgorithm; } - byte[] getDigest() { - return digest; + int getIterations() { + return this.iterations; } /** - * Returns the ASN.1 encoding of this object. - * @return the ASN.1 encoding. - * @exception IOException if error occurs when constructing its + * Returns the ASN.1 encoding. + * @return the ASN.1 encoding + * @exception NoSuchAlgorithmException if error occurs when constructing its * ASN.1 encoding. */ - public byte[] getEncoded() throws NoSuchAlgorithmException - { - if (this.encoded != null) - return this.encoded.clone(); - - DerOutputStream out = new DerOutputStream(); - DerOutputStream tmp = new DerOutputStream(); - - DerOutputStream tmp2 = new DerOutputStream(); - // encode encryption algorithm - AlgorithmId algid = AlgorithmId.get(digestAlgorithmName); - algid.encode(tmp2); + static byte[] encode(String algName, byte[] digest, PBEParameterSpec p, + String kdfHmac, String hmac, int keyLength) + throws IOException, NoSuchAlgorithmException { - // encode digest data - tmp2.putOctetString(digest); + final int iterations = p.getIterationCount(); + final byte[] macSalt = p.getSalt(); - tmp.write(DerValue.tag_Sequence, tmp2); + DerOutputStream tmp = new DerOutputStream(); + DerOutputStream out = new DerOutputStream(); - // encode salt - tmp.putOctetString(macSalt); + if (algName.equals("PBMAC1")) { + DerOutputStream tmp1 = new DerOutputStream(); + DerOutputStream tmp2 = new DerOutputStream(); + + // id-PBMAC1 OBJECT IDENTIFIER ::= { pkcs-5 14 } + tmp2.putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)); + tmp2.writeBytes(PBMAC1Parameters.encode(macSalt, iterations, + keyLength, kdfHmac, hmac)); + + tmp1.write(DerValue.tag_Sequence, tmp2); + tmp1.putOctetString(digest); + + tmp.write(DerValue.tag_Sequence, tmp1); + tmp.putOctetString( + new byte[]{ 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }); + // Unused, but must have non-zero positive value. + tmp.putInteger(1); + } else { + final AlgorithmId digestAlgorithm = AlgorithmId.get(algName); + DerOutputStream tmp2 = new DerOutputStream(); - // encode iterations - tmp.putInteger(iterations); + tmp2.write(digestAlgorithm); + tmp2.putOctetString(digest); + // wrap into a SEQUENCE + tmp.write(DerValue.tag_Sequence, tmp2); + tmp.putOctetString(macSalt); + tmp.putInteger(iterations); + } // wrap everything into a SEQUENCE out.write(DerValue.tag_Sequence, tmp); - this.encoded = out.toByteArray(); + return out.toByteArray(); + } - return this.encoded.clone(); + private static String parseKdfHmac(String text) { + int index1 = text.indexOf("with") + 4; + int index2 = text.indexOf("and"); + if (index1 == 3) { // -1 + 4 + return null; + } else if (index2 == -1) { + return text.substring(index1); + } else { + return text.substring(index1, index2); + } } + private static String parseHmac(String text) { + int index1 = text.indexOf("and") + 3; + if (index1 == 2) { // -1 + 3 + return null; + } else { + return text.substring(index1); + } + } } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.pkcs12; + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; + +import sun.security.util.*; +import sun.security.x509.AlgorithmId; + +/** + * This class implements the parameter set used with password-based + * mac scheme 1 (PBMAC1), which is defined in PKCS#5 as follows: + * + *
+ * -- PBMAC1
+ *
+ * PBMAC1Algorithms ALGORITHM-IDENTIFIER ::=
+ *   { {PBMAC1-params IDENTIFIED BY id-PBMAC1}, ...}
+ *
+ * id-PBMAC1 OBJECT IDENTIFIER ::= {pkcs-5 14}
+ *
+ * PBMAC1-params ::= SEQUENCE {
+ *   keyDerivationFunc AlgorithmIdentifier {{PBMAC1-KDFs}},
+ *   messageAuthScheme AlgorithmIdentifier {{PBMAC1-MACs}} }
+ *
+ * PBMAC1-KDFs ALGORITHM-IDENTIFIER ::=
+ *   { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
+ *
+ * PBMAC1-MACs ALGORITHM-IDENTIFIER ::= { ... }
+ *
+ * -- PBKDF2
+ *
+ * See sun.security.util.PBKDF2Parameters.
+ *
+ * 
+ * + * @since 26 + */ +final class PBMAC1Parameters { + + static final ObjectIdentifier pkcs5PBKDF2_OID = + ObjectIdentifier.of(KnownOIDs.PBKDF2); + + private final String hmacAlgo; + private final PBKDF2Parameters kdfParams; + + PBMAC1Parameters(byte[] encoded) throws IOException { + DerValue pBMAC1_params = new DerValue(encoded); + if (pBMAC1_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBMAC1 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue[] info = new DerInputStream(pBMAC1_params.toByteArray()) + .getSequence(2); + if (info.length != 2) { + throw new IOException("PBMAC1 parameter parsing error: " + + "expected length not 2"); + } + ObjectIdentifier OID = info[1].data.getOID(); + KnownOIDs o = KnownOIDs.findMatch(OID.toString()); + if (o == null || (!o.stdName().equals("HmacSHA1") && + !o.stdName().equals("HmacSHA224") && + !o.stdName().equals("HmacSHA256") && + !o.stdName().equals("HmacSHA384") && + !o.stdName().equals("HmacSHA512") && + !o.stdName().equals("HmacSHA512/224") && + !o.stdName().equals("HmacSHA512/256"))) { + throw new IOException("PBMAC1 parameter parsing error: " + + "expecting the object identifier for a HmacSHA key " + + "derivation function"); + } + // Hmac function used to compute the MAC + this.hmacAlgo = o.stdName(); + + //DerValue kdf = pBMAC1_params.data.getDerValue(); + DerValue kdf = info[0]; + + if (!pkcs5PBKDF2_OID.equals(kdf.data.getOID())) { + throw new IOException("PBKDF2 parameter parsing error: " + + "expecting the object identifier for PBKDF2"); + } + if (kdf.tag != DerValue.tag_Sequence) { + throw new IOException("PBKDF2 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue pBKDF2_params = kdf.data.getDerValue(); + + this.kdfParams = new PBKDF2Parameters(pBKDF2_params); + } + + /* + * Encode PBMAC1 parameters from components. + */ + static byte[] encode(byte[] salt, int iterationCount, int keyLength, + String kdfHmac, String hmac) throws NoSuchAlgorithmException { + + DerOutputStream out = new DerOutputStream(); + + // keyDerivationFunc AlgorithmIdentifier {{PBMAC1-KDFs}} + out.writeBytes(PBKDF2Parameters.encode(salt, + iterationCount, keyLength, kdfHmac)); + + // messageAuthScheme AlgorithmIdentifier {{PBMAC1-MACs}} + out.write(AlgorithmId.get(hmac)); + return new DerOutputStream().write(DerValue.tag_Sequence, out) + .toByteArray(); + } + + PBKDF2Parameters getKdfParams() { + return this.kdfParams; + } + + String getHmac() { + return this.hmacAlgo; + } +} diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,52 +26,36 @@ package sun.security.pkcs12; import java.io.*; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.KeyStore; -import java.security.KeyStoreSpi; -import java.security.KeyStoreException; -import java.security.PKCS12Attribute; -import java.security.PrivateKey; -import java.security.UnrecoverableEntryException; -import java.security.UnrecoverableKeyException; -import java.security.SecureRandom; -import java.security.Security; +import java.security.*; import java.security.cert.Certificate; +import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.security.cert.CertificateException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import java.util.*; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; -import javax.crypto.spec.PBEParameterSpec; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; import javax.crypto.spec.SecretKeySpec; -import javax.crypto.SecretKeyFactory; -import javax.crypto.SecretKey; -import javax.crypto.Cipher; -import javax.crypto.Mac; import javax.security.auth.DestroyFailedException; import javax.security.auth.x500.X500Principal; import jdk.internal.access.SharedSecrets; -import sun.security.tools.KeyStoreUtil; -import sun.security.util.*; import sun.security.pkcs.ContentInfo; -import sun.security.x509.AlgorithmId; import sun.security.pkcs.EncryptedPrivateKeyInfo; import sun.security.provider.JavaKeyStore.JKS; +import sun.security.tools.KeyStoreUtil; +import sun.security.util.*; +import sun.security.x509.AlgorithmId; import sun.security.x509.AuthorityKeyIdentifierExtension; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * This class provides the keystore implementation referred to as "PKCS12". @@ -366,7 +350,7 @@ try { cipher.init(Cipher.DECRYPT_MODE, skey, algParams); } finally { - destroyPBEKey(skey); + KeyUtil.destroySecretKeys(skey); } byte[] keyInfo = cipher.doFinal(encryptedKey); /* @@ -856,17 +840,6 @@ } /* - * Destroy the key obtained from getPBEKey(). - */ - private void destroyPBEKey(SecretKey key) { - try { - key.destroy(); - } catch (DestroyFailedException e) { - // Accept this - } - } - - /* * Encrypt private key or secret key using Password-based encryption (PBE) * as defined in PKCS#5. * @@ -915,7 +888,7 @@ try { cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); } finally { - destroyPBEKey(skey); + KeyUtil.destroySecretKeys(skey); } byte[] encryptedKey = cipher.doFinal(data); algid = new AlgorithmId(pbeOID, cipher.getParameters()); @@ -1265,7 +1238,8 @@ macIterationCount = defaultMacIterationCount(); } if (password != null && !macAlgorithm.equalsIgnoreCase("NONE")) { - byte[] macData = calculateMac(password, authenticatedSafe); + byte[] macData = MacData.generateMac(password, authenticatedSafe, + macAlgorithm, macIterationCount, getSalt()); pfx.write(macData); } // write PFX to output stream @@ -1481,48 +1455,6 @@ } /* - * Calculate MAC using HMAC algorithm (required for password integrity) - * - * Hash-based MAC algorithm combines secret key with message digest to - * create a message authentication code (MAC) - */ - private byte[] calculateMac(char[] passwd, byte[] data) - throws IOException - { - byte[] mData; - String algName = macAlgorithm.substring(7); - - try { - // Generate a random salt. - byte[] salt = getSalt(); - - // generate MAC (MAC key is generated within JCE) - Mac m = Mac.getInstance(macAlgorithm); - PBEParameterSpec params = - new PBEParameterSpec(salt, macIterationCount); - SecretKey key = getPBEKey(passwd); - try { - m.init(key, params); - } finally { - destroyPBEKey(key); - } - m.update(data); - byte[] macResult = m.doFinal(); - - // encode as MacData - MacData macData = new MacData(algName, macResult, salt, - macIterationCount); - DerOutputStream bytes = new DerOutputStream(); - bytes.write(macData.getEncoded()); - mData = bytes.toByteArray(); - } catch (Exception e) { - throw new IOException("calculateMac failed: " + e, e); - } - return mData; - } - - - /* * Validate Certificate Chain */ private boolean validateChain(Certificate[] certChain) @@ -1890,7 +1822,7 @@ try { cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); } finally { - destroyPBEKey(skey); + KeyUtil.destroySecretKeys(skey); } encryptedData = cipher.doFinal(data); @@ -2100,7 +2032,7 @@ try { cipher.init(Cipher.DECRYPT_MODE, skey, algParams); } finally { - destroyPBEKey(skey); + KeyUtil.destroySecretKeys(skey); } loadSafeContents(new DerInputStream(cipher.doFinal(rawData))); return null; @@ -2135,39 +2067,11 @@ "MAC iteration count too large: " + ic); } - String algName = - macData.getDigestAlgName().toUpperCase(Locale.ENGLISH); - - // Change SHA-1 to SHA1 - algName = algName.replace("-", ""); - - macAlgorithm = "HmacPBE" + algName; + // Store MAC algorithm of keystore that was just loaded. + macAlgorithm = macData.getMacAlgorithm(); macIterationCount = ic; - - // generate MAC (MAC key is created within JCE) - Mac m = Mac.getInstance(macAlgorithm); - PBEParameterSpec params = - new PBEParameterSpec(macData.getSalt(), ic); - RetryWithZero.run(pass -> { - SecretKey key = getPBEKey(pass); - try { - m.init(key, params); - } finally { - destroyPBEKey(key); - } - m.update(authSafeData); - byte[] macResult = m.doFinal(); - - if (debug != null) { - debug.println("Checking keystore integrity " + - "(" + m.getAlgorithm() + " iterations: " + ic + ")"); - } - - if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { - throw new UnrecoverableKeyException("Failed PKCS12" + - " integrity checking"); - } + macData.verifyMac(pass, authSafeData); return (Void) null; }, password); } catch (Exception e) { diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/provider/SHA3.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/provider/SHA3.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/provider/SHA3.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/provider/SHA3.java 2026-10-19 12:10:20.000000000 +0000 @@ -28,6 +28,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteOrder; +import java.security.DigestException; import java.security.ProviderException; import java.util.Arrays; import java.util.Objects; @@ -467,6 +468,11 @@ return engineDigest(); } + public int digest(byte[] out, int offs, int len) + throws DigestException { + return engineDigest(out, offs, len); + } + public void squeeze(byte[] output, int offset, int numBytes) { implSqueeze(output, offset, numBytes); } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/DHasKEM.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/DHasKEM.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/DHasKEM.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/DHasKEM.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import sun.security.util.ArrayUtil; +import sun.security.util.CurveDB; +import sun.security.util.ECUtil; +import sun.security.util.NamedCurve; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.KeyAgreement; +import javax.crypto.SecretKey; +import java.io.IOException; +import java.math.BigInteger; +import java.security.*; +import java.security.interfaces.ECKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.XECKey; +import java.security.interfaces.XECPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.NamedParameterSpec; +import java.security.spec.XECPublicKeySpec; +import java.util.Arrays; + +/** + * The DHasKEM class presents a KEM abstraction layer over traditional + * DH-based key exchange, which can be used for either straight + * ECDH/XDH or TLS hybrid key exchanges. + * + * This class can be alongside standard full post-quantum KEMs + * when hybrid implementations are required. + */ +public class DHasKEM implements KEMSpi { + + @Override + public EncapsulatorSpi engineNewEncapsulator( + PublicKey publicKey, AlgorithmParameterSpec spec, + SecureRandom secureRandom) throws InvalidKeyException { + return new Handler(publicKey, null, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, + AlgorithmParameterSpec spec) throws InvalidKeyException { + return new Handler(null, privateKey, null); + } + + private static final class Handler + implements KEMSpi.EncapsulatorSpi, KEMSpi.DecapsulatorSpi { + private final PublicKey pkR; + private final PrivateKey skR; + private final SecureRandom sr; + private final Params params; + + Handler(PublicKey pk, PrivateKey sk, SecureRandom sr) + throws InvalidKeyException { + this.pkR = pk; + this.skR = sk; + this.sr = sr; + this.params = paramsFromKey(pk == null ? sk : pk); + } + + @Override + public KEM.Encapsulated engineEncapsulate(int from, int to, + String algorithm) { + KeyPair kpE = params.generateKeyPair(sr); + PrivateKey skE = kpE.getPrivate(); + PublicKey pkE = kpE.getPublic(); + byte[] pkEm = params.SerializePublicKey(pkE); + try { + SecretKey dh = params.DH(algorithm, skE, pkR); + return new KEM.Encapsulated( + sub(dh, from, to), + pkEm, null); + + } catch (IllegalArgumentException e) { + // ECDH validation failure + // all-zero shared secret + throw e; + } catch (InvalidKeyException e) { + // Invalid peer public key + // Convert InvalidKeyException to an unchecked exception + throw new IllegalArgumentException("Invalid peer public key", + e); + } catch (Exception e) { + // Unexpected internal failure + throw new ProviderException("internal error", e); + } + } + + @Override + public int engineSecretSize() { + return params.secretLen; + } + + @Override + public int engineEncapsulationSize() { + return params.publicKeyLen; + } + + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, + int to, String algorithm) throws DecapsulateException { + if (encapsulation.length != params.publicKeyLen) { + throw new DecapsulateException("incorrect encapsulation size"); + } + try { + PublicKey pkE = params.DeserializePublicKey(encapsulation); + SecretKey dh = params.DH(algorithm, skR, pkE); + return sub(dh, from, to); + + } catch (IllegalArgumentException e) { + // ECDH validation failure + // all-zero shared secret + throw e; + } catch (IOException | InvalidKeyException e) { + throw new DecapsulateException("Cannot decapsulate", e); + } catch (Exception e) { + throw new ProviderException("internal error", e); + } + } + + private SecretKey sub(SecretKey key, int from, int to) { + if (from == 0 && to == params.secretLen) { + return key; + } + + // Key slicing should never happen. Otherwise, there might be + // a programming error. + throw new AssertionError( + "Unexpected key slicing: from=" + from + ", to=" + to); + } + + // This KEM is designed to be able to represent every ECDH and XDH + private Params paramsFromKey(Key k) throws InvalidKeyException { + if (k instanceof ECKey eckey) { + if (ECUtil.equals(eckey.getParams(), CurveDB.P_256)) { + return Params.P256; + } else if (ECUtil.equals(eckey.getParams(), CurveDB.P_384)) { + return Params.P384; + } else if (ECUtil.equals(eckey.getParams(), CurveDB.P_521)) { + return Params.P521; + } + } else if (k instanceof XECKey xkey + && xkey.getParams() instanceof NamedParameterSpec ns) { + if (ns.getName().equalsIgnoreCase( + NamedParameterSpec.X25519.getName())) { + return Params.X25519; + } else if (ns.getName().equalsIgnoreCase( + NamedParameterSpec.X448.getName())) { + return Params.X448; + } + } + throw new InvalidKeyException("Unsupported key"); + } + } + + private enum Params { + + P256(32, 2 * 32 + 1, + "ECDH", "EC", CurveDB.P_256), + + P384(48, 2 * 48 + 1, + "ECDH", "EC", CurveDB.P_384), + + P521(66, 2 * 66 + 1, + "ECDH", "EC", CurveDB.P_521), + + X25519(32, 32, + "XDH", "XDH", NamedParameterSpec.X25519), + + X448(56, 56, + "XDH", "XDH", NamedParameterSpec.X448); + + private final int secretLen; + private final int publicKeyLen; + private final String kaAlgorithm; + private final String keyAlgorithm; + private final AlgorithmParameterSpec spec; + + Params(int secretLen, int publicKeyLen, String kaAlgorithm, + String keyAlgorithm, AlgorithmParameterSpec spec) { + this.spec = spec; + this.secretLen = secretLen; + this.publicKeyLen = publicKeyLen; + this.kaAlgorithm = kaAlgorithm; + this.keyAlgorithm = keyAlgorithm; + } + + private boolean isEC() { + return this == P256 || this == P384 || this == P521; + } + + private KeyPair generateKeyPair(SecureRandom sr) { + try { + KeyPairGenerator g = KeyPairGenerator.getInstance(keyAlgorithm); + g.initialize(spec, sr); + return g.generateKeyPair(); + } catch (Exception e) { + throw new ProviderException("internal error", e); + } + } + + private byte[] SerializePublicKey(PublicKey k) { + if (isEC()) { + ECPoint w = ((ECPublicKey) k).getW(); + return ECUtil.encodePoint(w, ((NamedCurve) spec).getCurve()); + } else { + byte[] uArray = ((XECPublicKey) k).getU().toByteArray(); + ArrayUtil.reverse(uArray); + return Arrays.copyOf(uArray, publicKeyLen); + } + } + + private PublicKey DeserializePublicKey(byte[] data) throws + IOException, NoSuchAlgorithmException, + InvalidKeySpecException { + KeySpec keySpec; + if (isEC()) { + NamedCurve curve = (NamedCurve) this.spec; + keySpec = new ECPublicKeySpec( + ECUtil.decodePoint(data, curve.getCurve()), curve); + } else { + data = data.clone(); + ArrayUtil.reverse(data); + keySpec = new XECPublicKeySpec( + this.spec, new BigInteger(1, data)); + } + return KeyFactory.getInstance(keyAlgorithm). + generatePublic(keySpec); + } + + private SecretKey DH(String alg, PrivateKey skE, PublicKey pkR) + throws NoSuchAlgorithmException, InvalidKeyException { + KeyAgreement ka = KeyAgreement.getInstance(kaAlgorithm); + ka.init(skE); + ka.doPhase(pkR, true); + SecretKey secret = ka.generateSecret(alg); + + // RFC 8446 section 7.4.2: checks for all-zero + // X25519/X448 shared secret. + if (this == X25519 || this == X448) { + byte[] s = secret.getEncoded(); + byte data = 0; + for (byte b : s) { + data |= b; + } + if (data == 0) { + // Trigger ILLEGAL_PARAMETER alert + throw new IllegalArgumentException( + "All-zero shared secret"); + } + } + + return secret; + } + } +} diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/Hybrid.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/Hybrid.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/Hybrid.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/Hybrid.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import sun.security.util.ArrayUtil; +import sun.security.util.CurveDB; +import sun.security.util.ECUtil; +import sun.security.util.RawKeySpec; +import sun.security.x509.X509Key; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyFactorySpi; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyPairGeneratorSpi; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.*; +import java.util.Arrays; +import java.util.Locale; + +// The Hybrid class wraps two underlying algorithms (left and right sides) +// in a single TLS hybrid named group. +// It implements: +// - Hybrid KeyPair generation +// - Hybrid KeyFactory for decoding concatenated hybrid public keys +// - Hybrid KEM implementation for performing encapsulation and +// decapsulation over two underlying algorithms (traditional +// algorithm and post-quantum KEM algorithm) + +public class Hybrid { + + public static final NamedParameterSpec X25519_MLKEM768 = + new NamedParameterSpec("X25519MLKEM768"); + + public static final NamedParameterSpec SECP256R1_MLKEM768 = + new NamedParameterSpec("SecP256r1MLKEM768"); + + public static final NamedParameterSpec SECP384R1_MLKEM1024 = + new NamedParameterSpec("SecP384r1MLKEM1024"); + + private static AlgorithmParameterSpec getSpec(String name) { + if (name.startsWith("secp")) { + return new ECGenParameterSpec(name); + } else { + return new NamedParameterSpec(name); + } + } + + private static KeyPairGenerator getKeyPairGenerator(String name) throws + NoSuchAlgorithmException { + if (name.startsWith("secp")) { + name = "EC"; + } + return KeyPairGenerator.getInstance(name); + } + + private static KeyFactory getKeyFactory(String name) throws + NoSuchAlgorithmException { + if (name.startsWith("secp")) { + name = "EC"; + } + return KeyFactory.getInstance(name); + } + + /** + * Returns a KEM instance for each side of the hybrid algorithm. + * For traditional key exchange algorithms, we use the DH-based KEM + * implementation provided by DHasKEM class. + * For ML-KEM post-quantum algorithms, we obtain a KEM instance + * with "ML-KEM". This is done to work with 3rd-party providers that + * only have "ML-KEM" KEM algorithm. + */ + private static KEM getKEM(String name) throws NoSuchAlgorithmException { + if (name.startsWith("secp") || name.equals("X25519")) { + return KEM.getInstance("DH", HybridProvider.PROVIDER); + } else { + return KEM.getInstance("ML-KEM"); + } + } + + public static class KeyPairGeneratorImpl extends KeyPairGeneratorSpi { + private final KeyPairGenerator left; + private final KeyPairGenerator right; + private final AlgorithmParameterSpec leftSpec; + private final AlgorithmParameterSpec rightSpec; + + public KeyPairGeneratorImpl(String leftAlg, String rightAlg) + throws NoSuchAlgorithmException { + left = getKeyPairGenerator(leftAlg); + right = getKeyPairGenerator(rightAlg); + leftSpec = getSpec(leftAlg); + rightSpec = getSpec(rightAlg); + } + + @Override + public void initialize(AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException { + left.initialize(leftSpec, random); + right.initialize(rightSpec, random); + } + + @Override + public void initialize(int keysize, SecureRandom random) { + // NO-OP (do nothing) + } + + @Override + public KeyPair generateKeyPair() { + var kp1 = left.generateKeyPair(); + var kp2 = right.generateKeyPair(); + return new KeyPair( + new PublicKeyImpl("Hybrid", kp1.getPublic(), + kp2.getPublic()), + new PrivateKeyImpl("Hybrid", kp1.getPrivate(), + kp2.getPrivate())); + } + } + + public static class KeyFactoryImpl extends KeyFactorySpi { + private final KeyFactory left; + private final KeyFactory right; + private final int leftlen; + private final String leftname; + private final String rightname; + + public KeyFactoryImpl(String left, String right) + throws NoSuchAlgorithmException { + this.left = getKeyFactory(left); + this.right = getKeyFactory(right); + this.leftlen = leftPublicLength(left); + this.leftname = left; + this.rightname = right; + } + + @Override + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + if (keySpec == null) { + throw new InvalidKeySpecException("keySpec must not be null"); + } + + if (keySpec instanceof RawKeySpec rks) { + byte[] key = rks.getKeyArr(); + if (key == null) { + throw new InvalidKeySpecException( + "RawkeySpec contains null key data"); + } + if (key.length <= leftlen) { + throw new InvalidKeySpecException( + "Hybrid key length " + key.length + + " is too short and its left key length is " + + leftlen); + } + + byte[] leftKeyBytes = Arrays.copyOfRange(key, 0, leftlen); + byte[] rightKeyBytes = Arrays.copyOfRange(key, leftlen, + key.length); + PublicKey leftKey, rightKey; + + try { + if (leftname.startsWith("secp")) { + var curve = CurveDB.lookup(leftname); + var ecSpec = new ECPublicKeySpec( + ECUtil.decodePoint(leftKeyBytes, + curve.getCurve()), curve); + leftKey = left.generatePublic(ecSpec); + } else if (leftname.startsWith("ML-KEM")) { + leftKey = left.generatePublic(new RawKeySpec( + leftKeyBytes)); + } else { + throw new InvalidKeySpecException("Unsupported left" + + " algorithm" + leftname); + } + + if (rightname.equals("X25519")) { + ArrayUtil.reverse(rightKeyBytes); + var xecSpec = new XECPublicKeySpec( + new NamedParameterSpec(rightname), + new BigInteger(1, rightKeyBytes)); + rightKey = right.generatePublic(xecSpec); + } else if (rightname.startsWith("ML-KEM")) { + rightKey = right.generatePublic(new RawKeySpec( + rightKeyBytes)); + } else { + throw new InvalidKeySpecException("Unsupported right" + + " algorithm: " + rightname); + } + + return new PublicKeyImpl("Hybrid", leftKey, rightKey); + } catch (Exception e) { + throw new InvalidKeySpecException("Failed to decode " + + "hybrid key", e); + } + } + + throw new InvalidKeySpecException( + "KeySpec type:" + + keySpec.getClass().getName() + " not supported"); + } + + private static int leftPublicLength(String name) { + return switch (name.toLowerCase(Locale.ROOT)) { + case "secp256r1" -> 65; + case "secp384r1" -> 97; + case "ml-kem-768" -> 1184; + default -> throw new IllegalArgumentException( + "Unknown named group: " + name); + }; + } + + @Override + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws + InvalidKeySpecException { + throw new UnsupportedOperationException(); + } + + @Override + protected T engineGetKeySpec(Key key, + Class keySpec) throws InvalidKeySpecException { + throw new UnsupportedOperationException(); + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + throw new UnsupportedOperationException(); + } + } + + public static class KEMImpl implements KEMSpi { + private final KEM left; + private final KEM right; + + public KEMImpl(String left, String right) + throws NoSuchAlgorithmException { + this.left = getKEM(left); + this.right = getKEM(right); + } + + @Override + public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, + AlgorithmParameterSpec spec, SecureRandom secureRandom) throws + InvalidAlgorithmParameterException, InvalidKeyException { + if (publicKey instanceof PublicKeyImpl pk) { + return new Handler(left.newEncapsulator(pk.left, secureRandom), + right.newEncapsulator(pk.right, secureRandom), + null, null); + } + throw new InvalidKeyException(); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, + AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (privateKey instanceof PrivateKeyImpl pk) { + return new Handler(null, null, left.newDecapsulator(pk.left), + right.newDecapsulator(pk.right)); + } + throw new InvalidKeyException(); + } + } + + private static byte[] concat(byte[]... inputs) { + int outLen = 0; + for (byte[] in : inputs) { + outLen += in.length; + } + byte[] out = new byte[outLen]; + int pos = 0; + for (byte[] in : inputs) { + System.arraycopy(in, 0, out, pos, in.length); + pos += in.length; + } + return out; + } + + private record Handler(KEM.Encapsulator le, KEM.Encapsulator re, + KEM.Decapsulator ld, KEM.Decapsulator rd) + implements KEMSpi.EncapsulatorSpi, KEMSpi.DecapsulatorSpi { + @Override + public KEM.Encapsulated engineEncapsulate(int from, int to, + String algorithm) { + int expectedSecretSize = engineSecretSize(); + if (!(from == 0 && to == expectedSecretSize)) { + throw new IllegalArgumentException( + "Invalid range for encapsulation: from = " + from + + " to = " + to + ", expected total secret size = " + + expectedSecretSize); + } + + var left = le.encapsulate(); + var right = re.encapsulate(); + return new KEM.Encapsulated( + new SecretKeyImpl(left.key(), right.key()), + concat(left.encapsulation(), right.encapsulation()), + null); + } + + @Override + public int engineSecretSize() { + if (le != null) { + return le.secretSize() + re.secretSize(); + } else { + return ld.secretSize() + rd.secretSize(); + } + } + + @Override + public int engineEncapsulationSize() { + if (le != null) { + return le.encapsulationSize() + re.encapsulationSize(); + } else { + return ld.encapsulationSize() + rd.encapsulationSize(); + } + } + + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, + int to, String algorithm) throws DecapsulateException { + int expectedEncSize = engineEncapsulationSize(); + if (encapsulation.length != expectedEncSize) { + throw new DecapsulateException( + "Invalid key encapsulation message length: " + + encapsulation.length + + ", expected = " + expectedEncSize); + } + + int expectedSecretSize = engineSecretSize(); + if (!(from == 0 && to == expectedSecretSize)) { + throw new IllegalArgumentException( + "Invalid range for decapsulation: from = " + from + + " to = " + to + ", expected total secret size = " + + expectedSecretSize); + } + + var left = Arrays.copyOf(encapsulation, ld.encapsulationSize()); + var right = Arrays.copyOfRange(encapsulation, + ld.encapsulationSize(), encapsulation.length); + return new SecretKeyImpl( + ld.decapsulate(left), + rd.decapsulate(right) + ); + } + } + + // Package-private + record SecretKeyImpl(SecretKey k1, SecretKey k2) + implements SecretKey { + @Override + public String getAlgorithm() { + return "Generic"; + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return null; + } + } + + /** + * Hybrid public key combines two underlying public keys (left and right). + * Public keys can be transmitted/encoded because the hybrid protocol + * requires the public component to be sent. + */ + // Package-private + record PublicKeyImpl(String algorithm, PublicKey left, + PublicKey right) implements PublicKey { + @Override + public String getAlgorithm() { + return algorithm; + } + + // getFormat() returns "RAW" as hybrid key uses RAW concatenation + // of underlying encodings. + @Override + public String getFormat() { + return "RAW"; + } + + // getEncoded() returns the concatenation of the encoded bytes of the + // left and right public keys. + @Override + public byte[] getEncoded() { + return concat(onlyKey(left), onlyKey(right)); + } + + static byte[] onlyKey(PublicKey key) { + if (key instanceof X509Key xk) { + return xk.getKeyAsBytes(); + } + + // Fallback for 3rd-party providers + if (!"X.509".equalsIgnoreCase(key.getFormat())) { + throw new ProviderException("Invalid public key encoding " + + "format"); + } + var xk = new X509Key(); + try { + xk.decode(key.getEncoded()); + } catch (InvalidKeyException e) { + throw new ProviderException("Invalid public key encoding", e); + } + return xk.getKeyAsBytes(); + } + } + + /** + * Hybrid private key combines two underlying private keys (left and right). + * It is for internal use only. The private keys should never be exported. + */ + private record PrivateKeyImpl(String algorithm, PrivateKey left, + PrivateKey right) implements PrivateKey { + + @Override + public String getAlgorithm() { + return algorithm; + } + + // getFormat() returns null because there is no standard + // format for a hybrid private key. + @Override + public String getFormat() { + return null; + } + + // getEncoded() returns an empty byte array because there is no + // standard encoding format for a hybrid private key. + @Override + public byte[] getEncoded() { + return null; + } + } +} diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/HybridProvider.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/HybridProvider.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/HybridProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/HybridProvider.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.security.Provider; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Map; + +import static sun.security.util.SecurityConstants.PROVIDER_VER; + +// This is an internal provider used in the JSSE code for DH-as-KEM +// and Hybrid KEM support. It doesn't actually get installed in the +// system's list of security providers that is searched at runtime. +// JSSE loads this provider internally. +// It registers Hybrid KeyPairGenerator, KeyFactory, and KEM +// implementations for hybrid named groups as Provider services. + +public class HybridProvider { + + public static final Provider PROVIDER = new ProviderImpl(); + + private static final class ProviderImpl extends Provider { + @java.io.Serial + private static final long serialVersionUID = 0L; + + ProviderImpl() { + super("HybridAndDHAsKEM", PROVIDER_VER, + "Hybrid and DHAsKEM provider"); + put("KEM.DH", DHasKEM.class.getName()); + + // Hybrid KeyPairGenerator/KeyFactory/KEM + + // The order of shares in the concatenation for group name + // X25519MLKEM768 has been reversed as per the current + // draft RFC. + var attrs = Map.of("name", "X25519MLKEM768", "left", "ML-KEM-768", + "right", "X25519"); + putService(new HybridService(this, "KeyPairGenerator", + "X25519MLKEM768", + "sun.security.ssl.Hybrid$KeyPairGeneratorImpl", + null, attrs)); + putService(new HybridService(this, "KEM", + "X25519MLKEM768", + "sun.security.ssl.Hybrid$KEMImpl", + null, attrs)); + putService(new HybridService(this, "KeyFactory", + "X25519MLKEM768", + "sun.security.ssl.Hybrid$KeyFactoryImpl", + null, attrs)); + + attrs = Map.of("name", "SecP256r1MLKEM768", "left", "secp256r1", + "right", "ML-KEM-768"); + putService(new HybridService(this, "KeyPairGenerator", + "SecP256r1MLKEM768", + "sun.security.ssl.Hybrid$KeyPairGeneratorImpl", + null, attrs)); + putService(new HybridService(this, "KEM", + "SecP256r1MLKEM768", + "sun.security.ssl.Hybrid$KEMImpl", + null, attrs)); + putService(new HybridService(this, "KeyFactory", + "SecP256r1MLKEM768", + "sun.security.ssl.Hybrid$KeyFactoryImpl", + null, attrs)); + + attrs = Map.of("name", "SecP384r1MLKEM1024", "left", "secp384r1", + "right", "ML-KEM-1024"); + putService(new HybridService(this, "KeyPairGenerator", + "SecP384r1MLKEM1024", + "sun.security.ssl.Hybrid$KeyPairGeneratorImpl", + null, attrs)); + putService(new HybridService(this, "KEM", + "SecP384r1MLKEM1024", + "sun.security.ssl.Hybrid$KEMImpl", + null, attrs)); + putService(new HybridService(this, "KeyFactory", + "SecP384r1MLKEM1024", + "sun.security.ssl.Hybrid$KeyFactoryImpl", + null, attrs)); + } + } + + private static class HybridService extends Provider.Service { + + HybridService(Provider p, String type, String algo, String cn, + List aliases, Map attrs) { + super(p, type, algo, cn, aliases, attrs); + } + + @Override + public Object newInstance(Object ctrParamObj) + throws NoSuchAlgorithmException { + String type = getType(); + return switch (type) { + case "KeyPairGenerator" -> new Hybrid.KeyPairGeneratorImpl( + getAttribute("left"), getAttribute("right")); + case "KeyFactory" -> new Hybrid.KeyFactoryImpl( + getAttribute("left"), getAttribute("right")); + case "KEM" -> new Hybrid.KEMImpl( + getAttribute("left"), getAttribute("right")); + default -> throw new NoSuchAlgorithmException( + "Unexpected value: " + type); + }; + } + } +} diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,11 @@ */ package sun.security.ssl; +import sun.security.util.RawKeySpec; + +import javax.crypto.DecapsulateException; import javax.crypto.KDF; +import javax.crypto.KEM; import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; import javax.crypto.spec.HKDFParameterSpec; @@ -32,9 +36,12 @@ import java.io.IOException; import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; import java.security.PrivateKey; +import java.security.Provider; import java.security.PublicKey; -import java.security.spec.AlgorithmParameterSpec; +import java.security.SecureRandom; import sun.security.util.KeyUtil; /** @@ -46,15 +53,32 @@ private final HandshakeContext context; private final PrivateKey localPrivateKey; private final PublicKey peerPublicKey; + private final byte[] keyshare; + private final Provider provider; + // Constructor called by Key Agreement KAKeyDerivation(String algorithmName, HandshakeContext context, PrivateKey localPrivateKey, PublicKey peerPublicKey) { + this(algorithmName, null, context, localPrivateKey, + peerPublicKey, null); + } + + // When the constructor called by KEM: store the client's public key or the + // encapsulated message in keyshare. + KAKeyDerivation(String algorithmName, + NamedGroup namedGroup, + HandshakeContext context, + PrivateKey localPrivateKey, + PublicKey peerPublicKey, + byte[] keyshare) { this.algorithmName = algorithmName; this.context = context; this.localPrivateKey = localPrivateKey; this.peerPublicKey = peerPublicKey; + this.keyshare = keyshare; + this.provider = (namedGroup != null) ? namedGroup.getProvider() : null; } @Override @@ -94,22 +118,15 @@ } } - /** - * Handle the TLSv1.3 objects, which use the HKDF algorithms. - */ - private SecretKey t13DeriveKey(String type) - throws IOException { - SecretKey sharedSecret = null; + private SecretKey deriveHandshakeSecret(String label, + SecretKey sharedSecret) + throws GeneralSecurityException, IOException { SecretKey earlySecret = null; SecretKey saltSecret = null; - try { - KeyAgreement ka = KeyAgreement.getInstance(algorithmName); - ka.init(localPrivateKey); - ka.doPhase(peerPublicKey, true); - sharedSecret = ka.generateSecret("TlsPremasterSecret"); - CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; - SSLKeyDerivation kd = context.handshakeKeyDerivation; + CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; + SSLKeyDerivation kd = context.handshakeKeyDerivation; + try { if (kd == null) { // No PSK is in use. // If PSK is not in use, Early Secret will still be // HKDF-Extract(0, 0). @@ -129,12 +146,121 @@ // the handshake secret key derivation (below) as it may not // work with the "sharedSecret" obj. KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); - return hkdf.deriveKey(type, HKDFParameterSpec.ofExtract() - .addSalt(saltSecret).addIKM(sharedSecret).extractOnly()); + var spec = HKDFParameterSpec.ofExtract().addSalt(saltSecret); + if (sharedSecret instanceof Hybrid.SecretKeyImpl hsk) { + spec = spec.addIKM(hsk.k1()).addIKM(hsk.k2()); + } else { + spec = spec.addIKM(sharedSecret); + } + + return hkdf.deriveKey(label, spec.extractOnly()); + } finally { + KeyUtil.destroySecretKeys(earlySecret, saltSecret); + } + } + /** + * This method is called by the server to perform KEM encapsulation. + * It uses the client's public key (sent by the client as a keyshare) + * to encapsulate a shared secret and returns the encapsulated message. + * + * Package-private, used from KeyShareExtension.SHKeyShareProducer:: + * produce(). + */ + KEM.Encapsulated encapsulate(String algorithm, SecureRandom random) + throws IOException { + SecretKey sharedSecret = null; + + if (keyshare == null) { + throw new IOException("No keyshare available for KEM " + + "encapsulation"); + } + + // All exceptions thrown during KEM encapsulation are mapped + // to TLS fatal alerts: + // illegal_parameter alert or internal_error alert. + try { + KeyFactory kf = (provider != null) ? + KeyFactory.getInstance(algorithmName, provider) : + KeyFactory.getInstance(algorithmName); + var pk = kf.generatePublic(new RawKeySpec(keyshare)); + + KEM kem = (provider != null) ? + KEM.getInstance(algorithmName, provider) : + KEM.getInstance(algorithmName); + KEM.Encapsulator e = kem.newEncapsulator(pk, random); + KEM.Encapsulated enc = e.encapsulate(); + sharedSecret = enc.key(); + + SecretKey derived = deriveHandshakeSecret(algorithm, sharedSecret); + + return new KEM.Encapsulated(derived, enc.encapsulation(), null); + } catch (IllegalArgumentException | InvalidKeyException e) { + // Peer validation failure + // ECDH all-zero shared secret (RFC 8446 section 7.4.2), + // ML-KEM encapsulation key check failure (FIPS-203 section 7.2) + throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER, e); + } catch (GeneralSecurityException e) { + // Cryptographic failure, + // deriveHandshakeSecret failure. + throw context.conContext.fatal(Alert.INTERNAL_ERROR, e); + } catch (RuntimeException e) { + // unexpected provider/runtime failure + throw context.conContext.fatal(Alert.INTERNAL_ERROR, e); + } finally { + KeyUtil.destroySecretKeys(sharedSecret); + } + } + + /** + * Handle the TLSv1.3 objects, which use the HKDF algorithms. + */ + private SecretKey t13DeriveKey(String type) + throws IOException { + SecretKey sharedSecret = null; + + try { + if (keyshare != null) { + // Using KEM: called by the client after receiving the KEM + // ciphertext (keyshare) from the server in ServerHello. + // The client decapsulates it using its private key. + + // All exceptions thrown during KEM decapsulation are mapped + // to TLS fatal alerts: + // illegal_parameter alert or internal_error alert. + try { + KEM kem = (provider != null) + ? KEM.getInstance(algorithmName, provider) + : KEM.getInstance(algorithmName); + var decapsulator = kem.newDecapsulator(localPrivateKey); + sharedSecret = decapsulator.decapsulate( + keyshare, 0, decapsulator.secretSize(), + "TlsPremasterSecret"); + } catch (IllegalArgumentException | InvalidKeyException | + DecapsulateException e) { + // Peer validation failure + // ECDH all-zero shared secret (RFC 8446 section 7.4.2) + throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER, e); + } catch (GeneralSecurityException e) { + // cryptographic failure + throw context.conContext.fatal(Alert.INTERNAL_ERROR, e); + } catch (RuntimeException e) { + // unexpected provider/runtime failure + throw context.conContext.fatal(Alert.INTERNAL_ERROR, e); + } + } else { + // Using traditional DH-style Key Agreement + KeyAgreement ka = KeyAgreement.getInstance(algorithmName); + ka.init(localPrivateKey); + ka.doPhase(peerPublicKey, true); + sharedSecret = ka.generateSecret("TlsPremasterSecret"); + } + + return deriveHandshakeSecret(type, sharedSecret); } catch (GeneralSecurityException gse) { + // deriveHandshakeSecret() failure throw new SSLHandshakeException("Could not generate secret", gse); } finally { - KeyUtil.destroySecretKeys(sharedSecret, earlySecret, saltSecret); + KeyUtil.destroySecretKeys(sharedSecret); } } } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/KEMKeyExchange.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/KEMKeyExchange.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/KEMKeyExchange.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/KEMKeyExchange.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.security.ssl; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.NamedParameterSpec; +import javax.crypto.SecretKey; + +import sun.security.ssl.NamedGroup.NamedGroupSpec; +import sun.security.x509.X509Key; + +/** + * Specifics for single or hybrid Key exchanges based on KEM + */ +final class KEMKeyExchange { + + static final SSLKeyAgreementGenerator kemKAGenerator + = new KEMKAGenerator(); + + static final class KEMCredentials implements NamedGroupCredentials { + + final NamedGroup namedGroup; + // Unlike other credentials, we directly store the key share + // value here, no need to convert to a key + private final byte[] keyshare; + + KEMCredentials(byte[] keyshare, NamedGroup namedGroup) { + this.keyshare = keyshare; + this.namedGroup = namedGroup; + } + + // For KEM, server performs encapsulation and the resulting + // encapsulated message becomes the key_share value sent to + // the client. It is not a public key, so no PublicKey object + // to return. + @Override + public PublicKey getPublicKey() { + throw new UnsupportedOperationException( + "KEMCredentials stores raw keyshare, not a PublicKey"); + } + + public byte[] getKeyShare() { + return keyshare; + } + + @Override + public NamedGroup getNamedGroup() { + return namedGroup; + } + + /** + * Instantiates a KEMCredentials object + */ + static KEMCredentials valueOf(NamedGroup namedGroup, + byte[] encodedPoint) { + + if (namedGroup.spec != NamedGroupSpec.NAMED_GROUP_KEM) { + throw new RuntimeException( + "Credentials decoding: Not KEM named group"); + } + + if (encodedPoint == null || encodedPoint.length == 0) { + return null; + } + + return new KEMCredentials(encodedPoint, namedGroup); + } + } + + private static class KEMPossession implements SSLPossession { + private final NamedGroup namedGroup; + + public KEMPossession(NamedGroup ng) { + this.namedGroup = ng; + } + public NamedGroup getNamedGroup() { + return namedGroup; + } + } + + static final class KEMReceiverPossession extends KEMPossession { + + private final PrivateKey privateKey; + private final PublicKey publicKey; + + KEMReceiverPossession(NamedGroup namedGroup, SecureRandom random) { + super(namedGroup); + String algName = null; + try { + // For KEM: This receiver side (client) generates a key pair. + algName = ((NamedParameterSpec)namedGroup.keAlgParamSpec). + getName(); + Provider provider = namedGroup.getProvider(); + KeyPairGenerator kpg = (provider != null) ? + KeyPairGenerator.getInstance(algName, provider) : + KeyPairGenerator.getInstance(algName); + + kpg.initialize(namedGroup.keAlgParamSpec, random); + KeyPair kp = kpg.generateKeyPair(); + privateKey = kp.getPrivate(); + publicKey = kp.getPublic(); + } catch (GeneralSecurityException e) { + throw new RuntimeException( + "Could not generate keypair for algorithm: " + + algName, e); + } + } + + @Override + public byte[] encode() { + if (publicKey instanceof X509Key xk) { + return xk.getKeyAsBytes(); + } else if (publicKey instanceof Hybrid.PublicKeyImpl hk) { + return hk.getEncoded(); + } + throw new ProviderException("Unsupported key type: " + publicKey); + } + + // Package-private + PublicKey getPublicKey() { + return publicKey; + } + + // Package-private + PrivateKey getPrivateKey() { + return privateKey; + } + } + + static final class KEMSenderPossession extends KEMPossession { + + private SecretKey key; + private final SecureRandom random; + + KEMSenderPossession(NamedGroup namedGroup, SecureRandom random) { + super(namedGroup); + this.random = random; + } + + // Package-private + SecureRandom getRandom() { + return random; + } + + // Package-private + SecretKey getKey() { + return key; + } + + // Package-private + void setKey(SecretKey key) { + this.key = key; + } + + @Override + public byte[] encode() { + throw new UnsupportedOperationException("encode() not supported"); + } + } + + private static final class KEMKAGenerator + implements SSLKeyAgreementGenerator { + + // Prevent instantiation of this class. + private KEMKAGenerator() { + // blank + } + + @Override + public SSLKeyDerivation createKeyDerivation( + HandshakeContext context) throws IOException { + for (SSLPossession poss : context.handshakePossessions) { + if (poss instanceof KEMReceiverPossession kposs) { + NamedGroup ng = kposs.getNamedGroup(); + for (SSLCredentials cred : context.handshakeCredentials) { + if (cred instanceof KEMCredentials kcred && + ng.equals(kcred.namedGroup)) { + String name = ((NamedParameterSpec) + ng.keAlgParamSpec).getName(); + return new KAKeyDerivation(name, ng, context, + kposs.getPrivateKey(), null, + kcred.getKeyShare()); + } + } + } + } + context.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No suitable KEM key agreement " + + "parameters negotiated"); + return null; + } + } +} diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,11 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.security.AlgorithmConstraints; import java.security.CryptoPrimitive; import java.security.GeneralSecurityException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; import java.text.MessageFormat; import java.util.*; import javax.net.ssl.SSLProtocolException; @@ -46,7 +49,7 @@ new CHKeyShareProducer(); static final ExtensionConsumer chOnLoadConsumer = new CHKeyShareConsumer(); - static final HandshakeAbsence chOnTradAbsence = + static final HandshakeAbsence chOnTradeAbsence = new CHKeyShareOnTradeAbsence(); static final SSLStringizer chStringizer = new CHKeyShareStringizer(); @@ -297,7 +300,9 @@ // update the context chc.handshakePossessions.add(pos); // May need more possession types in the future. - if (pos instanceof NamedGroupPossession) { + if (pos instanceof NamedGroupPossession || + pos instanceof + KEMKeyExchange.KEMReceiverPossession) { return pos.encode(); } } @@ -358,24 +363,16 @@ try { SSLCredentials kaCred = ng.decodeCredentials(entry.keyExchange); - if (shc.algorithmConstraints != null && - kaCred instanceof - NamedGroupCredentials namedGroupCredentials) { - if (!shc.algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - namedGroupCredentials.getPublicKey())) { - if (SSLLogger.isOn && - SSLLogger.isOn("ssl,handshake")) { - SSLLogger.warning( - "key share entry of " + ng + " does not " + - " comply with algorithm constraints"); - } - kaCred = null; + if (!isCredentialPermitted(shc.algorithmConstraints, + kaCred)) { + if (SSLLogger.isOn && + SSLLogger.isOn("ssl,handshake")) { + SSLLogger.warning( + "key share entry of " + ng + " does not " + + "comply with algorithm constraints"); } - } - - if (kaCred != null) { + } else { credentials.add(kaCred); } } catch (GeneralSecurityException ex) { @@ -513,7 +510,8 @@ @Override public byte[] produce(ConnectionContext context, HandshakeMessage message) throws IOException { - // The producing happens in client side only. + // The producing happens in server side only. + ServerHandshakeContext shc = (ServerHandshakeContext)context; // In response to key_share request only @@ -571,7 +569,9 @@ SSLPossession[] poses = ke.createPossessions(shc); for (SSLPossession pos : poses) { - if (!(pos instanceof NamedGroupPossession)) { + if (!(pos instanceof NamedGroupPossession || + pos instanceof + KEMKeyExchange.KEMSenderPossession)) { // May need more possession types in the future. continue; } @@ -579,7 +579,34 @@ // update the context shc.handshakeKeyExchange = ke; shc.handshakePossessions.add(pos); - keyShare = new KeyShareEntry(ng.id, pos.encode()); + + // For KEM, perform encapsulation using the client’s public + // key (KEMCredentials). The resulting encapsulated message + // becomes the key_share value sent to the client. The + // shared secret derived from encapsulation is stored in + // the KEMSenderPossession for later use in the TLS key + // schedule. + + // SSLKeyExchange.createPossessions() returns at most one + // key-agreement possession or one KEMSenderPossession + // per handshake. + if (pos instanceof KEMKeyExchange.KEMSenderPossession xp) { + if (cd instanceof KEMKeyExchange.KEMCredentials kcred + && ng.equals(kcred.namedGroup)) { + String name = ((NamedParameterSpec) + ng.keAlgParamSpec).getName(); + KAKeyDerivation handshakeKD = new KAKeyDerivation( + name, ng, shc, null, null, + kcred.getKeyShare()); + var encaped = handshakeKD.encapsulate( + "TlsHandshakeSecret", xp.getRandom()); + xp.setKey(encaped.key()); + keyShare = new KeyShareEntry(ng.id, + encaped.encapsulation()); + } + } else { + keyShare = new KeyShareEntry(ng.id, pos.encode()); + } break; } @@ -663,19 +690,13 @@ try { SSLCredentials kaCred = ng.decodeCredentials(keyShare.keyExchange); - if (chc.algorithmConstraints != null && - kaCred instanceof - NamedGroupCredentials namedGroupCredentials) { - if (!chc.algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - namedGroupCredentials.getPublicKey())) { - chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, - "key share entry of " + ng + " does not " + - " comply with algorithm constraints"); - } - } - if (kaCred != null) { + if (!isCredentialPermitted(chc.algorithmConstraints, + kaCred)) { + chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, + "key share entry of " + ng + " does not " + + "comply with algorithm constraints"); + } else { credentials = kaCred; } } catch (GeneralSecurityException ex) { @@ -696,6 +717,34 @@ } } + private static boolean isCredentialPermitted( + AlgorithmConstraints constraints, + SSLCredentials cred) { + + if (constraints == null) return true; + if (cred == null) return false; + + if (cred instanceof NamedGroupCredentials namedGroupCred) { + if (namedGroupCred instanceof KEMKeyExchange.KEMCredentials + kemCred) { + AlgorithmParameterSpec paramSpec = kemCred.getNamedGroup(). + keAlgParamSpec; + String algName = (paramSpec instanceof NamedParameterSpec nps) ? + nps.getName() : null; + return algName != null && constraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + algName, + null); + } else { + return constraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCred.getPublicKey()); + } + } + + return true; + } + /** * The absence processing if the extension is not present in * the ServerHello handshake message. diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/NamedGroup.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/NamedGroup.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/NamedGroup.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/NamedGroup.java 2026-10-19 12:10:20.000000000 +0000 @@ -214,6 +214,39 @@ ProtocolVersion.PROTOCOLS_TO_13, PredefinedDHParameterSpecs.ffdheParams.get(8192)), + ML_KEM_512(0x0200, "MLKEM512", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + null), + + ML_KEM_768(0x0201, "MLKEM768", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + null), + + ML_KEM_1024(0x0202, "MLKEM1024", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + null), + + X25519MLKEM768(0x11ec, "X25519MLKEM768", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + Hybrid.X25519_MLKEM768, + HybridProvider.PROVIDER), + + SECP256R1MLKEM768(0x11eb, "SecP256r1MLKEM768", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + Hybrid.SECP256R1_MLKEM768, + HybridProvider.PROVIDER), + + SECP384R1MLKEM1024(0x11ed, "SecP384r1MLKEM1024", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + Hybrid.SECP384R1_MLKEM1024, + HybridProvider.PROVIDER), + // Elliptic Curves (RFC 4492) // // arbitrary prime and characteristic-2 curves @@ -234,22 +267,33 @@ final AlgorithmParameterSpec keAlgParamSpec; final AlgorithmParameters keAlgParams; final boolean isAvailable; + final Provider defaultProvider; // performance optimization private static final Set KEY_AGREEMENT_PRIMITIVE_SET = Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT)); - // Constructor used for all NamedGroup types NamedGroup(int id, String name, NamedGroupSpec namedGroupSpec, ProtocolVersion[] supportedProtocols, AlgorithmParameterSpec keAlgParamSpec) { + this(id, name, namedGroupSpec, supportedProtocols, keAlgParamSpec, + null); + } + + // Constructor used for all NamedGroup types + NamedGroup(int id, String name, + NamedGroupSpec namedGroupSpec, + ProtocolVersion[] supportedProtocols, + AlgorithmParameterSpec keAlgParamSpec, + Provider defaultProvider) { this.id = id; this.name = name; this.spec = namedGroupSpec; this.algorithm = namedGroupSpec.algorithm; this.supportedProtocols = supportedProtocols; this.keAlgParamSpec = keAlgParamSpec; + this.defaultProvider = defaultProvider; // Check if it is a supported named group. AlgorithmParameters algParams = null; @@ -266,16 +310,28 @@ // Check the specific algorithm parameters. if (mediator) { try { - algParams = - AlgorithmParameters.getInstance(namedGroupSpec.algorithm); - algParams.init(keAlgParamSpec); + // Skip AlgorithmParameters for KEMs (not supported) + // Check KEM's availability via KeyFactory + if (namedGroupSpec == NamedGroupSpec.NAMED_GROUP_KEM) { + if (defaultProvider == null) { + KeyFactory.getInstance(name); + } else { + KeyFactory.getInstance(name, defaultProvider); + } + } else { + // ECDHE or others: use AlgorithmParameters as before + algParams = AlgorithmParameters.getInstance( + namedGroupSpec.algorithm); + algParams.init(keAlgParamSpec); + } } catch (InvalidParameterSpecException | NoSuchAlgorithmException exp) { if (namedGroupSpec != NamedGroupSpec.NAMED_GROUP_XDH) { mediator = false; if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( - "No AlgorithmParameters for " + name, exp); + "No AlgorithmParameters or KeyFactory for " + name, + exp); } } else { // Please remove the following code if the XDH/X25519/X448 @@ -307,6 +363,10 @@ this.keAlgParams = mediator ? algParams : null; } + Provider getProvider() { + return defaultProvider; + } + // // The next set of methods search & retrieve NamedGroups. // @@ -545,6 +605,10 @@ return spec.decodeCredentials(this, encoded); } + SSLPossession createPossession(boolean isClient, SecureRandom random) { + return spec.createPossession(this, isClient, random); + } + SSLPossession createPossession(SecureRandom random) { return spec.createPossession(this, random); } @@ -566,6 +630,11 @@ SSLKeyDerivation createKeyDerivation( HandshakeContext hc) throws IOException; + + default SSLPossession createPossession(NamedGroup ng, boolean isClient, + SecureRandom random) { + return createPossession(ng, random); + } } enum NamedGroupSpec implements NamedGroupScheme { @@ -578,6 +647,10 @@ // Finite Field Groups (XDH) NAMED_GROUP_XDH("XDH", XDHScheme.instance), + // Post-Quantum Cryptography (PQC) KEM groups + // Currently used for hybrid named groups + NAMED_GROUP_KEM("KEM", KEMScheme.instance), + // arbitrary prime and curves (ECDHE) NAMED_GROUP_ARBITRARY("EC", null), @@ -634,6 +707,15 @@ return null; } + public SSLPossession createPossession( + NamedGroup ng, boolean isClient, SecureRandom random) { + if (scheme != null) { + return scheme.createPossession(ng, isClient, random); + } + + return null; + } + @Override public SSLPossession createPossession( NamedGroup ng, SecureRandom random) { @@ -739,6 +821,42 @@ } } + private static class KEMScheme implements NamedGroupScheme { + private static final KEMScheme instance = new KEMScheme(); + + @Override + public byte[] encodePossessionPublicKey(NamedGroupPossession poss) { + return poss.encode(); + } + + @Override + public SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException { + return KEMKeyExchange.KEMCredentials.valueOf(ng, encoded); + } + + @Override + public SSLPossession createPossession(NamedGroup ng, + SecureRandom random) { + // Must call createPossession with isClient + throw new UnsupportedOperationException(); + } + + @Override + public SSLPossession createPossession( + NamedGroup ng, boolean isClient, SecureRandom random) { + return isClient + ? new KEMKeyExchange.KEMReceiverPossession(ng, random) + : new KEMKeyExchange.KEMSenderPossession(ng, random); + } + + @Override + public SSLKeyDerivation createKeyDerivation( + HandshakeContext hc) throws IOException { + return KEMKeyExchange.kemKAGenerator.createKeyDerivation(hc); + } + } + static final class SupportedGroups { // the supported named groups, non-null immutable list static final String[] namedGroups; @@ -784,6 +902,9 @@ } else { // default groups NamedGroup[] groups = new NamedGroup[] { + // Hybrid key agreement + X25519MLKEM768, + // Primary XDH (RFC 7748) curves X25519, diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java 2026-10-19 12:10:20.000000000 +0000 @@ -58,7 +58,7 @@ new CHPreSharedKeyOnLoadAbsence(); static final HandshakeConsumer chOnTradeConsumer = new CHPreSharedKeyUpdate(); - static final HandshakeAbsence chOnTradAbsence = + static final HandshakeAbsence chOnTradeAbsence = new CHPreSharedKeyOnTradeAbsence(); static final SSLStringizer chStringizer = new CHPreSharedKeyStringizer(); diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmDecomposer.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmDecomposer.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmDecomposer.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmDecomposer.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -172,9 +173,18 @@ case B_AES_128_GCM: components.add("AES_128_GCM"); break; + case B_AES_128_GCM_IV: + components.add("AES_128_GCM"); + break; case B_AES_256_GCM: components.add("AES_256_GCM"); break; + case B_AES_256_GCM_IV: + components.add("AES_256_GCM"); + break; + case B_CC20_P1305: + components.add("CHACHA20_POLY1305"); + break; } return components; diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SSLExtension.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLExtension.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SSLExtension.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLExtension.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -142,7 +142,7 @@ SupportedGroupsExtension.chOnLoadConsumer, null, null, - SupportedGroupsExtension.chOnTradAbsence, + SupportedGroupsExtension.chOnTradeAbsence, SupportedGroupsExtension.sgsStringizer), EE_SUPPORTED_GROUPS (0x000A, "supported_groups", SSLHandshake.ENCRYPTED_EXTENSIONS, @@ -433,7 +433,7 @@ KeyShareExtension.chOnLoadConsumer, null, null, - KeyShareExtension.chOnTradAbsence, + KeyShareExtension.chOnTradeAbsence, KeyShareExtension.chStringizer), SH_KEY_SHARE (0x0033, "key_share", SSLHandshake.SERVER_HELLO, @@ -486,7 +486,7 @@ PreSharedKeyExtension.chOnLoadConsumer, PreSharedKeyExtension.chOnLoadAbsence, PreSharedKeyExtension.chOnTradeConsumer, - PreSharedKeyExtension.chOnTradAbsence, + PreSharedKeyExtension.chOnTradeAbsence, PreSharedKeyExtension.chStringizer), SH_PRE_SHARED_KEY (0x0029, "pre_shared_key", SSLHandshake.SERVER_HELLO, diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -68,8 +68,17 @@ } encodedLength = len + 2; // 2: the length of the extensions. + Set extIdSet = new HashSet<>(); // To check for duplicates. + while (len > 0) { int extId = Record.getInt16(m); + + if (!extIdSet.add(extId)) { + throw hm.handshakeContext.conContext.fatal( + Alert.ILLEGAL_PARAMETER, + "Duplicate extension with ID: " + extId); + } + int extLen = Record.getInt16(m); if (extLen > m.remaining()) { throw hm.handshakeContext.conContext.fatal( diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -570,7 +570,9 @@ @Override public SSLPossession createPossession(HandshakeContext hc) { - return namedGroup.createPossession(hc.sslContext.getSecureRandom()); + return namedGroup.createPossession( + hc instanceof ClientHandshakeContext, + hc.sslContext.getSecureRandom()); } @Override diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java 2026-10-19 12:10:20.000000000 +0000 @@ -29,13 +29,11 @@ import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.security.ProviderException; -import java.security.spec.AlgorithmParameterSpec; import javax.crypto.KDF; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.HKDFParameterSpec; import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.SSLHandshakeException; import sun.security.internal.spec.TlsKeyMaterialParameterSpec; import sun.security.internal.spec.TlsKeyMaterialSpec; @@ -191,26 +189,26 @@ private enum KeySchedule { // Note that we use enum name as the key name. - TlsKey ("key", false), - TlsIv ("iv", true), - TlsUpdateNplus1 ("traffic upd", false); + TlsKey ("key"), + TlsIv ("iv"), + TlsUpdateNplus1 ("traffic upd"); private final byte[] label; - private final boolean isIv; - KeySchedule(String label, boolean isIv) { + KeySchedule(String label) { this.label = ("tls13 " + label).getBytes(); - this.isIv = isIv; } int getKeyLength(CipherSuite cs) { - if (this == KeySchedule.TlsUpdateNplus1) - return cs.hashAlg.hashLength; - return isIv ? cs.bulkCipher.ivSize : cs.bulkCipher.keySize; + return switch (this) { + case TlsUpdateNplus1 -> cs.hashAlg.hashLength; + case TlsIv -> cs.bulkCipher.ivSize; + case TlsKey -> cs.bulkCipher.keySize; + }; } String getAlgorithm(CipherSuite cs, String algorithm) { - return isIv ? algorithm : cs.bulkCipher.algorithm; + return this == TlsKey ? cs.bulkCipher.algorithm : algorithm; } } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/ServerHello.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/ServerHello.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/ServerHello.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/ServerHello.java 2026-10-19 12:10:20.000000000 +0000 @@ -563,6 +563,34 @@ clientHello); shc.serverHelloRandom = shm.serverRandom; + // For key derivation, we will either use the traditional Key + // Agreement (KA) model or the Key Encapsulation Mechanism (KEM) + // model, depending on what key exchange group is used. + // + // For KA flows, the server first receives the client's share, + // then generates its key share, and finally comes here. + // However, this is changed for KEM: the server + // must perform both actions — derive the secret and generate + // the key encapsulation message at the same time during + // encapsulation in SHKeyShareProducer. + // + // Traditional Key Agreement (KA): + // - Both peers generate a key share and exchange it. + // - Each peer computes a shared secret sometime after + // receiving the other's key share. + // + // Key Encapsulation Mechanism (KEM): + // The client publishes a public key via a KeyShareExtension, + // which the server uses to: + // + // - generate the shared secret + // - encapsulate the message which is sent to the client in + // another KeyShareExtension + // + // The derived shared secret must be stored in a + // KEMSenderPossession so it can be retrieved for handshake + // traffic secret derivation later. + // Produce extensions for ServerHello handshake message. SSLExtension[] serverHelloExtensions = shc.sslConfig.getEnabledExtensions( @@ -588,9 +616,26 @@ "Not negotiated key shares"); } - SSLKeyDerivation handshakeKD = ke.createKeyDerivation(shc); - SecretKey handshakeSecret = handshakeKD.deriveKey( - "TlsHandshakeSecret"); + SecretKey handshakeSecret = null; + + // For KEM, the shared secret has already been generated and + // stored in the server’s possession (KEMSenderPossession) + // during encapsulation in SHKeyShareProducer. + // + // Only one key share is selected by the server, so at most one + // possession will contain the pre-derived shared secret. + for (var pos : shc.handshakePossessions) { + if (pos instanceof KEMKeyExchange.KEMSenderPossession xp) { + handshakeSecret = xp.getKey(); + break; + } + } + + if (handshakeSecret == null) { + SSLKeyDerivation handshakeKD = ke.createKeyDerivation(shc); + handshakeSecret = handshakeKD.deriveKey( + "TlsHandshakeSecret"); + } SSLTrafficKeyDerivation kdg = SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol); diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java 2026-10-19 12:10:20.000000000 +0000 @@ -278,8 +278,10 @@ aad.putInt(keyID).put(compressed); c.updateAAD(aad); + // use getOutputSize to avoid a ShortBufferException + // from providers that require oversized buffers. See JDK-8368514. ByteBuffer out = ByteBuffer.allocate( - data.remaining() - GCM_TAG_LEN / 8); + c.getOutputSize(data.remaining())); c.doFinal(data, out); out.flip(); @@ -291,7 +293,7 @@ return out; } catch (Exception e) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine("Decryption failed." + e.getMessage()); + SSLLogger.fine("Decryption failed." + e); } } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ new CHSupportedGroupsProducer(); static final ExtensionConsumer chOnLoadConsumer = new CHSupportedGroupsConsumer(); - static final HandshakeAbsence chOnTradAbsence = + static final HandshakeAbsence chOnTradeAbsence = new CHSupportedGroupsOnTradeAbsence(); static final SSLStringizer sgsStringizer = new SupportedGroupsStringizer(); diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/util/HostnameChecker.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/HostnameChecker.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/util/HostnameChecker.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/HostnameChecker.java 2026-10-19 12:10:20.000000000 +0000 @@ -125,7 +125,7 @@ /** * Check if the certificate allows use of the given IP address. - * + *

* From RFC2818: * In some cases, the URI is specified as an IP address rather than a * hostname. In this case, the iPAddress subjectAltName must be present @@ -140,26 +140,30 @@ } for (List next : subjAltNames) { // For IP address, it needs to be exact match - if (((Integer)next.get(0)).intValue() == ALTNAME_IP) { + if ((int) next.get(0) == ALTNAME_IP) { String ipAddress = (String)next.get(1); + if (expectedIP.equalsIgnoreCase(ipAddress)) { return; } else { - // compare InetAddress objects in order to ensure - // equality between a long IPv6 address and its - // abbreviated form. + // Compare InetAddress objects if literal check failed. + // InetAddress.getByName() normalizes IP address, thus + // the following is insured: + // - Equality between a long IPv6 address and its + // abbreviated form. + // - Equality between IPv4-Mapped IPv6 address and its + // regular IPv4 form. try { if (InetAddress.getByName(expectedIP).equals( InetAddress.getByName(ipAddress))) { return; } - } catch (UnknownHostException e) {} + } catch (UnknownHostException _) {} } } } throw new CertificateException("No subject alternative " + - "names matching " + "IP address " + - expectedIP + " found"); + "names matching IP address " + expectedIP + " found"); } /** diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/util/KeyUtil.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/KeyUtil.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/util/KeyUtil.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/KeyUtil.java 2026-10-19 12:10:20.000000000 +0000 @@ -40,6 +40,7 @@ import javax.security.auth.DestroyFailedException; import jdk.internal.access.SharedSecrets; +import com.sun.crypto.provider.PBKDF2KeyImpl; import sun.security.jca.JCAUtil; import sun.security.x509.AlgorithmId; @@ -469,6 +470,8 @@ if (k instanceof SecretKeySpec sk) { SharedSecrets.getJavaxCryptoSpecAccess() .clearSecretKeySpec(sk); + } else if (k instanceof PBKDF2KeyImpl p2k) { + p2k.clear(); } else { try { k.destroy(); diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/util/KnownOIDs.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/KnownOIDs.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/util/KnownOIDs.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/KnownOIDs.java 2026-10-19 12:10:20.000000000 +0000 @@ -208,8 +208,9 @@ PBEWithMD5AndRC2("1.2.840.113549.1.5.6"), PBEWithSHA1AndDES("1.2.840.113549.1.5.10"), PBEWithSHA1AndRC2("1.2.840.113549.1.5.11"), - PBKDF2WithHmacSHA1("1.2.840.113549.1.5.12"), + PBKDF2("1.2.840.113549.1.5.12", "PBKDF2WithHmacSHA1"), PBES2("1.2.840.113549.1.5.13"), + PBMAC1("1.2.840.113549.1.5.14"), // PKCS7 1.2.840.113549.1.7.* PKCS7("1.2.840.113549.1.7"), diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.util; + +import java.io.IOException; + +import sun.security.util.KnownOIDs; +import sun.security.x509.AlgorithmId; + +/** + * This class implements the parameter set used with password-based + * key derivation function 2 (PBKDF2), which is defined in PKCS#5 as follows: + * + *

+ *
+ * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::=
+ *   { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...}
+ *
+ * id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
+ *
+ * PBKDF2-params ::= SEQUENCE {
+ *     salt CHOICE {
+ *       specified OCTET STRING,
+ *       otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+ *     },
+ *     iterationCount INTEGER (1..MAX),
+ *     keyLength INTEGER (1..MAX) OPTIONAL,
+ *     prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
+ * }
+ *
+ * PBKDF2-SaltSources ALGORITHM-IDENTIFIER ::= { ... }
+ *
+ * PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= {
+ *     {NULL IDENTIFIED BY id-hmacWithSHA1} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA224} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA256} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA384} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA512}, ... }
+ *
+ * algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::=
+ *     {algorithm id-hmacWithSHA1, parameters NULL : NULL}
+ *
+ * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7}
+ *
+ * For more information, see
+ * RFC 8018:
+ * PKCS #5: Password-Based Cryptography Specification.
+ *
+ * 
+ */ +public final class PBKDF2Parameters { + + private final byte[] salt; + + private final int iterationCount; + + // keyLength in bits, or -1 if not present + private final int keyLength; + + private final String prfAlgo; + + /** + * Initialize PBKDF2Parameters from a DER encoded + * parameter block. + * + * @param pBKDF2_params the DER encoding of the parameter block + * + * @throws IOException for parsing errors in the input stream + */ + public PBKDF2Parameters(DerValue pBKDF2_params) throws IOException { + + if (pBKDF2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBKDF2 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue specified = pBKDF2_params.data.getDerValue(); + // the 'specified' ASN.1 CHOICE for 'salt' is supported + if (specified.tag == DerValue.tag_OctetString) { + salt = specified.getOctetString(); + } else { + // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported + throw new IOException("PBKDF2 parameter parsing error: " + + "not an ASN.1 OCTET STRING tag"); + } + iterationCount = pBKDF2_params.data.getInteger(); + + // keyLength INTEGER (1..MAX) OPTIONAL, + var ksDer = pBKDF2_params.data.getOptional(DerValue.tag_Integer); + if (ksDer.isPresent()) { + keyLength = ksDer.get().getInteger() * 8; // keyLength (in bits) + } else { + keyLength = -1; + } + + // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 + var prfDer = pBKDF2_params.data.getOptional(DerValue.tag_Sequence); + if (prfDer.isPresent()) { + DerValue prf = prfDer.get(); + // the pseudorandom function (default is HmacSHA1) + ObjectIdentifier kdfAlgo_OID = prf.data.getOID(); + KnownOIDs o = KnownOIDs.findMatch(kdfAlgo_OID.toString()); + if (o == null || (!o.stdName().equals("HmacSHA1") && + !o.stdName().equals("HmacSHA224") && + !o.stdName().equals("HmacSHA256") && + !o.stdName().equals("HmacSHA384") && + !o.stdName().equals("HmacSHA512") && + !o.stdName().equals("HmacSHA512/224") && + !o.stdName().equals("HmacSHA512/256"))) { + throw new IOException("PBKDF2 parameter parsing error: " + + "expecting the object identifier for a HmacSHA " + + "pseudorandom function"); + } + prfAlgo = o.stdName(); + prf.data.getOptional(DerValue.tag_Null); + prf.data.atEnd(); + } else { + prfAlgo = "HmacSHA1"; + } + } + + public static byte[] encode(byte[] salt, int iterationCount, + int keyLength, String kdfHmac) { + ObjectIdentifier prf = + ObjectIdentifier.of(KnownOIDs.findMatch(kdfHmac)); + return PBKDF2Parameters.encode(salt, iterationCount, keyLength, prf); + } + + /* + * Encode PBKDF2 parameters from components. + * The outer algorithm ID is also encoded in addition to the parameters. + */ + public static byte[] encode(byte[] salt, int iterationCount, + int keyLength, ObjectIdentifier prf) { + assert keyLength != -1; + + DerOutputStream out = new DerOutputStream(); + DerOutputStream tmp0 = new DerOutputStream(); + + tmp0.putOctetString(salt); + tmp0.putInteger(iterationCount); + tmp0.putInteger(keyLength); + + // prf AlgorithmIdentifier {{PBKDF2-PRFs}} + tmp0.write(new AlgorithmId(prf)); + + // id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} + out.putOID(ObjectIdentifier.of(KnownOIDs.PBKDF2)); + out.write(DerValue.tag_Sequence, tmp0); + + return new DerOutputStream().write(DerValue.tag_Sequence, out) + .toByteArray(); + } + + /** + * Returns the salt. + * + * @return the salt + */ + public byte[] getSalt() { + return this.salt; + } + + /** + * Returns the iteration count. + * + * @return the iteration count + */ + public int getIterationCount() { + return this.iterationCount; + } + + /** + * Returns size of key generated by PBKDF2, or -1 if not found/set. + * + * @return size of key generated by PBKDF2, or -1 if not found/set + */ + public int getKeyLength() { + return this.keyLength; + } + + /** + * Returns name of Hmac. + * + * @return name of Hmac + */ + public String getPrfAlgo() { + return this.prfAlgo; + } +} diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java 2026-10-19 12:10:20.000000000 +0000 @@ -36,12 +36,9 @@ */ enum CADistrustPolicy { /** - * Distrust TLS Server certificates anchored by a Symantec root CA and - * issued after April 16, 2019 (with exceptions for a couple of subordinate - * CAs, see the jdk.security.caDistrustPolicies definition in the - * java.security file for more details). If enabled, this policy is - * currently enforced by the PKIX and SunX509 TrustManager implementations - * of the SunJSSE provider implementation. + * Distrust TLS Server certificates anchored by a Symantec root CA. + * If enabled, this policy is currently enforced by the PKIX and SunX509 + * TrustManager implementations of the SunJSSE provider implementation. */ SYMANTEC_TLS { void checkDistrust(String variant, X509Certificate[] chain) @@ -54,10 +51,9 @@ }, /** - * Distrust TLS Server certificates anchored by an Entrust root CA and - * issued after November 11, 2024. If enabled, this policy is currently - * enforced by the PKIX and SunX509 TrustManager implementations - * of the SunJSSE provider implementation. + * Distrust TLS Server certificates anchored by an Entrust root CA. + * If enabled, this policy is currently enforced by the PKIX and SunX509 + * TrustManager implementations of the SunJSSE provider implementation. */ ENTRUST_TLS { void checkDistrust(String variant, X509Certificate[] chain) @@ -70,10 +66,9 @@ }, /** - * Distrust TLS Server certificates anchored by a CAMERFIRMA root CA and - * issued after April 15, 2025. If enabled, this policy is currently - * enforced by the PKIX and SunX509 TrustManager implementations - * of the SunJSSE provider implementation. + * Distrust TLS Server certificates anchored by a CAMERFIRMA root CA. + * If enabled, this policy is currently enforced by the PKIX and SunX509 + * TrustManager implementations of the SunJSSE provider implementation. */ CAMERFIRMA_TLS { void checkDistrust(String variant, X509Certificate[] chain) @@ -87,9 +82,10 @@ /** * Distrust TLS Server certificates anchored by the Chunghwa ePKI root CA - * and issued after March 17, 2026. If enabled, this policy is currently - * enforced by the PKIX and SunX509 TrustManager implementations - * of the SunJSSE provider implementation. + * and issued after March 17, 2026. After APRIL 19, 2027, certificates will + * be distrusted regardless of the issued date in the certificate. + * If enabled, this policy is currently enforced by the PKIX and SunX509 + * TrustManager implementations of the SunJSSE provider implementation. */ CHUNGHWA_TLS { void checkDistrust(String variant, X509Certificate[] chain) diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java 2026-10-19 12:10:20.000000000 +0000 @@ -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,12 +25,6 @@ package sun.security.validator; import java.security.cert.X509Certificate; -import java.time.LocalDate; -import java.time.Month; -import java.time.ZoneOffset; -import java.util.Date; -import java.util.Map; -import java.util.Set; import sun.security.util.Debug; import sun.security.x509.X509CertImpl; @@ -53,9 +47,7 @@ "063E4AFAC491DFD332F3089B8542E94617D893D7FE944E10A7937EE29D9693C0"; // Any TLS Server certificate that is anchored by one of the Camerfirma - // roots above and is issued after this date will be distrusted. - private static final LocalDate APRIL_15_2025 = - LocalDate.of(2025, Month.APRIL, 15); + // roots above will be distrusted. /** * This method assumes the eeCert is a TLS Server Cert and chains back to @@ -74,11 +66,10 @@ + "trust anchor of TLS server certificate"); } if (FINGERPRINT.equalsIgnoreCase(fp)) { - Date notBefore = chain[0].getNotBefore(); - LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(), - ZoneOffset.UTC); - // reject if certificate is issued after April 15, 2025 - checkNotBefore(ldNotBefore, APRIL_15_2025, anchor); + throw new ValidatorException + ("TLS Server certificate anchored by a distrusted legacy " + + "Camerfirma root CA: "+ anchor.getSubjectX500Principal(), + ValidatorException.T_UNTRUSTED_CERT, anchor); } } @@ -86,17 +77,5 @@ return X509CertImpl.getFingerprint("SHA-256", cert, debug); } - private static void checkNotBefore(LocalDate notBeforeDate, - LocalDate distrustDate, X509Certificate anchor) - throws ValidatorException { - if (notBeforeDate.isAfter(distrustDate)) { - throw new ValidatorException - ("TLS Server certificate issued after " + distrustDate + - " and anchored by a distrusted legacy Camerfirma root CA: " - + anchor.getSubjectX500Principal(), - ValidatorException.T_UNTRUSTED_CERT, anchor); - } - } - private CamerfirmaTLSPolicy() {} } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java 2026-10-19 12:10:20.000000000 +0000 @@ -29,8 +29,6 @@ import java.time.Month; import java.time.ZoneOffset; import java.util.Date; -import java.util.Map; -import java.util.Set; import sun.security.util.Debug; import sun.security.x509.X509CertImpl; @@ -55,6 +53,12 @@ private static final LocalDate MARCH_17_2026 = LocalDate.of(2026, Month.MARCH, 17); + // Any TLS Server certificate that is anchored by the Chunghwa + // root above is distrusted after APRIL_19_2027. + // APRIL_19_2027 is MARCH_17_2026 plus 398 days. + private static final LocalDate APRIL_19_2027 = + LocalDate.of(2027, Month.APRIL, 19); + /** * This method assumes the eeCert is a TLS Server Cert and chains back to * the anchor. @@ -72,6 +76,13 @@ + "trust anchor of TLS server certificate"); } if (FINGERPRINT.equalsIgnoreCase(fp)) { + if (LocalDate.now().isAfter(APRIL_19_2027)) { + throw new ValidatorException + ("TLS Server certificate anchored by a distrusted legacy " + + "Chunghwa root CA: " + anchor.getSubjectX500Principal(), + ValidatorException.T_UNTRUSTED_CERT, anchor); + } + Date notBefore = chain[0].getNotBefore(); LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(), ZoneOffset.UTC); diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -25,11 +25,6 @@ package sun.security.validator; import java.security.cert.X509Certificate; -import java.time.LocalDate; -import java.time.Month; -import java.time.ZoneOffset; -import java.util.Date; -import java.util.Map; import java.util.Set; import sun.security.util.Debug; @@ -75,9 +70,7 @@ ); // Any TLS Server certificate that is anchored by one of the Entrust - // roots above and is issued after this date will be distrusted. - private static final LocalDate NOVEMBER_11_2024 = - LocalDate.of(2024, Month.NOVEMBER, 11); + // roots above will be distrusted. /** * This method assumes the eeCert is a TLS Server Cert and chains back to @@ -96,11 +89,10 @@ + "trust anchor of TLS server certificate"); } if (FINGERPRINTS.contains(fp)) { - Date notBefore = chain[0].getNotBefore(); - LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(), - ZoneOffset.UTC); - // reject if certificate is issued after November 11, 2024 - checkNotBefore(ldNotBefore, NOVEMBER_11_2024, anchor); + throw new ValidatorException + ("TLS Server certificate anchored by a distrusted legacy " + + "Entrust root CA: "+ anchor.getSubjectX500Principal(), + ValidatorException.T_UNTRUSTED_CERT, anchor); } } @@ -108,17 +100,5 @@ return X509CertImpl.getFingerprint("SHA-256", cert, debug); } - private static void checkNotBefore(LocalDate notBeforeDate, - LocalDate distrustDate, X509Certificate anchor) - throws ValidatorException { - if (notBeforeDate.isAfter(distrustDate)) { - throw new ValidatorException - ("TLS Server certificate issued after " + distrustDate + - " and anchored by a distrusted legacy Entrust root CA: " - + anchor.getSubjectX500Principal(), - ValidatorException.T_UNTRUSTED_CERT, anchor); - } - } - private EntrustTLSPolicy() {} } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/validator/SymantecTLSPolicy.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/SymantecTLSPolicy.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/validator/SymantecTLSPolicy.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/validator/SymantecTLSPolicy.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,6 @@ package sun.security.validator; import java.security.cert.X509Certificate; -import java.time.LocalDate; -import java.time.Month; -import java.time.ZoneOffset; -import java.util.Date; -import java.util.Map; import java.util.Set; import sun.security.util.Debug; @@ -123,28 +118,8 @@ "2399561127A57125DE8CEFEA610DDF2FA078B5C8067F4E828290BFB860E84B3C" ); - private static final LocalDate DECEMBER_31_2019 = - LocalDate.of(2019, Month.DECEMBER, 31); - // SHA-256 certificate fingerprints of subCAs with later distrust dates - private static final Map EXEMPT_SUBCAS = Map.of( - // Subject DN: C=US, O=Apple Inc., OU=Certification Authority, - // CN=Apple IST CA 2 - G1 - // Issuer DN: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US - "AC2B922ECFD5E01711772FEA8ED372DE9D1E2245FCE3F57A9CDBEC77296A424B", - DECEMBER_31_2019, - // Subject DN: C=US, O=Apple Inc., OU=Certification Authority, - // CN=Apple IST CA 8 - G1 - // Issuer DN: CN=GeoTrust Primary Certification Authority - G2, - // OU=(c) 2007 GeoTrust Inc. - For authorized use only, - // O=GeoTrust Inc., C=US - "A4FE7C7F15155F3F0AEF7AAA83CF6E06DEB97CA3F909DF920AC1490882D488ED", - DECEMBER_31_2019 - ); - // Any TLS Server certificate that is anchored by one of the Symantec - // roots above and is issued after this date will be distrusted. - private static final LocalDate APRIL_16_2019 = - LocalDate.of(2019, Month.APRIL, 16); + // roots above will be distrusted. /** * This method assumes the eeCert is a TLS Server Cert and chains back to @@ -163,26 +138,10 @@ + "trust anchor of TLS server certificate"); } if (FINGERPRINTS.contains(fp)) { - Date notBefore = chain[0].getNotBefore(); - LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(), - ZoneOffset.UTC); - // check if chain goes through one of the subCAs - if (chain.length > 2) { - X509Certificate subCA = chain[chain.length-2]; - fp = fingerprint(subCA); - if (fp == null) { - throw new ValidatorException("Cannot generate fingerprint " - + "for intermediate CA of TLS server certificate"); - } - LocalDate distrustDate = EXEMPT_SUBCAS.get(fp); - if (distrustDate != null) { - // reject if certificate is issued after specified date - checkNotBefore(ldNotBefore, distrustDate, anchor); - return; // success - } - } - // reject if certificate is issued after April 16, 2019 - checkNotBefore(ldNotBefore, APRIL_16_2019, anchor); + throw new ValidatorException( + "TLS Server certificate anchored by a distrusted legacy " + + "Symantec root CA: " +anchor.getSubjectX500Principal(), + ValidatorException.T_UNTRUSTED_CERT, anchor); } } @@ -190,17 +149,5 @@ return X509CertImpl.getFingerprint("SHA-256", cert, debug); } - private static void checkNotBefore(LocalDate notBeforeDate, - LocalDate distrustDate, X509Certificate anchor) - throws ValidatorException { - if (notBeforeDate.isAfter(distrustDate)) { - throw new ValidatorException - ("TLS Server certificate issued after " + distrustDate + - " and anchored by a distrusted legacy Symantec root CA: " - + anchor.getSubjectX500Principal(), - ValidatorException.T_UNTRUSTED_CERT, anchor); - } - } - private SymantecTLSPolicy() {} } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/AlgorithmId.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/AlgorithmId.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/AlgorithmId.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/AlgorithmId.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,10 +127,35 @@ public AlgorithmId(ObjectIdentifier oid, DerValue params) throws IOException { this.algid = oid; - if (params != null) { - encodedParams = params.toByteArray(); - decodeParams(); + + if (params == null) { + this.encodedParams = null; + this.algParams = null; + return; + } + + /* + * If the parameters field explicitly contains an ASN.1 NULL, treat it as + * "no parameters" rather than storing a literal NULL encoding. + * + * This canonicalization ensures consistent encoding/decoding behavior: + * - Algorithms that omit parameters and those that encode explicit NULL + * are treated equivalently (encodedParams == null). + */ + if (params.tag == DerValue.tag_Null) { + if (params.length() != 0) { + throw new IOException("Invalid ASN.1 NULL in AlgorithmId parameters: " + + "non-zero length"); + } + // Canonicalize to "no parameters" representation for consistency + this.encodedParams = null; + this.algParams = null; + return; } + + // Normal case: non-NULL params -> store and decode + this.encodedParams = params.toByteArray(); + decodeParams(); } protected void decodeParams() throws IOException { @@ -163,38 +188,10 @@ bytes.putOID(algid); if (encodedParams == null) { - // MessageDigest algorithms usually have a NULL parameters even - // if most RFCs suggested absent. - // RSA key and signature algorithms requires the NULL parameters - // to be present, see A.1 and A.2.4 of RFC 8017. - if (algid.equals(RSAEncryption_oid) - || algid.equals(MD2_oid) - || algid.equals(MD5_oid) - || algid.equals(SHA_oid) - || algid.equals(SHA224_oid) - || algid.equals(SHA256_oid) - || algid.equals(SHA384_oid) - || algid.equals(SHA512_oid) - || algid.equals(SHA512_224_oid) - || algid.equals(SHA512_256_oid) - || algid.equals(SHA3_224_oid) - || algid.equals(SHA3_256_oid) - || algid.equals(SHA3_384_oid) - || algid.equals(SHA3_512_oid) - || algid.equals(SHA1withRSA_oid) - || algid.equals(SHA224withRSA_oid) - || algid.equals(SHA256withRSA_oid) - || algid.equals(SHA384withRSA_oid) - || algid.equals(SHA512withRSA_oid) - || algid.equals(SHA512$224withRSA_oid) - || algid.equals(SHA512$256withRSA_oid) - || algid.equals(MD2withRSA_oid) - || algid.equals(MD5withRSA_oid) - || algid.equals(SHA3_224withRSA_oid) - || algid.equals(SHA3_256withRSA_oid) - || algid.equals(SHA3_384withRSA_oid) - || algid.equals(SHA3_512withRSA_oid)) { + if (OIDS_REQUIRING_NULL.contains(algid.toString())) { bytes.putNull(); + } else { + // Parameters omitted } } else { bytes.writeBytes(encodedParams); @@ -646,30 +643,54 @@ public static final ObjectIdentifier MGF1_oid = ObjectIdentifier.of(KnownOIDs.MGF1); - public static final ObjectIdentifier SHA1withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA1withRSA); - public static final ObjectIdentifier SHA224withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA224withRSA); - public static final ObjectIdentifier SHA256withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA256withRSA); - public static final ObjectIdentifier SHA384withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA384withRSA); - public static final ObjectIdentifier SHA512withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA512withRSA); - public static final ObjectIdentifier SHA512$224withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA512$224withRSA); - public static final ObjectIdentifier SHA512$256withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA512$256withRSA); - public static final ObjectIdentifier MD2withRSA_oid = - ObjectIdentifier.of(KnownOIDs.MD2withRSA); - public static final ObjectIdentifier MD5withRSA_oid = - ObjectIdentifier.of(KnownOIDs.MD5withRSA); - public static final ObjectIdentifier SHA3_224withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA3_224withRSA); - public static final ObjectIdentifier SHA3_256withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA3_256withRSA); - public static final ObjectIdentifier SHA3_384withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA3_384withRSA); - public static final ObjectIdentifier SHA3_512withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA3_512withRSA); + /* Set of OIDs that must explicitly encode a NULL parameter in AlgorithmIdentifier. + * References: + - RFC 8017 (PKCS #1) §A.1, §A.2.4: RSA key and signature algorithms + - RFC 9879 (HMAC) §4: HMAC algorithm identifiers + - RFC 9688 (HMAC with SHA-3) §4.3: HMAC-SHA3 algorithms MUST omit parameters + */ + private static final Set OIDS_REQUIRING_NULL = Set.of( + // MessageDigest algorithms usually have a NULL parameters even + // if most RFCs suggested absent. + KnownOIDs.MD2.value(), + KnownOIDs.MD5.value(), + KnownOIDs.SHA_1.value(), + KnownOIDs.SHA_224.value(), + KnownOIDs.SHA_256.value(), + KnownOIDs.SHA_384.value(), + KnownOIDs.SHA_512.value(), + KnownOIDs.SHA_512$224.value(), + KnownOIDs.SHA_512$256.value(), + KnownOIDs.SHA3_224.value(), + KnownOIDs.SHA3_256.value(), + KnownOIDs.SHA3_384.value(), + KnownOIDs.SHA3_512.value(), + + //--- RSA key and signature algorithms (RFC 8017 §A.1, §A.2.4) + KnownOIDs.RSA.value(), + KnownOIDs.SHA1withRSA.value(), + KnownOIDs.SHA224withRSA.value(), + KnownOIDs.SHA256withRSA.value(), + KnownOIDs.SHA384withRSA.value(), + KnownOIDs.SHA512withRSA.value(), + KnownOIDs.SHA512$224withRSA.value(), + KnownOIDs.SHA512$256withRSA.value(), + KnownOIDs.MD2withRSA.value(), + KnownOIDs.MD5withRSA.value(), + KnownOIDs.SHA3_224withRSA.value(), + KnownOIDs.SHA3_256withRSA.value(), + KnownOIDs.SHA3_384withRSA.value(), + KnownOIDs.SHA3_512withRSA.value(), + + // HMACs per RFC 9879 (Section 4): these require explicit NULL parameters + // Note: HMAC-SHA3 algorithms (RFC 9688 §4.3) MUST omit parameters, + // so they are intentionally excluded from this list. + KnownOIDs.HmacSHA1.value(), + KnownOIDs.HmacSHA224.value(), + KnownOIDs.HmacSHA256.value(), + KnownOIDs.HmacSHA384.value(), + KnownOIDs.HmacSHA512.value(), + KnownOIDs.HmacSHA512$224.value(), + KnownOIDs.HmacSHA512$256.value() + ); } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/DNSName.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/DNSName.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/DNSName.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/DNSName.java 2026-10-19 12:10:20.000000000 +0000 @@ -54,8 +54,8 @@ private static final HostnameChecker HOSTNAME_CHECKER = HostnameChecker.getInstance(HostnameChecker.TYPE_TLS); - private static final String alphaDigits = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final String DNS_ALLOWED = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-"; /** * Create the DNSName object from the passed encoded Der value. @@ -75,52 +75,64 @@ * @throws IOException if the name is not a valid DNSName */ public DNSName(String name, boolean allowWildcard) throws IOException { - if (name == null || name.isEmpty()) + + // Check the full name. + if (name == null || name.isEmpty()) { throw new IOException("DNSName must not be null or empty"); - if (name.contains(" ")) - throw new IOException("DNSName with blank components is not permitted"); - if (name.startsWith(".") || name.endsWith(".")) + } + + if (name.contains(" ")) { + throw new IOException( + "DNSName with blank labels is not permitted"); + } + + if (name.startsWith(".") || name.endsWith(".")) { throw new IOException("DNSName may not begin or end with a ."); - /* - * Name will consist of label components separated by "." - * startIndex is the index of the first character of a component - * endIndex is the index of the last character of a component plus 1 - */ - for (int endIndex,startIndex = 0; startIndex < name.length(); startIndex = endIndex+1) { - endIndex = name.indexOf('.', startIndex); - if (endIndex < 0) { - endIndex = name.length(); - } - if (endIndex - startIndex < 1) - throw new IOException("DNSName with empty components are not permitted"); - - if (allowWildcard) { - // RFC 1123: DNSName components must begin with a letter or digit - // or RFC 4592: the first component of a DNSName can have only a wildcard - // character * (asterisk), i.e. *.example.com. Asterisks at other components - // will not be allowed as a wildcard. - if (alphaDigits.indexOf(name.charAt(startIndex)) < 0) { - // Checking to make sure the wildcard only appears in the first component, - // and it has to be at least 3-char long with the form of *.[alphaDigit] - if ((name.length() < 3) || (name.indexOf('*') != 0) || - (name.charAt(startIndex+1) != '.') || - (alphaDigits.indexOf(name.charAt(startIndex+2)) < 0)) - throw new IOException("DNSName components must begin with a letter, digit, " - + "or the first component can have only a wildcard character *"); - } - } else { - // RFC 1123: DNSName components must begin with a letter or digit - if (alphaDigits.indexOf(name.charAt(startIndex)) < 0) - throw new IOException("DNSName components must begin with a letter or digit"); + } + + // RFC 1123 Section 2.1 and RFC 2181 Section 11 + if (name.length() > 253) { + throw new IOException( + "DNSName can't be longer than 253 characters"); + } + + // Check the labels. + String[] labels = name.split("\\."); + + for (int i = 0; i < labels.length; i++) { + String label = labels[i]; + + if (label.isEmpty()) { + throw new IOException( + "DNSName with empty labels is not permitted"); + } + + // RFC 1123 Section 2.1 + if (label.length() > 63) { + throw new IOException( + "DNSName label can't be longer than 63 characters"); } - //nonStartIndex: index for characters in the component beyond the first one - for (int nonStartIndex=startIndex+1; nonStartIndex < endIndex; nonStartIndex++) { - char x = name.charAt(nonStartIndex); - if ((alphaDigits).indexOf(x) < 0 && x != '-') - throw new IOException("DNSName components must consist of letters, digits, and hyphens"); + // RFC 1035 Section 2.3.1 + if (label.startsWith("-") || label.endsWith("-")) { + throw new IOException( + "DNSName label may not begin or end with a hyphen"); + } + + // RFC 9525 Section 6.3 + if (allowWildcard && label.equals("*") && i == 0 + && labels.length > 1) { + continue; + } + + for (char c : label.toCharArray()) { + if (DNS_ALLOWED.indexOf(c) < 0) { + throw new IOException("DNSName labels must consist of " + + "letters, digits, and hyphens"); + } } } + this.name = name; } @@ -217,11 +229,13 @@ * order zero bit. * * @param inputName to be checked for being constrained + * @param matchWildcard whether to match a wildcard in inputName * @return constraint type above * @throws UnsupportedOperationException if name is not exact match, but narrowing and widening are * not supported for this name type. */ - public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException { + public int constrains(GeneralNameInterface inputName, boolean matchWildcard) + throws UnsupportedOperationException { int constraintType; if (inputName == null) constraintType = NAME_DIFF_TYPE; @@ -232,7 +246,9 @@ (((DNSName)inputName).getName()).toLowerCase(Locale.ENGLISH); String thisName = name.toLowerCase(Locale.ENGLISH); - if (HOSTNAME_CHECKER.isMatched(thisName, inName, false)) + if (inName.equals(thisName) || (matchWildcard + && inName.contains("*") + && HOSTNAME_CHECKER.isMatched(thisName, inName, false))) constraintType = NAME_MATCH; else if (thisName.endsWith(inName)) { int inNdx = thisName.lastIndexOf(inName); @@ -253,6 +269,10 @@ return constraintType; } + public int constrains(GeneralNameInterface inputName) { + return constrains(inputName, false); + } + /** * Return subtree depth of this name for purposes of determining * NameConstraints minimum and maximum bounds and for calculating diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/IPAddressName.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/IPAddressName.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/IPAddressName.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/IPAddressName.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, 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 @@ -29,6 +29,7 @@ import java.lang.Integer; import java.net.InetAddress; import java.util.Arrays; +import sun.net.util.IPAddressUtil; import sun.security.util.HexDumpEncoder; import sun.security.util.BitArray; import sun.security.util.DerOutputStream; @@ -69,11 +70,12 @@ */ public class IPAddressName implements GeneralNameInterface { private byte[] address; - private final boolean isIPv4; private String name; /** * Create the IPAddressName object from the passed encoded Der value. + *

+ * IPv4-Mapped IPv6 addresses/subnets normalized to IPv4. * * @param derValue the encoded DER IPAddressName. * @exception IOException on error. @@ -84,24 +86,44 @@ /** * Create the IPAddressName object with the specified octets. + *

+ * A valid address must consist of 4 bytes of address and + * optional 4 bytes of mask, or 16 bytes of address and + * optional 16 bytes of mask. + *

+ * IPv4-Mapped IPv6 addresses/subnets normalized to IPv4. * * @param address the IP address * @throws IOException if address is not a valid IPv4 or IPv6 address */ public IPAddressName(byte[] address) throws IOException { - /* - * A valid address must consist of 4 bytes of address and - * optional 4 bytes of 4 bytes of mask, or 16 bytes of address - * and optional 16 bytes of mask. - */ - if (address.length == 4 || address.length == 8) { - isIPv4 = true; - } else if (address.length == 16 || address.length == 32) { - isIPv4 = false; - } else { - throw new IOException("Invalid IPAddressName"); - } - this.address = address; + // Treat IPv4-Mapped IPv6 address as a regular IPv4. + this.address = switch (address.length) { + case 4, 8 -> address; // IPv4 address/subnet + case 16 -> { + // Single IPv6 address. + byte[] newAddr = IPAddressUtil.convertFromIPv4MappedAddress( + address); + yield newAddr != null ? newAddr : address; + } + case 32 -> { + // IPv6 subnet. + byte[] newAddr = IPAddressUtil.convertFromIPv4MappedAddress( + Arrays.copyOfRange(address, 0, 16)); + + if (newAddr == null) { + yield address; + } + + byte[] ret = new byte[8]; + System.arraycopy(newAddr, 0, ret, 0, 4); + System.arraycopy(ipv4MaskFromIpv6Mask( + Arrays.copyOfRange(address, 16, 32)), + 0, ret, 4, 4); + yield ret; + } + default -> throw new IOException("Invalid IPAddressName"); + }; } /** @@ -118,6 +140,8 @@ * of the address. If /n is used, n is a decimal number indicating how many * of the leftmost contiguous bits of the address comprise the prefix for * this subnet. Internally, a mask value is created using the prefix length. + *

+ * IPv4-Mapped IPv6 addresses/subnets normalized to IPv4. * * @param name String form of IPAddressName * @throws IOException if name can not be converted to a valid IPv4 or IPv6 @@ -137,11 +161,9 @@ // Parse name into byte-value address components and optional // prefix parseIPv6(name); - isIPv4 = false; } else if (name.indexOf('.') >= 0) { //name is IPv4: uses dots as value separators parseIPv4(name); - isIPv4 = true; } else { throw new IOException("Invalid IPAddress: " + name); } @@ -150,7 +172,7 @@ /** * Parse an IPv4 address. * - * @param name IPv4 address with optional mask values + * @param name IPv4 address with an optional mask in dotted IP notation. * @throws IOException on error */ private void parseIPv4(String name) throws IOException { @@ -178,41 +200,76 @@ /** * Parse an IPv6 address. * - * @param name String IPv6 address with optional / - * If / is present, address[] array will - * be 32 bytes long, otherwise 16. + * @param name IPv6 address with an optional mask in CIDR notation. * @throws IOException on error */ - private static final int MASKSIZE = 16; private void parseIPv6(String name) throws IOException { - int slashNdx = name.indexOf('/'); + if (slashNdx == -1) { address = InetAddress.getByName(name).getAddress(); } else { - address = new byte[32]; byte[] base = InetAddress.getByName (name.substring(0, slashNdx)).getAddress(); - System.arraycopy(base, 0, address, 0, 16); + byte[] mask = ipv6MaskFromString(name.substring(slashNdx + 1)); - // append a mask corresponding to the num of prefix bits specified - int prefixLen = Integer.parseInt(name.substring(slashNdx+1)); - if (prefixLen < 0 || prefixLen > 128) { - throw new IOException("IPv6Address prefix length (" + - prefixLen + ") in out of valid range [0,128]"); + if (base.length == 16) { + // IPv6 address. + address = new byte[32]; + System.arraycopy(base, 0, address, 0, 16); + System.arraycopy(mask, 0, address, 16, 16); + } else if (base.length == 4) { + // IPv4-Mapped IPv6 address. + address = new byte[8]; + System.arraycopy(base, 0, address, 0, 4); + System.arraycopy(ipv4MaskFromIpv6Mask(mask), 0, address, 4, 4); + } else { + throw new IOException("Invalid IPAddress subnet: " + name); } + } + } + + private static byte[] ipv6MaskFromString(String ipv6Mask) + throws IOException { + int prefixLen; + + try { + prefixLen = Integer.parseInt(ipv6Mask); + } catch (NumberFormatException e) { + throw new IOException(e); + } - // create new bit array initialized to zeros - BitArray bitArray = new BitArray(MASKSIZE * 8); + if (prefixLen < 0 || prefixLen > 128) { + throw new IOException("IPv6Address prefix length (" + + prefixLen + ") is out of valid range [0,128]"); + } - // set all most significant bits up to prefix length - for (int i = 0; i < prefixLen; i++) - bitArray.set(i, true); - byte[] maskArray = bitArray.toByteArray(); + // create new bit array initialized to zeros + BitArray bitArray = new BitArray(128); - // copy mask bytes into mask portion of address - System.arraycopy(maskArray, 0, address, MASKSIZE, MASKSIZE); + // set all most significant bits up to prefix length + for (int i = 0; i < prefixLen; i++) { + bitArray.set(i, true); } + + return bitArray.toByteArray(); + } + + private static byte[] ipv4MaskFromIpv6Mask(byte[] ipv6Mask) + throws IOException { + if (ipv6Mask == null || ipv6Mask.length != 16) { + throw new IOException("IPv6 mask must be 16 bytes"); + } + + // For a mapped IPv4 subnet, the first 96 bits must be set. + for (int i = 0; i < 12; i++) { + if ((ipv6Mask[i] & 0xFF) != 0xFF) { + throw new IOException("Not an IPv4-mapped IPv6 mask: first 96" + + " bits are not set"); + } + } + + return Arrays.copyOfRange(ipv6Mask, 12, 16); } /** @@ -256,8 +313,8 @@ if (name != null) return name; - if (isIPv4) { - //IPv4 address or subdomain + if (address.length == 4 || address.length == 8) { + //IPv4 address or subnet byte[] host = new byte[4]; System.arraycopy(address, 0, host, 0, 4); name = InetAddress.getByAddress(host).getHostAddress(); @@ -268,14 +325,14 @@ InetAddress.getByAddress(mask).getHostAddress(); } } else { - //IPv6 address or subdomain + //IPv6 address or subnet byte[] host = new byte[16]; System.arraycopy(address, 0, host, 0, 16); name = InetAddress.getByAddress(host).getHostAddress(); if (address.length == 32) { - // IPv6 subdomain: display prefix length + // IPv6 subnet: display prefix length - // copy subdomain into new array and convert to BitArray + // copy subnet into new array and convert to BitArray byte[] maskBytes = new byte[16]; System.arraycopy(address, 16, maskBytes, 0, 16); BitArray ba = new BitArray(16*8, maskBytes); @@ -289,7 +346,7 @@ // Verify remaining bits 0 for (; i < 16*8; i++) { if (ba.get(i)) { - throw new IOException("Invalid IPv6 subdomain - set " + + throw new IOException("Invalid IPv6 subnet - set " + "bit " + i + " not contiguous"); } } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, 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 @@ -449,7 +449,14 @@ } } else { if (!hasNameType(altNames, GeneralNameInterface.NAME_DNS)) { - altNames.add(new GeneralName(new DNSName(cn))); + // Replacing wildcard character '*' with 'z' to check + // the domain name template validity. + new DNSName(cn.replace('*', 'z')); + // If the above line doesn't throw, use Der constructor + // which performs no format checks: we want to accept + // DNS name with any wildcard here. + altNames.add(new GeneralName(new DNSName(new DerValue( + DerValue.tag_IA5String, cn)))); } } } catch (IOException ioe) { @@ -506,9 +513,15 @@ if (exName == null) continue; + // Match a wildcard in DNSName only against the excluded subtree + int matchResult = + exName.getType() == GeneralNameInterface.NAME_DNS + ? ((DNSName) exName).constrains(name, true) + : exName.constrains(name); + // if name matches or narrows any excluded subtree, // return false - switch (exName.constrains(name)) { + switch (matchResult) { case GeneralNameInterface.NAME_DIFF_TYPE: case GeneralNameInterface.NAME_WIDENS: // name widens excluded case GeneralNameInterface.NAME_SAME_TYPE: diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/URIName.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/URIName.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/URIName.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/URIName.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, 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 @@ -29,6 +29,7 @@ import java.net.URI; import java.net.URISyntaxException; +import sun.net.util.IPAddressUtil; import sun.security.util.*; /** @@ -131,14 +132,21 @@ try { hostDNS = new DNSName(host); } catch (IOException ioe) { - // Not a valid DNSName; see if it is a valid IPv4 - // IPAddressName - try { - hostIP = new IPAddressName(host); - } catch (Exception ioe2) { + // Not a valid DNSName; only accept host as an + // IPv4 literal. + byte[] ipV4 = IPAddressUtil.textToNumericFormatV4(host); + if (ipV4 != null) { + try { + hostIP = new IPAddressName(ipV4); + } catch (IOException ioe2) { + throw new IOException("invalid URI name (host " + + "portion is not a valid DNSName or IPv4 address" + + "):" + name, ioe2); + } + } else { throw new IOException("invalid URI name (host " + - "portion is not a valid DNSName, IPv4 address," + - " or IPv6 address):" + name); + "portion is not a valid DNSName or IPv4 address" + + "):" + name); } } } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/X509Key.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/X509Key.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/security/x509/X509Key.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/security/x509/X509Key.java 2026-10-19 12:10:20.000000000 +0000 @@ -104,6 +104,10 @@ return (BitArray)bitStringKey.clone(); } + public byte[] getKeyAsBytes() { + return bitStringKey.toByteArray(); + } + /** * Construct X.509 subject public key from a DER value. If * the runtime environment is configured with a specific class for diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java 2026-10-19 12:10:20.000000000 +0000 @@ -107,6 +107,9 @@ // TimeZoneNamesBundle exemplar city prefix private static final String TZNB_EXCITY_PREFIX = "timezone.excity."; + // TimeZoneNamesBundle explicit metazone dst offset prefix + private static final String TZNB_METAZONE_DSTOFFSET_PREFIX = "metazone.dstoffset."; + // null singleton cache value private static final Object NULLOBJECT = new Object(); @@ -333,7 +336,8 @@ if (Objects.isNull(data) || Objects.isNull(val = data.get())) { TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale); - if (key.startsWith(TZNB_EXCITY_PREFIX)) { + if (key.startsWith(TZNB_EXCITY_PREFIX) || + key.startsWith(TZNB_METAZONE_DSTOFFSET_PREFIX)) { if (tznb.containsKey(key)) { val = tznb.getString(key); assert val instanceof String; @@ -390,7 +394,8 @@ Set value = new LinkedHashSet<>(); Set tzIds = new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs())); for (String key : keyset) { - if (!key.startsWith(TZNB_EXCITY_PREFIX)) { + if (!key.startsWith(TZNB_EXCITY_PREFIX) && + !key.startsWith(TZNB_METAZONE_DSTOFFSET_PREFIX)) { value.add(rb.getStringArray(key)); tzIds.remove(key); } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java 2026-10-19 12:10:20.000000000 +0000 @@ -37,7 +37,7 @@ import java.util.spi.TimeZoneNameProvider; import sun.util.calendar.ZoneInfo; import sun.util.cldr.CLDRLocaleProviderAdapter; -import static sun.util.locale.provider.LocaleProviderAdapter.Type; +import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR; /** * Utility class that deals with the localized time zone names @@ -169,10 +169,22 @@ * Returns the canonical ID for the given ID */ public static Optional canonicalTZID(String id) { - return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR)) + return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(CLDR)) .canonicalTZID(id); } + /** + * {@return the explicit metazone DST offset for the specified time zone ID, if exists} + * @param tzid the time zone ID + */ + public static String explicitDstOffset(String tzid) { + return (String) (LocaleProviderAdapter.forType(CLDR) instanceof CLDRLocaleProviderAdapter ca ? + ca.getLocaleResources(Locale.ROOT) + .getTimeZoneNames("metazone.dstoffset." + + ca.canonicalTZID(tzid).orElse(tzid)) : + null); + } + private static String[] retrieveDisplayNamesImpl(String id, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class); diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java openjdk-25-25.0.5+8/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java --- openjdk-25-25.0.4.1+1/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,8 +43,6 @@ import java.util.Map; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.MissingResourceException; -import java.util.Objects; import java.util.Set; /** diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/conf/security/java.security openjdk-25-25.0.5+8/src/java.base/share/conf/security/java.security --- openjdk-25-25.0.4.1+1/src/java.base/share/conf/security/java.security 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/conf/security/java.security 2026-10-19 12:10:20.000000000 +0000 @@ -1,4 +1,4 @@ -# + # This is the "master security properties file". # # An alternate java.security properties file may be specified @@ -1313,8 +1313,9 @@ #keystore.pkcs12.keyPbeIterationCount = 10000 # The algorithm used to calculate the optional MacData at the end of a PKCS12 -# file. This can be any HmacPBE algorithm defined in the Mac section of the -# Java Security Standard Algorithm Names Specification. When set to "NONE", +# file. This can be any HmacPBE or PBEWith algorithm defined in +# the Mac section of the Java Security Standard Algorithm Names Specification, +# for example, HmacPBESHA256 or PBEWithHmacSHA256. When set to "NONE", # no Mac is generated. The default value is "HmacPBESHA256". #keystore.pkcs12.macAlgorithm = HmacPBESHA256 @@ -1393,23 +1394,18 @@ # The supported values are: # # SYMANTEC_TLS : Distrust TLS Server certificates anchored by a Symantec -# root CA and issued after April 16, 2019 unless issued by one of the -# following subordinate CAs which have a later distrust date: -# 1. Apple IST CA 2 - G1, SHA-256 fingerprint: -# AC2B922ECFD5E01711772FEA8ED372DE9D1E2245FCE3F57A9CDBEC77296A424B -# Distrust after December 31, 2019. -# 2. Apple IST CA 8 - G1, SHA-256 fingerprint: -# A4FE7C7F15155F3F0AEF7AAA83CF6E06DEB97CA3F909DF920AC1490882D488ED -# Distrust after December 31, 2019. +# root CA. # # ENTRUST_TLS : Distrust TLS Server certificates anchored by -# an Entrust root CA and issued after November 11, 2024. +# an Entrust root CA. # # CAMERFIRMA_TLS : Distrust TLS Server certificates anchored by -# a Camerfirma root CA and issued after April 15, 2025. +# a Camerfirma root CA. # # CHUNGHWA_TLS : Distrust TLS Server certificates anchored by # a Chunghwa root CA and issued after March 17, 2026. +# After April 19, 2027, certificates will be distrusted regardless +# of the date the certificate was issued. # # Leading and trailing whitespace surrounding each value are ignored. # Unknown values are ignored. If the property is commented out or set to the diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/cacerts/luxtrustglobalrootca openjdk-25-25.0.5+8/src/java.base/share/data/cacerts/luxtrustglobalrootca --- openjdk-25-25.0.4.1+1/src/java.base/share/data/cacerts/luxtrustglobalrootca 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/cacerts/luxtrustglobalrootca 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -Owner: CN=LuxTrust Global Root, O=LuxTrust s.a., C=LU -Issuer: CN=LuxTrust Global Root, O=LuxTrust s.a., C=LU -Serial number: bb8 -Valid from: Thu Mar 17 09:51:37 GMT 2011 until: Wed Mar 17 09:51:37 GMT 2021 -Signature algorithm name: SHA256withRSA -Subject Public Key Algorithm: 2048-bit RSA key -Version: 3 ------BEGIN CERTIFICATE----- -MIIDZDCCAkygAwIBAgICC7gwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCTFUx -FjAUBgNVBAoTDUx1eFRydXN0IHMuYS4xHTAbBgNVBAMTFEx1eFRydXN0IEdsb2Jh -bCBSb290MB4XDTExMDMxNzA5NTEzN1oXDTIxMDMxNzA5NTEzN1owRDELMAkGA1UE -BhMCTFUxFjAUBgNVBAoTDUx1eFRydXN0IHMuYS4xHTAbBgNVBAMTFEx1eFRydXN0 -IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsn+n -QPAiygz267Hxyw6VV0B1r6A/Ps7sqjJX5hmxZ0OYWmt8s7j6eJyqpoSyYBuAQc5j -zR8XCJmk9e8+EsdMsFeaXHhAePxFjdqRZ9w6Ubltc+a3OY52OrQfBfVpVfmTz3iI -Sr6qm9d7R1tGBEyCFqY19vx039a0r9jitScRdFmiwmYsaArhmIiIPIoFdRTjuK7z -CISbasE/MRivJ6VLm6T9eTHemD0OYcqHmMH4ijCc+j4z1aXEAwfh95Z0GAAnOCfR -K6qq4UFFi2/xJcLcopeVx0IUM115hCNq52XAV6DYXaljAeew5Ivo+MVjuOVsdJA9 -x3f8K7p56aTGEnin/wIDAQABo2AwXjAMBgNVHRMEBTADAQH/MA4GA1UdDwEB/wQE -AwIBBjAfBgNVHSMEGDAWgBQXFYWJCS8kh28/HRvk8pZ5g0gTzjAdBgNVHQ4EFgQU -FxWFiQkvJIdvPx0b5PKWeYNIE84wDQYJKoZIhvcNAQELBQADggEBAFrwHNDUUM9B -fua4nX3DcNBeNv9ujnov3kgR1TQuPLdFwlQlp+HBHjeDtpSutkVIA+qVvuucarQ3 -XB8u02uCgUNbCj8RVWOs+nwIAjegPDkEM/6XMshS5dklTbDG7mgfcKpzzlcD3H0K -DTPy0lrfCmw7zBFRlxqkIaKFNQLXgCLShLL4wKpov9XrqsMLq6F8K/f1O4fhVFfs -BSTveUJO84ton+Ruy4KZycwq3FPCH3CDqyEPVrRI/98HIrOM+R2mBN8tAza53W/+ -MYhm/2xtRDSvCHc+JtJy9LtHVpM8mGPhM7uZI5K1g3noHZ9nrWLWidb2/CfeMifL -hNp3hSGhEiE= ------END CERTIFICATE----- diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/VERSION openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/VERSION --- openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/VERSION 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/VERSION 2026-10-19 12:10:20.000000000 +0000 @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2026b +tzdata2026e diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/africa openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/africa --- openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/africa 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/africa 2026-10-19 12:10:20.000000000 +0000 @@ -620,6 +620,24 @@ # Morocco # See Africa/Ceuta for Spanish Morocco. +# From Paul Eggert (2026-06-26): +# In “Morocco’s GMT+1, a century of shifting time and a debate far from over” +# https://en.yabiladi.com/articles/details/191310/morocco-s-gmt1-century-shifting-time +# (2026-03-30), Yabiladi’s Latifa Babas reports the following: +# * A 1913-10-26 royal dahir established GMT as legal time in Morocco. +# * A 1918-05-10 dahir instituted DST on 1918-05-16 at 00:00. +# * A September 1939 dahir restarted DST on 1939-09-12. +# * A February 1940 dahir restarted DST as early as 1940-02-25. +# * Standard time resumed in September 1946. +# * A June 1950 decree restarted DST, which ran until as late as October. +# * Royal decree 455-67 (1967-06-02) restarted DST on June 3 at noon. +# * After 1967 Morocco used DST “during several summers, particularly +# throughout the 1970s and 1980s.” +# Babas consulted official records that disagree with and are surely +# more correct than our pre-2008 timestamp data, which came from the +# unreliable Shanks & Pottenger. Unfortunately, Babas did not provide +# enough detail to correct our data. + # From Alex Krivenyshev (2008-05-09): # Here is an article that Morocco plan to introduce Daylight Saving Time between # 1 June, 2008 and 27 September, 2008. @@ -873,33 +891,16 @@ # The return to legal GMT time will take place this Sunday, March 19 at 3 a.m. # ... the return to GMT+1 will be made on Sunday April 23, 2023 at 2 a.m. # https://www.mmsp.gov.ma/fr/actualites/passage-à-l%E2%80%99heure-gmt-à-partir-du-dimanche-19-mars-2023 -# -# From Paul Eggert (2023-03-14): -# For now, guess that in the future Morocco will fall back at 03:00 -# the last Sunday before Ramadan, and spring forward at 02:00 the -# first Sunday after one day after Ramadan. To implement this, -# transition dates and times for 2019 through 2087 were determined by -# running the following program under GNU Emacs 28.2. (This algorithm -# also produces the correct transition dates for 2016 through 2018, -# though the times differ due to Morocco's time zone change in 2018.) -# (let ((islamic-year 1440)) -# (require 'cal-islam) -# (while (< islamic-year 1511) -# (let ((a (calendar-islamic-to-absolute (list 9 1 islamic-year))) -# (b (+ 1 (calendar-islamic-to-absolute (list 10 1 islamic-year)))) -# (sunday 0)) -# (while (/= sunday (mod (setq a (1- a)) 7))) -# (while (/= sunday (mod b 7)) -# (setq b (1+ b))) -# (setq a (calendar-gregorian-from-absolute a)) -# (setq b (calendar-gregorian-from-absolute b)) -# (insert -# (format -# (concat "Rule\tMorocco\t%d\tonly\t-\t%s\t%2d\t 3:00\t-1:00\t-\n" -# "Rule\tMorocco\t%d\tonly\t-\t%s\t%2d\t 2:00\t0\t-\n") -# (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a)) -# (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b))))) -# (setq islamic-year (+ 1 islamic-year)))) + +# From Paul Eggert (2026-06-25): +# https://www.moroccoworldnews.com/2026/06/325034/confirmed-morocco-to-restore-gmt-on-september-20-ending-eight-year-gmt1-saga/ +# Today the Moroccan government adopted Decree No. 2.26.530, which abrogates +# the 2018 decree that put it at +01 with daylight saving during Ramadan. +# The plan is to go back to +00 without DST on 2026-09-20 at 02:00. +# From Anass Taghjichte (2026-07-03): +# https://www.sgg.gov.ma/BO/AR/3111/2026/BO_7521_Ar.pdf +# From Afaf EL MAAYATI (2026-07-06): +# https://www.mapexpress.ma/actualite/activite-gouvernementale/conseil-gouvernement-approuve-projet-decret-relatif-au-retour-lheure-legale/ # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Morocco 1939 only - Sep 12 0:00 1:00 - @@ -959,143 +960,14 @@ Rule Morocco 2025 only - Apr 6 2:00 0 - Rule Morocco 2026 only - Feb 15 3:00 -1:00 - Rule Morocco 2026 only - Mar 22 2:00 0 - -Rule Morocco 2027 only - Feb 7 3:00 -1:00 - -Rule Morocco 2027 only - Mar 14 2:00 0 - -Rule Morocco 2028 only - Jan 23 3:00 -1:00 - -Rule Morocco 2028 only - Mar 5 2:00 0 - -Rule Morocco 2029 only - Jan 14 3:00 -1:00 - -Rule Morocco 2029 only - Feb 18 2:00 0 - -Rule Morocco 2029 only - Dec 30 3:00 -1:00 - -Rule Morocco 2030 only - Feb 10 2:00 0 - -Rule Morocco 2030 only - Dec 22 3:00 -1:00 - -Rule Morocco 2031 only - Jan 26 2:00 0 - -Rule Morocco 2031 only - Dec 14 3:00 -1:00 - -Rule Morocco 2032 only - Jan 18 2:00 0 - -Rule Morocco 2032 only - Nov 28 3:00 -1:00 - -Rule Morocco 2033 only - Jan 9 2:00 0 - -Rule Morocco 2033 only - Nov 20 3:00 -1:00 - -Rule Morocco 2033 only - Dec 25 2:00 0 - -Rule Morocco 2034 only - Nov 5 3:00 -1:00 - -Rule Morocco 2034 only - Dec 17 2:00 0 - -Rule Morocco 2035 only - Oct 28 3:00 -1:00 - -Rule Morocco 2035 only - Dec 9 2:00 0 - -Rule Morocco 2036 only - Oct 19 3:00 -1:00 - -Rule Morocco 2036 only - Nov 23 2:00 0 - -Rule Morocco 2037 only - Oct 4 3:00 -1:00 - -Rule Morocco 2037 only - Nov 15 2:00 0 - -Rule Morocco 2038 only - Sep 26 3:00 -1:00 - -Rule Morocco 2038 only - Oct 31 2:00 0 - -Rule Morocco 2039 only - Sep 18 3:00 -1:00 - -Rule Morocco 2039 only - Oct 23 2:00 0 - -Rule Morocco 2040 only - Sep 2 3:00 -1:00 - -Rule Morocco 2040 only - Oct 14 2:00 0 - -Rule Morocco 2041 only - Aug 25 3:00 -1:00 - -Rule Morocco 2041 only - Sep 29 2:00 0 - -Rule Morocco 2042 only - Aug 10 3:00 -1:00 - -Rule Morocco 2042 only - Sep 21 2:00 0 - -Rule Morocco 2043 only - Aug 2 3:00 -1:00 - -Rule Morocco 2043 only - Sep 13 2:00 0 - -Rule Morocco 2044 only - Jul 24 3:00 -1:00 - -Rule Morocco 2044 only - Aug 28 2:00 0 - -Rule Morocco 2045 only - Jul 9 3:00 -1:00 - -Rule Morocco 2045 only - Aug 20 2:00 0 - -Rule Morocco 2046 only - Jul 1 3:00 -1:00 - -Rule Morocco 2046 only - Aug 5 2:00 0 - -Rule Morocco 2047 only - Jun 23 3:00 -1:00 - -Rule Morocco 2047 only - Jul 28 2:00 0 - -Rule Morocco 2048 only - Jun 7 3:00 -1:00 - -Rule Morocco 2048 only - Jul 19 2:00 0 - -Rule Morocco 2049 only - May 30 3:00 -1:00 - -Rule Morocco 2049 only - Jul 4 2:00 0 - -Rule Morocco 2050 only - May 15 3:00 -1:00 - -Rule Morocco 2050 only - Jun 26 2:00 0 - -Rule Morocco 2051 only - May 7 3:00 -1:00 - -Rule Morocco 2051 only - Jun 18 2:00 0 - -Rule Morocco 2052 only - Apr 28 3:00 -1:00 - -Rule Morocco 2052 only - Jun 2 2:00 0 - -Rule Morocco 2053 only - Apr 13 3:00 -1:00 - -Rule Morocco 2053 only - May 25 2:00 0 - -Rule Morocco 2054 only - Apr 5 3:00 -1:00 - -Rule Morocco 2054 only - May 10 2:00 0 - -Rule Morocco 2055 only - Mar 28 3:00 -1:00 - -Rule Morocco 2055 only - May 2 2:00 0 - -Rule Morocco 2056 only - Mar 12 3:00 -1:00 - -Rule Morocco 2056 only - Apr 23 2:00 0 - -Rule Morocco 2057 only - Mar 4 3:00 -1:00 - -Rule Morocco 2057 only - Apr 8 2:00 0 - -Rule Morocco 2058 only - Feb 17 3:00 -1:00 - -Rule Morocco 2058 only - Mar 31 2:00 0 - -Rule Morocco 2059 only - Feb 9 3:00 -1:00 - -Rule Morocco 2059 only - Mar 23 2:00 0 - -Rule Morocco 2060 only - Feb 1 3:00 -1:00 - -Rule Morocco 2060 only - Mar 7 2:00 0 - -Rule Morocco 2061 only - Jan 16 3:00 -1:00 - -Rule Morocco 2061 only - Feb 27 2:00 0 - -Rule Morocco 2062 only - Jan 8 3:00 -1:00 - -Rule Morocco 2062 only - Feb 12 2:00 0 - -Rule Morocco 2062 only - Dec 31 3:00 -1:00 - -Rule Morocco 2063 only - Feb 4 2:00 0 - -Rule Morocco 2063 only - Dec 16 3:00 -1:00 - -Rule Morocco 2064 only - Jan 27 2:00 0 - -Rule Morocco 2064 only - Dec 7 3:00 -1:00 - -Rule Morocco 2065 only - Jan 11 2:00 0 - -Rule Morocco 2065 only - Nov 22 3:00 -1:00 - -Rule Morocco 2066 only - Jan 3 2:00 0 - -Rule Morocco 2066 only - Nov 14 3:00 -1:00 - -Rule Morocco 2066 only - Dec 26 2:00 0 - -Rule Morocco 2067 only - Nov 6 3:00 -1:00 - -Rule Morocco 2067 only - Dec 11 2:00 0 - -Rule Morocco 2068 only - Oct 21 3:00 -1:00 - -Rule Morocco 2068 only - Dec 2 2:00 0 - -Rule Morocco 2069 only - Oct 13 3:00 -1:00 - -Rule Morocco 2069 only - Nov 17 2:00 0 - -Rule Morocco 2070 only - Oct 5 3:00 -1:00 - -Rule Morocco 2070 only - Nov 9 2:00 0 - -Rule Morocco 2071 only - Sep 20 3:00 -1:00 - -Rule Morocco 2071 only - Nov 1 2:00 0 - -Rule Morocco 2072 only - Sep 11 3:00 -1:00 - -Rule Morocco 2072 only - Oct 16 2:00 0 - -Rule Morocco 2073 only - Aug 27 3:00 -1:00 - -Rule Morocco 2073 only - Oct 8 2:00 0 - -Rule Morocco 2074 only - Aug 19 3:00 -1:00 - -Rule Morocco 2074 only - Sep 30 2:00 0 - -Rule Morocco 2075 only - Aug 11 3:00 -1:00 - -Rule Morocco 2075 only - Sep 15 2:00 0 - -Rule Morocco 2076 only - Jul 26 3:00 -1:00 - -Rule Morocco 2076 only - Sep 6 2:00 0 - -Rule Morocco 2077 only - Jul 18 3:00 -1:00 - -Rule Morocco 2077 only - Aug 22 2:00 0 - -Rule Morocco 2078 only - Jul 10 3:00 -1:00 - -Rule Morocco 2078 only - Aug 14 2:00 0 - -Rule Morocco 2079 only - Jun 25 3:00 -1:00 - -Rule Morocco 2079 only - Aug 6 2:00 0 - -Rule Morocco 2080 only - Jun 16 3:00 -1:00 - -Rule Morocco 2080 only - Jul 21 2:00 0 - -Rule Morocco 2081 only - Jun 1 3:00 -1:00 - -Rule Morocco 2081 only - Jul 13 2:00 0 - -Rule Morocco 2082 only - May 24 3:00 -1:00 - -Rule Morocco 2082 only - Jun 28 2:00 0 - -Rule Morocco 2083 only - May 16 3:00 -1:00 - -Rule Morocco 2083 only - Jun 20 2:00 0 - -Rule Morocco 2084 only - Apr 30 3:00 -1:00 - -Rule Morocco 2084 only - Jun 11 2:00 0 - -Rule Morocco 2085 only - Apr 22 3:00 -1:00 - -Rule Morocco 2085 only - May 27 2:00 0 - -Rule Morocco 2086 only - Apr 14 3:00 -1:00 - -Rule Morocco 2086 only - May 19 2:00 0 - -Rule Morocco 2087 only - Mar 30 3:00 -1:00 - -Rule Morocco 2087 only - May 11 2:00 0 - -# For dates after the somewhat-arbitrary cutoff of 2087, assume that -# Morocco will no longer observe DST. At some point this table will -# need to be extended, though quite possibly Morocco will change the -# rules first. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26 0:00 Morocco %z 1984 Mar 16 1:00 - %z 1986 0:00 Morocco %z 2018 Oct 28 3:00 - 1:00 Morocco %z + 1:00 Morocco %z 2026 Sep 20 2:00 + 0:00 - %z # Western Sahara # @@ -1111,7 +983,8 @@ Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún -1:00 - %z 1976 Apr 14 0:00 Morocco %z 2018 Oct 28 3:00 - 1:00 Morocco %z + 1:00 Morocco %z 2026 Sep 20 2:00 + 0:00 - %z # Botswana # Burundi diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/asia openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/asia --- openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/asia 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/asia 2026-10-19 12:10:20.000000000 +0000 @@ -1567,9 +1567,21 @@ # leap year calculation involved. There has never been any serious # plan to change that law.... # -# From Paul Eggert (2022-06-30): -# Go with Pournader for 1935 through spring 1979, and for timestamps -# after August 1991; go with with Shanks & Pottenger for other timestamps. +# From N.F. Hase (2026-07-26): +# Ettela'at (Tehran daily) printed a daily panel headed "taqvim-e +# Ettela'at / sa'at-ha-ye shar'i", attributed to Dr. Riyazi Kermani. +# Each panel gives today's maghrib followed by fajr, sunrise, solar noon +# and maghrib for the next day, together with the Iranian, Hijri and +# Gregorian dates.... 26 May 1979 (5 Khordād 1358) +# https://commons.wikimedia.org/wiki/File:Ettelaat13580305.pdf +# ... That also matches Movahedi's wording, that the government +# returned to DST on 26 May, and the note in the 2022 thread that the +# change was announced one day in advance on 25 May. +# +# From Paul Eggert (2026-07-27): +# Go with Pournader for 1935 through spring 1979 (with the last +# transition clarified by Hase), and for timestamps after August 1991; +# go with Shanks & Pottenger for other timestamps. # Go with Santoni's citation of the UIT for fall 1977, as 20 October 1977 # is 28 Mehr 1356, consistent with the "Mehr" in Pournader's source. # Assume that the UIT's "1930" is UTC, i.e., 24:00 local time. @@ -1614,13 +1626,13 @@ # # Rule NAME FROM TO - IN ON AT SAVE LETTER/S # Work around a bug in zic 2022a and earlier. -Rule Iran 1910 only - Jan 1 00:00 0 - +Rule Iran 1910 only - Jan 1 0:00 0 - # Rule Iran 1977 only - Mar 21 23:00 1:00 - Rule Iran 1977 only - Oct 20 24:00 0 - Rule Iran 1978 only - Mar 24 24:00 1:00 - -Rule Iran 1978 only - Aug 5 01:00 0 - -Rule Iran 1979 only - May 26 24:00 1:00 - +Rule Iran 1978 only - Aug 5 1:00 0 - +Rule Iran 1979 only - May 26 0:00 1:00 - Rule Iran 1979 only - Sep 18 24:00 0 - Rule Iran 1980 only - Mar 20 24:00 1:00 - Rule Iran 1980 only - Sep 22 24:00 0 - diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/australasia openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/australasia --- openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/australasia 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/australasia 2026-10-19 12:10:20.000000000 +0000 @@ -1744,7 +1744,7 @@ # to Japanese rule was right before 1970, ... per the current tz database # rule, the information doesn't warrant creation of a new timezone for Bonin # Islands itself and is thus as an anecdotal note for interest purpose only. -# ... [The abovementioned link] described some special timekeeping phenomenon +# ... [The link mentioned above] described some special timekeeping phenomenon # regarding Marcus island, another remote island currently owned by Japanese # in the same administrative unit as Bonin Islands. Many reports claim that # the American coastal guard on the American quarter of the island use its own diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/backward openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/backward --- openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/backward 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/backward 2026-10-19 12:10:20.000000000 +0000 @@ -38,7 +38,8 @@ # typically use this file for backward compatibility. # This file is divided into sections, one for each major reason for a -# backward compatibility link. Each section is sorted by link name. +# backward compatibility link or zone. Each section of links is +# sorted by name. # A "#= TARGET1" comment labels each link inserted only because some # .zi parsers (including tzcode through 2022e) mishandle links to links. @@ -69,7 +70,6 @@ Link America/Sao_Paulo Brazil/East Link America/Manaus Brazil/West Link Europe/Brussels CET -Link America/Chicago CST6CDT Link America/Halifax Canada/Atlantic Link America/Winnipeg Canada/Central # This line is commented out, as the name exceeded the 14-character limit @@ -86,7 +86,6 @@ Link America/Havana Cuba Link Europe/Athens EET Link America/Panama EST -Link America/New_York EST5EDT Link Africa/Cairo Egypt Link Europe/Dublin Eire # Vanguard section, for most .zi parsers. @@ -127,7 +126,6 @@ Link Africa/Tripoli Libya Link Europe/Brussels MET Link America/Phoenix MST -Link America/Denver MST7MDT Link America/Tijuana Mexico/BajaNorte Link America/Mazatlan Mexico/BajaSur Link America/Mexico_City Mexico/General @@ -349,6 +347,52 @@ # However, for various reasons many users expect to find it under Europe. Link Asia/Nicosia Europe/Nicosia Link Pacific/Honolulu HST -Link America/Los_Angeles PST8PDT Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk + + +# The backward-compatibility zones PST8PDT, MST7MDT, CST6CDT, and EST5EDT + +# Near-copy of US rules in the northamerica file, +# so that this file can be compiled separately. +# To conform to POSIX, this copy uses D instead of W for War and P for Peace. +# Rule NAME FROM TO - IN ON AT SAVE LETTER/S +Rule USback 1918 1919 - Mar lastSun 2:00 1:00 D +Rule USback 1918 1919 - Oct lastSun 2:00 0 S +Rule USback 1942 only - Feb 9 2:00 1:00 D # War +Rule USback 1945 only - Aug 14 23:00u 1:00 D # Peace +Rule USback 1945 only - Sep 30 2:00 0 S +Rule USback 1967 2006 - Oct lastSun 2:00 0 S +Rule USback 1967 1973 - Apr lastSun 2:00 1:00 D +Rule USback 1974 only - Jan 6 2:00 1:00 D +Rule USback 1975 only - Feb lastSun 2:00 1:00 D +Rule USback 1976 1986 - Apr lastSun 2:00 1:00 D +Rule USback 1987 2006 - Apr Sun>=1 2:00 1:00 D +Rule USback 2007 max - Mar Sun>=8 2:00 1:00 D +Rule USback 2007 max - Nov Sun>=1 2:00 0 S + +# From Arthur David Olson (2005-12-19): +# We generate the files specified below to guard against old files with +# obsolete information being left in the time zone binary directory. +# We limit the list to names that have appeared in previous versions of +# this time zone package. +# We do these as separate Zones rather than as Links to avoid problems if +# a particular place changes whether it observes DST. +# +# From Paul Eggert (2026-07-24): +# These zones are for backward compatibility with Unix System V (1983). +# They are ahistorical, in that they pretend standard time extends +# backward indefinitely into the past. +# They use USback (not US) rules so that they conform to POSIX instead +# of using abbreviations like EWT for Eastern War Time during World War II. +# The zones are here, not in the northamerica file, to lessen +# confusion downstream by making it clear that the zones are present +# only for backward compatibility. +# New software should use settings like TZ='America/New_York' instead +# of these backwards-compatibility zones. +# +# Zone NAME STDOFF RULES FORMAT [UNTIL] +Zone PST8PDT -8:00 USback P%sT +Zone MST7MDT -7:00 USback M%sT +Zone CST6CDT -6:00 USback C%sT +Zone EST5EDT -5:00 USback E%sT diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/europe openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/europe --- openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/europe 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/europe 2026-10-19 12:10:20.000000000 +0000 @@ -253,7 +253,7 @@ # https://www.polyomino.org.uk/british-time/bbc-19410418.png # https://www.polyomino.org.uk/british-time/ho-19410421.png -# From Sir Alexander Maxwell in the above-mentioned letter (1941-04-21): +# From Sir Alexander Maxwell (1941-04-21) in the letter mentioned above: # [N]o official designation has as far as I know been adopted for the time # which is to be introduced in May.... # I cannot think of anything better than "Double British Summer Time" @@ -401,13 +401,33 @@ # as a negative daylight saving time in winter. So, in this database # IST stands for Irish Summer Time for timestamps before 1968, and for # Irish Standard Time after that. See: -# http://www.irishstatutebook.ie/eli/1971/act/17/enacted/en/print +# https://www.irishstatutebook.ie/eli/1971/act/17/enacted/en/print # Michael Deckers (2017-06-01) gave the following URLs for Ireland's # Summer Time Act, 1925 and Summer Time Orders, 1926 and 1947: -# http://www.irishstatutebook.ie/eli/1925/act/8/enacted/en/print -# http://www.irishstatutebook.ie/eli/1926/sro/919/made/en/print -# http://www.irishstatutebook.ie/eli/1947/sro/71/made/en/print +# https://www.irishstatutebook.ie/eli/1925/act/8/enacted/en/print +# https://www.irishstatutebook.ie/eli/1926/sro/919/made/en/print +# https://www.irishstatutebook.ie/eli/1947/sro/71/made/en/print + +# From Stan Ulbrych (2026-09-12): +# Ireland's Summer Time Act, 1925 (No. 8 of 1925, see above) +# ended summer time at 02:00 GMT on the day after the third Saturday in +# September, that is, 1925-09-20. The UK's Summer Time Act, 1925, however, +# moved the UK's end date to the day after the first Saturday in October with +# immediate effect, but it did not apply to the Irish Free State. +# Ireland matched the October date only from 1926, via the Summer Time Order, +# 1926, whose recital replaces the period fixed by section 2 of the 1925 Act +# and mentions no earlier order. Moving approval of that order in the +# Dáil on 1926-03-24, Minister Kevin O'Higgins said: +# +# Deputies will remember that last year there was a discrepancy of a +# fortnight between the termination of Summer Time in the Saorstát and +# in Great Britain and Northern Ireland. As a result of that, serious +# inconvenience was caused to railway companies, and there was a certain +# amount of dislocation of postal services in the country. +# +# (See: https://www.oireachtas.ie/en/debates/debate/dail/1926-03-24/18/) +# So Dublin fell back on 1925-09-20, two weeks before London. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S # Summer Time Act, 1916 @@ -560,6 +580,8 @@ -0:25:21 - DMT 1916 May 21 2:00s -0:25:21 1:00 IST 1916 Oct 1 2:00s 0:00 GB-Eire %s 1921 Dec 6 # independence + 0:00 GB-Eire GMT/IST 1925 Sep Sun>=16 2:00s + 0:00 - GMT 1926 0:00 GB-Eire GMT/IST 1940 Feb 25 2:00s 0:00 1:00 IST 1946 Oct 6 2:00s 0:00 - GMT 1947 Mar 16 2:00s @@ -2038,7 +2060,7 @@ # From Roman Tudos (2015-07-02): # http://lex.justice.md/index.php?action=view&view=doc&lang=1&id=355077 # From Paul Eggert (2015-07-01): -# The abovementioned official link to IGO1445-868/2014 states that +# The above-mentioned official link to IGO1445-868/2014 states that # 2014-10-26's fallback transition occurred at 03:00 local time. Also, # https://www.trm.md/en/social/la-30-martie-vom-trece-la-ora-de-vara # says the 2014-03-30 spring-forward transition was at 02:00 local time. @@ -2403,10 +2425,17 @@ # https://oal.ul.pt/hora-legal/legislacao/ # working backward through references of revocation and abrogation to # Decreto-Lei 47233 of 1966-10-01, the last time DST was abolished across the -# mainland and its adjacent islands. Because of that reference, it is -# therefore assumed that DST rules in the islands prior to 1966 were like that -# of the mainland, though most legislation of the time didn't explicitly -# specify DST practices for the islands. +# mainland and its adjacent islands. +# +# From Tim Parenti (2026-05-26): +# Observance of DST on the Azores and Madeira was explicitly covered by +# mainland legislation in: +# - Portaria 11767 of 1947-03-28 for 1947, +# - Portaria 12286 of 1948-02-19 for 1948, and +# - Decreto-Lei 37048 of 1948-09-07 through its revocation in 1966. +# (See mainland commentary, above.) However, most legislation prior to 1947 +# didn't explicitly call out these "adjacent islands", so we assume that DST +# rules on the islands prior to 1947 were also like that of the mainland. Zone Atlantic/Azores -1:42:40 - LMT 1884 # Ponta Delgada -1:54:32 - HMT 1912 Jan 1 2:00u # Horta MT # Vanguard section, for zic and other parsers that support %z. @@ -2639,7 +2668,7 @@ # http://astro.uni-altai.ru/~orion/blog/2011/11/novyie-granitsyi-chasovyih-poyasov-v-sssr/ # # From Paul Eggert (2018-07-16): -# Perhaps someone could translate the above-mentioned link and use it +# Perhaps someone could translate the link mentioned above, and use it # to correct our data for the ex-Soviet Union. It cites the following: # «Поясное время и новые границы часовых поясов» / сост. П.Н. Долгов, # отв. ред. Г.Д. Бурдун - М: Комитет стандартов, мер и измерительных diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/leapseconds openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/leapseconds --- openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/leapseconds 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/leapseconds 2026-10-19 12:10:20.000000000 +0000 @@ -93,7 +93,7 @@ # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2026 Dec 28 00:00:00 +#Expires 2027 Jun 28 00:00:00 # Here are POSIX timestamps for the data in this file. # "#updated" gives the last time the leap seconds data changed @@ -102,8 +102,8 @@ # "#expires" gives the first time this file might be wrong; # if this file was derived from the IERS leap-seconds.list, # this is typically a bit less than one year after "updated". -#updated 1767698058 (2026-01-06 11:14:18 UTC) -#expires 1798416000 (2026-12-28 00:00:00 UTC) +#updated 1783323897 (2026-07-06 07:44:57 UTC) +#expires 1814140800 (2027-06-28 00:00:00 UTC) # Updated through IERS Bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat) -# File expires on 28 December 2026 +# File expires on 28 June 2027 diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/northamerica openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/northamerica --- openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/northamerica 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/northamerica 2026-10-19 12:10:20.000000000 +0000 @@ -119,7 +119,7 @@ # was the first nationwide legal time standard, and apparently # time was just called "Standard Time" or "Daylight Saving Time". -# From Paul Eggert (2019-06-04): +# From Paul Eggert (2019-06-04) and Tim Parenti (2026-07-21): # Here is the legal basis for the US federal rules. # * Public Law 65-106 (1918-03-19) implemented standard and daylight saving # time for the first time across the US, springing forward on March's last @@ -134,10 +134,15 @@ # * Public Law 89-387 (1966-04-13) reinstituted a national standard for DST, # from April's last Sunday to October's last Sunday, effective 1967. # https://www.govinfo.gov/content/pkg/STATUTE-80/pdf/STATUTE-80-Pg107.pdf -# * Public Law 93-182 (1973-12-15) moved the 1974 spring-forward to 01-06. +# * Public Law 93-182 (1973-12-15) applied DST year-round as an emergency +# measure. It took effect on the fourth Sunday after its enactment, +# effectively moving the 1974 spring-forward to 01-06. # https://www.govinfo.gov/content/pkg/STATUTE-87/pdf/STATUTE-87-Pg707.pdf -# * Public Law 93-434 (1974-10-05) moved the 1975 spring-forward to -# February's last Sunday. +# It was meant to last for 16 months or two winters (through 1975-04-27); +# however... +# * Public Law 93-434 (1974-10-05) created an exemption for much of the second +# winter, restoring standard time from the usual date of 1974-10-27 while +# moving the 1975 spring-forward up to February's last Sunday. # https://www.govinfo.gov/content/pkg/STATUTE-88/pdf/STATUTE-88-Pg1209.pdf # * Public Law 99-359 (1986-07-08) moved the spring-forward to April's first # Sunday. @@ -598,8 +603,12 @@ # Russian time, and it is more accurate to model this than to ignore it. # The database format requires an exact transition time; use the Russian # salute as a somewhat-arbitrary time for the formal transfer of control for -# all of Alaska. Sitka's UTC offset is -9:01:13; adjust its 15:30 to the -# local times of other Alaskan locations so that they change simultaneously. +# all of Alaska. +# +# From Tim Parenti (2026-08-26): +# Sitka's UT offset changed from +14:58:47 to -9:01:13, so effectuate this +# change at 15:30:00 +14:58:47, or 1867-10-19 00:31:13 UT in the Alaskan +# locations below. # From Paul Eggert (2014-07-18): # One opinion of the early 1980s turmoil in Alaska over time zones and @@ -679,7 +688,7 @@ # and are west of 169.5° W. # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Juneau 15:02:19 - LMT 1867 Oct 19 15:33:32 +Zone America/Juneau 15:02:19 - LMT 1867 Oct 19 0:31:13u -8:57:41 - LMT 1900 Aug 20 12:00 -8:00 - PST 1942 -8:00 US P%sT 1946 @@ -689,7 +698,7 @@ -8:00 US P%sT 1983 Oct 30 2:00 -9:00 US Y%sT 1983 Nov 30 -9:00 US AK%sT -Zone America/Sitka 14:58:47 - LMT 1867 Oct 19 15:30 +Zone America/Sitka 14:58:47 - LMT 1867 Oct 19 0:31:13u -9:01:13 - LMT 1900 Aug 20 12:00 -8:00 - PST 1942 -8:00 US P%sT 1946 @@ -697,7 +706,7 @@ -8:00 US P%sT 1983 Oct 30 2:00 -9:00 US Y%sT 1983 Nov 30 -9:00 US AK%sT -Zone America/Metlakatla 15:13:42 - LMT 1867 Oct 19 15:44:55 +Zone America/Metlakatla 15:13:42 - LMT 1867 Oct 19 0:31:13u -8:46:18 - LMT 1900 Aug 20 12:00 -8:00 - PST 1942 -8:00 US P%sT 1946 @@ -707,14 +716,14 @@ -9:00 US AK%sT 2018 Nov 4 2:00 -8:00 - PST 2019 Jan 20 2:00 -9:00 US AK%sT -Zone America/Yakutat 14:41:05 - LMT 1867 Oct 19 15:12:18 +Zone America/Yakutat 14:41:05 - LMT 1867 Oct 19 0:31:13u -9:18:55 - LMT 1900 Aug 20 12:00 -9:00 - YST 1942 -9:00 US Y%sT 1946 -9:00 - YST 1969 -9:00 US Y%sT 1983 Nov 30 -9:00 US AK%sT -Zone America/Anchorage 14:00:24 - LMT 1867 Oct 19 14:31:37 +Zone America/Anchorage 14:00:24 - LMT 1867 Oct 19 0:31:13u -9:59:36 - LMT 1900 Aug 20 12:00 -10:00 - AST 1942 -10:00 US A%sT 1967 Apr @@ -722,7 +731,7 @@ -10:00 US AH%sT 1983 Oct 30 2:00 -9:00 US Y%sT 1983 Nov 30 -9:00 US AK%sT -Zone America/Nome 12:58:22 - LMT 1867 Oct 19 13:29:35 +Zone America/Nome 12:58:22 - LMT 1867 Oct 19 0:31:13u -11:01:38 - LMT 1900 Aug 20 12:00 -11:00 - NST 1942 -11:00 US N%sT 1946 @@ -731,7 +740,7 @@ -11:00 US B%sT 1983 Oct 30 2:00 -9:00 US Y%sT 1983 Nov 30 -9:00 US AK%sT -Zone America/Adak 12:13:22 - LMT 1867 Oct 19 12:44:35 +Zone America/Adak 12:13:22 - LMT 1867 Oct 19 0:31:13u -11:46:38 - LMT 1900 Aug 20 12:00 -11:00 - NST 1942 -11:00 US N%sT 1946 @@ -1760,11 +1769,56 @@ -5:00 Canada E%sT 1946 -5:00 Toronto E%sT 1974 -5:00 Canada E%sT -# For Atikokan see America/Panama. +# From Tim Parenti (2026-09-21), per Paul Eggert (2000-10-02, 2006-07-17): +# In the northwest of the province, most portions of Kenora, Rainy River, and +# Thunder Bay Districts lying broadly west of 90°W longitude have historically +# been aligned with neighboring Manitoba and use America/Winnipeg, in +# accordance with section 2(2) of Ontario's Time Act, RSO 1990 chapter T.9: +# https://www.ontario.ca/laws/statute/90t09 +# With Manitoba now opting to stay on -05 year-round, if any of these areas do +# not follow, it would require a new zone; however, given the short leadtime +# ahead of a potential divergence on 2026-11-01 and in the interest of not +# creating zones that may not be needed, assume for the time being that they +# will. +# +# In practice, there are several exceptions to the 90°W dividing line set by +# the province, all of which technically contravene the official Ontario rules: +# - An area around Big Trout Lake in Kenora District observes Central Time +# (-06/-05) despite extending east of 90°W. +# - An area around Upsala in the southwest of Thunder Bay District observes +# Eastern Time (-05/-04) like America/Toronto despite extending west of +# 90°W. +# - Atikokan in the east of Rainy River District has observed year-round -05 +# (EST) since at least 1952; this matches America/Panama since our 1970 +# cutoff. +# - Pickle Lake and the Mishkeegogamang First Nation (formerly New Osnaburgh) +# in Kenora District have also observed year-round -05 (EST) since at least +# 1998, though it is less clear how far back that arrangement goes; assume +# the area is covered in the same way as Atikokan. +# See the 'backzone' file for further commentary. +# At time of writing, it is not yet known to what extent Manitoba's 2026-09-17 +# announcement may spur further adaptations in northwestern Ontario; see +# Manitoba, below. # Manitoba +# From Paul Eggert (2026-05-08): +# For 1916 timestamps America/Winnipeg covers only a small region. See: +# Cassidy C. Winnipeg’s 110-year history with daylight time. +# Winnipeg Free Press. 2026-05-06. +# https://www.winnipegfreepress.com/our-communities/correspondents/2026/05/06/winnipegs-110-year-history-with-daylight-time +# Of the 1916 experiment, Cassidy writes: “As rural areas and nearby +# urban centres such as Selkirk and Brandon did not adopt DST, the +# City of Winnipeg essentially had its own time zone.” Cassidy also +# writes that province-wide DST came into effect on 1963-05-12. +# +# Shanks & Pottenger write that Winnipeg did not observe DST in 1964 and 1965. +# Although dubious in the light of Cassidy’s article, we lack a better source. +# Perhaps S&P’s data are for the train stations, not for the city? +# Also, S&P say Manitoba switched at 02:00 (not 02:00s) starting in 1966. +# Since 02:00s is clearly correct for 1967 on, assume 02:00s in 1966 too. + # From Rob Douglas (2006-04-06): # the old Manitoba Time Act - as amended by Bill 2, assented to # March 27, 1987 ... said ... @@ -1779,10 +1833,39 @@ # the 1987 version would apply - the changeover was at 2:00 Central # Standard Time (i.e. not until 3:00 Central Daylight Time). -# From Paul Eggert (2006-04-10): -# Shanks & Pottenger say Manitoba switched at 02:00 (not 02:00s) -# starting 1966. Since 02:00s is clearly correct for 1967 on, assume -# it was also 02:00s in 1966. +# From Tim Parenti (2026-09-29): +# As much of western Canada began announcing year-round DST in early 2026, +# Manitoba Premier Wab Kinew publicly mused on forming a "Prairie time zone" by +# joining Saskatchewan and Alberta on year-round -06, while committing to +# conducting a public engagement survey on the matter. The results, however, +# showed that while "[a] total of 92 per cent of Manitobans surveyed wanted to +# see an end to seasonal time changes", "[a] majority of Manitobans (58 per +# cent) preferred to stay on permanent DST, while 34 per cent voted to +# eliminate the time change but stay on standard time." +# +# The survey results were published on Thursday 2026-09-17 alongside a policy +# announcement adopting permanent DST, or year-round -05, just over 6 weeks +# before clocks would otherwise fall back on 2026-11-01. +# https://news.gov.mb.ca/news/?item=75397 +# https://www.cbc.ca/news/canada/manitoba/daylight-time-manitoba-9.7347844 +# +# While other potential options would have required further legislation, the +# Official Time Amendment Act (Bill 2 of the 42nd Legislature's 5th Session), +# assented to 2023-05-30, provides for year-round -05 upon proclamation. +# https://web2.gov.mb.ca/laws/statutes/2023/pdf/c00423.pdf +# Order in Council 221/2026, issued 2026-09-23, directed the proclamation +# bringing the Act into force on 2026-10-31, 26 hours before clocks would +# otherwise fall back. +# https://oic.gov.mb.ca/OICDocs/2026/09/Municipal%20and%20Northern%20Relations.260923.%20Official%20Time%20Amendment%20Act.2212026.pdf +# https://web2.gov.mb.ca/laws/statutes/proclamations/2023c4(2026-10-31).pdf +# +# The Act further allows for the Lieutenant Governor in Council to, on +# recommendation of the relevant minister, "make regulations varying the +# reckoning" of official time in Manitoba, provided the minister has "due +# regard for the applicable time zone in neighbouring jurisdictions." +# +# Use a temporary hack like Alberta’s to work around potential CLDR +# limitations. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Winn 1916 only - Apr 23 0:00 1:00 D @@ -1812,7 +1895,11 @@ # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Winnipeg -6:28:36 - LMT 1887 Jul 16 -6:00 Winn C%sT 2006 - -6:00 Canada C%sT + -6:00 Canada C%sT 2026 Oct 31 + # Temporary hack; see above. + -6:00 Canada CDT 2026 Nov 1 2:00 + # End of temporary hack. + -5:00 - EST # Saskatchewan @@ -1875,6 +1962,28 @@ # long and rather painful to read. # http://www.qp.gov.sk.ca/documents/English/Statutes/Statutes/T14.pdf +# From Heitor David Pinto (2026-05-14): +# In Saskatchewan, a bill was passed to replace the Time Act. It sets UTC-6 all +# year in the whole province, including Lloydminster, but allows the government +# to issue regulations specifying a different time in localities that request +# so: +# https://docs.legassembly.sk.ca/legdocs/Bills/30L2S/Bill30-58.pdf +# The bill ... received royal assent today. +# From Tim Parenti (2026-05-14): +# In light of Alberta joining Saskatchewan on year-round -06, this simplifies +# the prior Act's framework for the many local exceptions to year-round -06 in +# border areas, by extending province-wide the notion of "time option areas" +# which can be prescribed by regulation "if it is in the provincial interest" +# for those areas to observe either "UTC-5, UTC-6 or UTC-7 for all or part of +# the year" on at least 30 days' notice. +# The new Act comes into force by order of the Lieutenant Governor in Council. +# From Tim Parenti (2026-09-21): +# With Manitoba now adopting year-round -05, the area around Creighton will +# likely wish to follow. As the area doesn't have a special charter like +# Lloydminster, the existing de facto arrangement technically violates +# provincial law already, but once the new Act takes effect it will better +# allow for continued alignment with Manitoba, per the above. + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Regina 1918 only - Apr 14 2:00 1:00 D Rule Regina 1918 only - Oct 27 2:00 0 S @@ -1925,6 +2034,49 @@ # Boyer JP. Forcing Choice: The Risky Reward of Referendums. Dundum. 2017. # ISBN 978-1459739123. +# From Roozbeh Pournader (2026-04-20): +# https://calgaryherald.com/opinion/columnists/bell-alberta-daylight-time-year-round-premier-danielle-smith +# +# From Tim Parenti (2026-04-23): +# Section 3 of Bill 31, the Red Tape Reduction Statutes Amendment Act, 2026 +# https://docs.assembly.ab.ca/LADDAR_files/docs/bills/bill/legislature_31/session_2/20251023_bill-031.pdf +# would repeal the Daylight Saving Time Act in the Revised Statutes of Alberta +# 2000 Chapter D-5: +# https://web.archive.org/web/20240128134751/https://kings-printer.alberta.ca/documents/Acts/D05.pdf +# ...and substitutes a new chapter with language that closely parallels the +# original. The new title is the Official Time Act and will be numbered +# Chapter O-5.7. The Act establishes a standard time of UTC−6 without +# replacing the language previously used to effectuate DST. +# +# From Tim Parenti (2026-06-19): +# After receiving Royal Assent on 2026-05-14, Order in Council 204/2026 was +# issued on 2026-06-18 proclaiming the relevant section of the bill in force on +# the same date. Order in Council 206/2026, issued the same day, uses the +# regulatory authority within the Act to prescribe the official term "Alberta +# Time"; we use the traditional abbreviation CST for consistency. +# https://kings-printer.alberta.ca/Documents/Orders/Orders_in_Council/2026/2026_204.pdf +# https://kings-printer.alberta.ca/Documents/Orders/Orders_in_Council/2026/2026_206.pdf +# +# Since wall clock times do not diverge from past practice until 2026-11-01, +# use that transition date for now to work around potential CLDR limitations in +# the meantime; see British Columbia, below. +# +# From Paul Eggert (2026-07-02): +# The temporary hack for Alberta is needed for CLDR 48.2 (2026-03-17) +# and earlier, not the CLDR 48.1-and-earlier which drives BC’s temporary hack. +# Only a few platforms track minor CLDR releases, though, so the two +# temporary hacks have roughly the same effect in practice. +# +# The term “Alberta Time” is legally prescribed from yesterday until +# 2031-06-30, when the regulation in OiC 206/2026 expires to ensure that the +# term is reviewed by then for relevancy and need. This plan for possible +# obsolescence affects neither timekeeping nor TZDB’s data, which do +# not contain the string “Alberta Time”. +# +# From Tim Parenti (2026-07-21): +# The new Official Time Act is now in the Revised Statutes as Chapter O-5.7: +# https://kings-printer.alberta.ca/documents/Acts/O05p7.pdf + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Edm 1918 1919 - Apr Sun>=8 2:00 1:00 D Rule Edm 1918 only - Oct 27 2:00 0 S @@ -1942,7 +2094,11 @@ # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Edmonton -7:33:52 - LMT 1906 Sep -7:00 Edm M%sT 1987 - -7:00 Canada M%sT + -7:00 Canada M%sT 2026 Jun 18 + # Temporary hack; see above. + -7:00 Canada MDT 2026 Nov 1 2:00 + # End of temporary hack. + -6:00 - CST # British Columbia @@ -1985,22 +2141,23 @@ # on March 8 will be the last time change, ending twice-yearly clock changes.” # https://news.gov.bc.ca/releases/2026AG0013-000209 # -# From Paul Eggert (2026-03-07): +# From Paul Eggert (2026-09-23): # The law says that 21 hours after the usual 2026-03-08 02:00 switch from -# PST to PDT, the next day inaugurates the new standard time Pacific Time, +# PST to PDT, the next day inaugurated the new standard time Pacific Time, # i.e., just one clock change but two name changes separated by 21 hours. # PT, the obvious abbreviation for Pacific Time, is one letter too short # to conform to TZDB’s (and POSIX’s) [-+[:alnum:]]{3,6} requirements. -# I asked the BC government for advice, with no response. For now, do this: +# For now, do this: # 1. As a temporary hack, pretend that the BC law takes effect # not on 2026-03-09 at 00:00, but on 2026-11-01 at 02:00. -# This pretense works around a limitation in CLDR v48.2 (2026-03-17), +# This pretense works around a limitation in CLDR 48.1 (2026-01-08), # which would otherwise say the interval uses “Pacific Standard Time”. # (Below, this temporary hack is marked “Temporary hack; see above.”) # Strictly speaking this hack is incorrect since the interval uses # standard time, but it does have the right UT offset and it # works around the CLDR limitation. We should be able to remove -# the temporary hack after CLDR is fixed. +# the temporary hack by November when there would be little point +# to keeping it anyway. # 2. After the BC law takes effect, model the time as MST sans DST. # We can change this later if another conforming non-numeric abbreviation # for Pacific Time becomes more popular. Possibilities include: @@ -2008,27 +2165,52 @@ # and already used in parts of BC and in Yukon # PDT - almost as software-friendly, but confusing because it implies # it is DST and is paired with PST, whereas PT is standard time -# PST - straightforward but even more confusing, -# and will likely break much software that assumes PST is -08 # -07 - accurate and clear in itself, but makes BC look odd vs neighbors -# CPT, CPST - for Canadian Pacific (Standard) Time, -# by analogy with AEST in Australia -# P-T - conforming approximation to “PT” -# PT+ - like P-T but suggesting one-hour advance over PST - -# From Chris Walton (2026-03-15): -# The Regional District of East Kootenay is planning to move to year-round -# Mountain Standard Time (MST) on November 1, 2026.... -# https://www.rdek.bc.ca/news/entry/rdek_board_moves_to_transition_to_year_round_mountain_standard_time -# (2026-03-17): -# The final decision East Kootenay made a few days ago may turn out not to -# be final after all. They are going to reopen the debate next month! +# PCT - as I understand it, inspired by the phrase “Pacific Coast Time” +# though legally it’s “Pacific Time”; suggested by the BC government +# + +# From Tim Parenti (2026-08-21): +# In the southeast of the province, the Regional District of East Kootenay +# (RDEK), Columbia Shuswap Regional District’s Electoral Area A (Rural Golden), +# and the Town of Golden have all historically been aligned with neighboring +# Alberta and use America/Edmonton. +# +# Shortly after the BC provincial government announced its adoption of +# year-round -07, the RDEK Board of Directors on 2026-03-13 initially voted +# narrowly, 8–7, that it would fall back one last time to rejoin the rest of BC +# on -07 from November 2026. However, citing the rushed decision and lack of +# feedback from residents, Mayor Steve Fairbairn of Elkford used his power to +# ask the question be called a second time, remarking, “Pardon the pun, but +# this is not a time-sensitive issue,” and the initial decision was rescinded +# by the RDEK Board at its 2026-04-10 meeting. # https://www.cbc.ca/news/canada/british-columbia/what-time-is-it-in-the-east-kootenay-debate-9.7132624 -# From Paul Eggert (2026-03-17): -# Mayor Steve Fairbairn of Elkford asked the question be called a second time, -# saying, “Pardon the pun, but this is not a time-sensitive issue.” -# For now, merely mention the potential change in these comments. -# If it happens it would likely affect clocks starting 2027-03-14 at 02:00. +# In the ensuing months, after Alberta announced and implemented its similar +# shift to “permanent DST” (see above), RDEK coordinated a public survey across +# all of the relevant BC communities. The survey found 89% of respondents in +# favor of ending seasonal time changes, with 66% of that group preferring to +# remain aligned with Alberta time on year-round -06 instead of the rest of BC. +# In line with those results, the RDEK Board adopted year-round -06 at its +# 2026-08-14 meeting. +# https://www.cbc.ca/news/canada/british-columbia/east-kootenay-stops-changing-clocks-9.7308201 +# +# From Tim Parenti (2026-09-24): +# Echoing RDEK’s earlier false step, the Town of Golden initially opted for +# year-round -07 by a 4–2 Council vote on 2026-09-01. This was met with +# significant pushback from residents preferring to maintain the existing +# alignment with RDEK and Alberta, with a formal petition swiftly gathering +# 2,395 signatures in two weeks from the town of 3,986 and some smaller +# neighboring communities. In response, Council unanimously rescinded the +# resolution at the following meeting on 2026-09-22, and unanimously replaced +# it with year-round -06 to keep the regional alignment. +# Acknowledging that “its initial move was driven in part by concerns about +# dark winter mornings and pedestrian safety for children travelling to +# school”, the new resolution directs town staff to partner on safety supports +# and commits to reviewing the decision and its impacts in October 2027. +# https://www.ctvnews.ca/calgary/article/golden-bc-council-reverses-course-on-time-zone-opts-for-mountain-daylight-time/ +# At time of writing, the surrounding CSRD Area A is yet to formalize its own +# decision following a 2026-09-10 deferral “to gather and assess further +# information”, but is expected to follow. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Vanc 1918 only - Apr 14 2:00 1:00 D @@ -2045,7 +2227,7 @@ -8:00 Vanc P%sT 1987 -8:00 Canada P%sT 2026 Mar 9 # Temporary hack; see above. - -8:00 1:00 PDT 2026 Nov 1 02:00 + -8:00 Canada PDT 2026 Nov 1 2:00 # End of temporary hack. -7:00 - MST Zone America/Dawson_Creek -8:00:56 - LMT 1884 @@ -2373,6 +2555,25 @@ # about 1970, and uses PST for standard time in Yukon since then. Consistent # with that, use MST for -07, the new standard time in Yukon effective Nov. 1. +# From Tim Parenti (2026-04-21): +# "[Northwest Territories] Premier R.J. Simpson announced Monday that the +# territory will move to end seasonal time changes and will adopt a year-round +# time standard instead. ... Simpson has previously said the territory wouldn't +# end seasonal time changes until Alberta does." +# https://www.cbc.ca/news/canada/north/nwt-ends-daylight-saving-9.7170964 +# +# From Tim Parenti (2026-07-24): +# Now that Alberta has adopted year-round -06, NWT plans to follow through with +# the same. Bill 13 of the 19th Assembly's 2nd Session, assented to +# 2021-03-31, provides the NWT Commissioner in Executive Council with authority +# to fix a year-round standard time: +# https://www.ntlegislativeassembly.ca/sites/default/files/legacy/bill_13_-_reprint_-_interpretation_a.pdf +# +# From Paul Eggert (2026-08-21): +# The regulations were registered 2026-08-18 and came into force today: +# https://www.justice.gov.nt.ca/en/files/legislation/interpretation/interpretation.r2.pdf +# Use a temporary hack like Alberta’s. + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule NT_YK 1918 only - Apr 14 2:00 1:00 D Rule NT_YK 1918 only - Oct 27 2:00 0 S @@ -2414,7 +2615,11 @@ Zone America/Inuvik 0 - -00 1953 # Inuvik founded -8:00 NT_YK P%sT 1979 Apr lastSun 2:00 -7:00 NT_YK M%sT 1980 - -7:00 Canada M%sT + -7:00 Canada M%sT 2026 Aug 21 + # Temporary hack; see above. + -7:00 Canada MDT 2026 Nov 1 2:00 + # End of temporary hack. + -6:00 - CST Zone America/Whitehorse -9:00:12 - LMT 1900 Aug 20 -9:00 NT_YK Y%sT 1965 -9:00 Yukon Y%sT 1966 Feb 27 0:00 diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/southamerica openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/southamerica --- openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/southamerica 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/southamerica 2026-10-19 12:10:20.000000000 +0000 @@ -1353,20 +1353,9 @@ # promulgated 2022-07-14 and published 2022-08-13: # https://www.diariooficial.interior.gob.cl/publicaciones/2022/08/13/43327/01/2172567.pdf # https://www.bcn.cl/leychile/navegar?idNorma=1179983 -# -# From Paul Eggert (2022-08-17): -# Although the presidential decree stops at fall 2026, assume that -# similar DST rules will continue thereafter. -# From Paul Eggert (2025-01-15): -# Diario Regional Aysén's Sebastián Martel reports that 94% of Aysén -# citizens polled in November favored changing the rules from -# -04/-03-with-DST to -03 all year... -# https://www.diarioregionalaysen.cl/noticia/actualidad/2024/12/presentan-decision-que-gano-la-votacion-sobre-el-cambio-del-huso-horario-en-aysen -# # From Yonathan Dossow (2025-03-20): -# [T]oday we have more confirmation of the change. [Aysén] region will keep -# UTC-3 all year... +# [Aysén] region will keep UTC-3 all year... # https://www.cnnchile.com/pais/region-de-aysen-mantendra-horario-de-verano-todo-el-ano_20250320/ # https://www.latercera.com/nacional/noticia/tras-consulta-ciudadana-region-de-aysen-mantendra-el-horario-de-verano-durante-todo-el-ano/ # https://x.com/min_interior/status/1902692504270672098 @@ -1378,6 +1367,14 @@ # https://www.bcn.cl/leychile/Navegar?idNorma=1211955 # Model this as a change to standard offset effective 2025-03-20. +# From Paul Eggert (2026-08-11): +# Chile’s timekeeping regime is renewed by Decreto 98 of 2026 of the +# Ministry of the Interior, Undersecretariat of the Interior, +# promulgated 2026-06-30 and published 2026-07-02: +# https://www.bcn.cl/leychile/navegar?idNorma=1225724 +# Although this decree stops at fall 2029, assume that +# similar DST rules will continue thereafter. + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Chile 1927 1931 - Sep 1 0:00 1:00 - Rule Chile 1928 1932 - Apr 1 0:00 0 - @@ -1495,13 +1492,19 @@ # Milne gives 4:56:16.4 for Bogotá time in 1899. He writes, # "A variation of fifteen minutes in the public clocks of Bogota is not rare." +# From Paul Eggert (2026-07-17): +# The 1992 spring forward was May 2 at 00:00. See: +# Jiménez FA. La noche en que Colombia perdió una hora para encarar el apagón, +# ¿se repetirá la historia en 2026? El Colombiano. 2026-06-21. +# https://www.elcolombiano.com/negocios/colombia-perdio-una-hora-para-evitar-apagon-horario-gaviria-LF37983109 + # From Alois Treindl (2022-11-10): # End of time change in Colombia 1993 ... should be 6 February 24h ... # DECRETO 267 DE 1993 # https://www.suin-juriscol.gov.co/viewDocument.asp?ruta=Decretos/1061335 # Rule NAME FROM TO - IN ON AT SAVE LETTER/S -Rule CO 1992 only - May 3 0:00 1:00 - +Rule CO 1992 only - May 2 0:00 1:00 - Rule CO 1993 only - Feb 6 24:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] #STDOFF -4:56:16.4 diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/tzmappings.override openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/tzmappings.override --- openjdk-25-25.0.4.1+1/src/java.base/share/data/tzdata/tzmappings.override 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/data/tzdata/tzmappings.override 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -26,7 +26,19 @@ # Extra definitions for Windows /lib/tzmappings file. These entries # replace the existing (Windows Zone Name):(REGION) entries, or are added # as new entries - +# # Example entries # Foo Standard Time:US:America/Los_Angeles: # Bar Standard Time:001:Asia/Tokyo: + +# tz2026b: British Columbia +# https://techcommunity.microsoft.com/blog/dstblog/interim-guidance-for-british-columbia-time-zone-changes-2026/4544988 +British Columbia Standard Time:001:America/Vancouver: + +# tz2026c: Alberta +# https://techcommunity.microsoft.com/blog/dstblog/interim-guidance-for-alberta-time-zone-changes-2026/4545015 +Alberta Standard Time:001:America/Edmonton: + +# tz2026e: Manitoba +# https://techcommunity.microsoft.com/blog/dstblog/interim-guidance-for-manitoba-permanent-dst-2026/4562488 +Manitoba Standard Time:001:America/Winnipeg: diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/native/libjava/Reference.c openjdk-25-25.0.5+8/src/java.base/share/native/libjava/Reference.c --- openjdk-25-25.0.4.1+1/src/java.base/share/native/libjava/Reference.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/native/libjava/Reference.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,12 @@ JVM_WaitForReferencePendingList(env); } +JNIEXPORT jobject JNICALL +Java_java_lang_ref_Reference_get0(JNIEnv *env, jobject ref) +{ + return JVM_ReferenceGet(env, ref); +} + JNIEXPORT jboolean JNICALL Java_java_lang_ref_Reference_refersTo0(JNIEnv *env, jobject ref, jobject o) { diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/native/libjli/java.c openjdk-25-25.0.5+8/src/java.base/share/native/libjli/java.c --- openjdk-25-25.0.4.1+1/src/java.base/share/native/libjli/java.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/native/libjli/java.c 2026-10-19 12:10:20.000000000 +0000 @@ -1058,7 +1058,7 @@ SetMainModule(const char *s) { static const char format[] = "-Djdk.module.main=%s"; - char* slash = JLI_StrChr(s, '/'); + const char* slash = JLI_StrChr(s, '/'); size_t s_len, def_len; char *def; diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/native/libjli/jli_util.c openjdk-25-25.0.5+8/src/java.base/share/native/libjli/jli_util.c --- openjdk-25-25.0.4.1+1/src/java.base/share/native/libjli/jli_util.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/native/libjli/jli_util.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, 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 @@ -87,7 +87,7 @@ jboolean JLI_HasSuffix(const char *s1, const char *s2) { - char *p = JLI_StrRChr(s1, '.'); + const char* p = JLI_StrRChr(s1, '.'); if (p == NULL || *p == '\0') { return JNI_FALSE; } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/share/native/libverify/check_code.c openjdk-25-25.0.5+8/src/java.base/share/native/libverify/check_code.c --- openjdk-25-25.0.4.1+1/src/java.base/share/native/libverify/check_code.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/share/native/libverify/check_code.c 2026-10-19 12:10:20.000000000 +0000 @@ -3832,7 +3832,7 @@ case JVM_SIGNATURE_CLASS: { char buffer_space[256]; char *buffer = buffer_space; - char *finish = strchr(p, JVM_SIGNATURE_ENDCLASS); + const char* finish = strchr(p, JVM_SIGNATURE_ENDCLASS); int length; if (finish == NULL) { /* Signature must have ';' after the class name. diff -Nru openjdk-25-25.0.4.1+1/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java openjdk-25-25.0.5+8/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java --- openjdk-25-25.0.4.1+1/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ import java.security.GeneralSecurityException; import java.util.Base64; import java.util.Locale; -import java.util.Properties; import sun.net.www.HeaderParser; import sun.net.www.protocol.http.AuthenticationInfo; @@ -203,10 +202,10 @@ * @param p A source of header values for this connection, not used because * HeaderParser converts the fields to lower case, use raw instead * @param raw The raw header field. - * @return true if all goes well, false if no headers were set. + * @throws IOException if no headers were set */ @Override - public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) throws IOException { // no need to synchronize here: // already locked by s.n.w.p.h.HttpURLConnection assert conn.isLockHeldByCurrentThread(); @@ -220,9 +219,8 @@ response = buildType3Msg (msg); } conn.setAuthenticationProperty(getHeaderName(), response); - return true; - } catch (IOException | GeneralSecurityException e) { - return false; + } catch (GeneralSecurityException e) { + throw new IOException(e); } } @@ -232,8 +230,7 @@ return result; } - private String buildType3Msg (String challenge) throws GeneralSecurityException, - IOException { + private String buildType3Msg (String challenge) throws GeneralSecurityException { /* First decode the type2 message to get the server nonce */ /* nonce is located at type2[24] for 8 bytes */ diff -Nru openjdk-25-25.0.4.1+1/src/java.base/unix/native/libjava/TimeZone_md.c openjdk-25-25.0.5+8/src/java.base/unix/native/libjava/TimeZone_md.c --- openjdk-25-25.0.4.1+1/src/java.base/unix/native/libjava/TimeZone_md.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/unix/native/libjava/TimeZone_md.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,7 @@ { static const char *zidir = "zoneinfo/"; - char *pos = strstr((const char *)str, zidir); + char* pos = strstr(str, zidir); if (pos == NULL) { return NULL; } @@ -352,33 +352,15 @@ } static char * -mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) { +getJavaTimezoneFromPlatform(const char *tz_buf, size_t tz_len, const char *mapfilename) { FILE *tzmapf; - char mapfilename[PATH_MAX + 1]; char line[256]; int linecount = 0; - char *tz_buf = NULL; - char *temp_tz = NULL; char *javatz = NULL; - size_t tz_len = 0; - /* On AIX, the TZ environment variable may end with a comma - * followed by modifier fields until early AIX6.1. - * This restriction has been removed from AIX7. */ - - tz_buf = strdup(tz); - tz_len = strlen(tz_buf); - - /* Open tzmappings file, with buffer overrun check */ - if ((strlen(java_home_dir) + 15) > PATH_MAX) { - jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir); - goto tzerr; - } - strcpy(mapfilename, java_home_dir); - strcat(mapfilename, "/lib/tzmappings"); if ((tzmapf = fopen(mapfilename, "r")) == NULL) { jio_fprintf(stderr, "can't open %s\n", mapfilename); - goto tzerr; + return NULL; } while (fgets(line, sizeof(line), tzmapf) != NULL) { @@ -431,10 +413,58 @@ break; } } + (void) fclose(tzmapf); + return javatz; +} + +static char * +mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) { + char mapfilename[PATH_MAX + 1]; + char *tz_buf = NULL; + char *javatz = NULL; + char *temp_tz = NULL; + size_t tz_len = 0; + + /* On AIX, the TZ environment variable may end with a comma + * followed by modifier fields until early AIX6.1. + * This restriction has been removed from AIX7. */ + + tz_buf = strdup(tz); + if (tz_buf == NULL) { + jio_fprintf(stderr, "Failed to allocate timezone buffer\n"); + goto tzerr; + } + tz_len = strlen(tz_buf); + + /* Open tzmappings file, with buffer overrun check */ + if ((strlen(java_home_dir) + 15) > PATH_MAX) { + jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir); + goto tzerr; + } + strcpy(mapfilename, java_home_dir); + strcat(mapfilename, "/lib/tzmappings"); + + // First attempt to find the Java timezone for the full tz string + javatz = getJavaTimezoneFromPlatform(tz_buf, tz_len, mapfilename); + + // If no match was found, check for timezone with truncated value + if (javatz == NULL) { + temp_tz = strchr(tz, ','); + tz_len = (temp_tz == NULL) ? strlen(tz) : temp_tz - tz; + free((void *) tz_buf); + tz_buf = (char *)malloc(tz_len + 1); + if (tz_buf == NULL) { + jio_fprintf(stderr, "Failed to allocate timezone buffer\n"); + goto tzerr; + } + memcpy(tz_buf, tz, tz_len); + tz_buf[tz_len] = '\0'; + javatz = getJavaTimezoneFromPlatform(tz_buf, tz_len, mapfilename); + } tzerr: - if (tz_buf != NULL ) { + if (tz_buf != NULL) { free((void *) tz_buf); } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/unix/native/libnet/NetworkInterface.c openjdk-25-25.0.5+8/src/java.base/unix/native/libnet/NetworkInterface.c --- openjdk-25-25.0.4.1+1/src/java.base/unix/native/libnet/NetworkInterface.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/unix/native/libnet/NetworkInterface.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,10 +58,14 @@ #endif #define CHECKED_MALLOC3(_pointer, _type, _size) \ + CHECKED_MALLOC4(_pointer, _type, _size, {}) + +#define CHECKED_MALLOC4(_pointer, _type, _size, _onFailure) \ do { \ _pointer = (_type)malloc(_size); \ if (_pointer == NULL) { \ JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \ + do _onFailure while (0); \ return ifs; /* return untouched list */ \ } \ } while(0) @@ -201,7 +205,7 @@ netif *ifs, *curr; jboolean isCopy; const char* name_utf; - char *colonP; + const char* colonP; jobject obj = NULL; if (name != NULL) { @@ -995,7 +999,7 @@ // If "new" then create a netif structure and insert it into the list. if (currif == NULL) { - CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE); + CHECKED_MALLOC4(currif, netif *, sizeof(netif) + IFNAMESIZE, { free(addrP); }); currif->name = (char *)currif + sizeof(netif); strncpy(currif->name, name, IFNAMESIZE); currif->name[IFNAMESIZE - 1] = '\0'; @@ -1027,7 +1031,10 @@ } if (currif == NULL) { - CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE); + CHECKED_MALLOC4(currif, netif *, sizeof(netif) + IFNAMESIZE, { + free(addrP); + free(parent); + }); currif->name = (char *)currif + sizeof(netif); strncpy(currif->name, vname, IFNAMESIZE); currif->name[IFNAMESIZE - 1] = '\0'; @@ -1039,7 +1046,11 @@ parent->childs = currif; } - CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size); + CHECKED_MALLOC4(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size, { + free(addrP); + free(parent); + free(currif); + }); memcpy(tmpaddr, addrP, sizeof(netaddr)); if (addrP->addr != NULL) { tmpaddr->addr = (struct sockaddr *) diff -Nru openjdk-25-25.0.4.1+1/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java openjdk-25-25.0.5+8/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java --- openjdk-25-25.0.4.1+1/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java 2026-10-19 12:10:20.000000000 +0000 @@ -91,6 +91,7 @@ private native long getCredentialsHandle (String user, String domain, String password); - private native byte[] getNextToken (long crdHandle, byte[] lastToken, Status returned); + private native byte[] getNextToken (long crdHandle, byte[] lastToken, Status returned) + throws IOException; } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java openjdk-25-25.0.5+8/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java --- openjdk-25-25.0.4.1+1/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,7 @@ package sun.net.www.protocol.http.ntlm; import java.io.IOException; -import java.net.InetAddress; import java.net.PasswordAuthentication; -import java.net.UnknownHostException; import java.net.URL; import java.util.Locale; import sun.net.NetProperties; @@ -204,10 +202,10 @@ * @param p A source of header values for this connection, not used because * HeaderParser converts the fields to lower case, use raw instead * @param raw The raw header field. - * @return true if all goes well, false if no headers were set. + * @throws IOException if no headers were set */ @Override - public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) throws IOException { // no need to synchronize here: // already locked by s.n.w.p.h.HttpURLConnection @@ -224,10 +222,9 @@ if (seq.isComplete()) { conn.authObj(null); } - return true; } catch (IOException e) { conn.authObj(null); - return false; + throw e; } } } diff -Nru openjdk-25-25.0.4.1+1/src/java.base/windows/native/libnet/NTLMAuthSequence.c openjdk-25-25.0.5+8/src/java.base/windows/native/libnet/NTLMAuthSequence.c --- openjdk-25-25.0.4.1+1/src/java.base/windows/native/libnet/NTLMAuthSequence.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.base/windows/native/libnet/NTLMAuthSequence.c 2026-10-19 12:10:20.000000000 +0000 @@ -232,6 +232,8 @@ } if (ss < 0) { + SetLastError(ss); + JNU_ThrowIOExceptionWithLastError(env, "InitializeSecurityContext"); endSequence (pCred, pCtx, env, status); return 0; } @@ -240,6 +242,8 @@ ss = CompleteAuthToken( pCtx, &OutBuffDesc ); if (ss < 0) { + SetLastError(ss); + JNU_ThrowIOExceptionWithLastError(env, "CompleteAuthToken"); endSequence (pCred, pCtx, env, status); return 0; } diff -Nru openjdk-25-25.0.4.1+1/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java openjdk-25-25.0.5+8/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java --- openjdk-25-25.0.4.1+1/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -33,7 +33,6 @@ import java.io.InputStreamReader; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.io.OptionalDataException; import java.io.Reader; import java.io.Serial; import java.io.StringReader; @@ -1320,19 +1319,7 @@ } } - try { - representationClass = (Class)is.readObject(); - } catch (OptionalDataException ode) { - if (!ode.eof || ode.length != 0) { - throw ode; - } - // Ensure backward compatibility. - // Old versions didn't write the representation class to the stream. - if (rcn != null) { - representationClass = - DataFlavor.tryToLoadClass(rcn, getClass().getClassLoader()); - } - } + representationClass = (Class)is.readObject(); } /** diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/macosx/classes/sun/lwawt/macosx/CImage.java openjdk-25-25.0.5+8/src/java.desktop/macosx/classes/sun/lwawt/macosx/CImage.java --- openjdk-25-25.0.4.1+1/src/java.desktop/macosx/classes/sun/lwawt/macosx/CImage.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/macosx/classes/sun/lwawt/macosx/CImage.java 2026-10-19 12:10:20.000000000 +0000 @@ -83,7 +83,6 @@ } public static class Creator { - CTrayIcon.IconObserver observer; Creator() { } @@ -131,7 +130,7 @@ return createImageUsingNativeSize(nativeCreateNSImageFromImageName(name)); } - private static int[] imageToArray(Image image, boolean prepareImage, CTrayIcon.IconObserver observer) { + private static BufferedImage getAsBufferedImage(Image image, boolean prepareImage, CTrayIcon.IconObserver observer) { if (image == null) return null; if (prepareImage && !(image instanceof BufferedImage)) { @@ -163,17 +162,18 @@ g2.drawImage(image, 0, 0, observer); g2.dispose(); - return ((DataBufferInt)bimg.getRaster().getDataBuffer()).getData(); + return bimg; } public byte[] getPlatformImageBytes(final Image image) { - int[] buffer = imageToArray(image, false, null); + BufferedImage bimg = getAsBufferedImage(image, false, null); - if (buffer == null) { + if (bimg == null) { return null; } + int[] buffer = ((DataBufferInt)bimg.getRaster().getDataBuffer()).getData(); - return nativeGetPlatformImageBytes(buffer, image.getWidth(null), image.getHeight(null)); + return nativeGetPlatformImageBytes(buffer, bimg.getWidth(), bimg.getHeight()); } /** @@ -205,11 +205,13 @@ return createFromImages(resolutionVariants, prepareImage); } - int[] buffer = imageToArray(image, prepareImage, observer); - if (buffer == null) { + BufferedImage bimg = getAsBufferedImage(image, prepareImage, observer); + + if (bimg == null) { return null; } - return new CImage(nativeCreateNSImageFromArray(buffer, image.getWidth(null), image.getHeight(null))); + int[] buffer = ((DataBufferInt)bimg.getRaster().getDataBuffer()).getData(); + return new CImage(nativeCreateNSImageFromArray(buffer, bimg.getWidth(), bimg.getHeight())); } public CImage createFromImages(final List images) { @@ -230,13 +232,14 @@ num = 0; for (final Image img : images) { - buffers[num] = imageToArray(img, prepareImage, null); - if (buffers[num] == null) { + BufferedImage bimg = getAsBufferedImage(img, prepareImage, null); + if (bimg == null) { // Unable to process the image continue; } - w[num] = img.getWidth(null); - h[num] = img.getHeight(null); + buffers[num] = ((DataBufferInt)bimg.getRaster().getDataBuffer()).getData(); + w[num] = bimg.getWidth(); + h[num] = bimg.getHeight(); num++; } diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/macosx/native/libawt_lwawt/awt/CImage.m openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/awt/CImage.m --- openjdk-25-25.0.4.1+1/src/java.desktop/macosx/native/libawt_lwawt/awt/CImage.m 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/awt/CImage.m 2026-10-19 12:10:20.000000000 +0000 @@ -75,6 +75,11 @@ static NSBitmapImageRep* CImage_CreateImageRep(JNIEnv *env, jintArray buffer, jint width, jint height) { + jlong bufferLength = (*env)->GetArrayLength(env, buffer); + if (((jlong)width * height) > bufferLength) { + return 0L; + } + NSBitmapImageRep* imageRep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:width pixelsHigh:height diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m --- openjdk-25-25.0.4.1+1/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m 2026-10-19 12:10:20.000000000 +0000 @@ -68,6 +68,11 @@ sjm_getCurrentAccessiblePopupMenu, fAccessible, fComponent); + CHECK_EXCEPTION(); + if (axComponent == nil) { + return nil; + } + CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:axComponent withEnv:env withView:self->fView isCurrent:YES]; diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m --- openjdk-25-25.0.4.1+1/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -48,6 +48,19 @@ extern void MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo); +/** + * Triggers the display link for the current destination surface. + */ +static void MTLSD_Flush() { + if (dstOps != NULL) { + MTLSDOps *dstMTLOps = (MTLSDOps *)dstOps->privOps; + MTLLayer *layer = (MTLLayer*)dstMTLOps->layer; + if (layer != NULL) { + [layer startDisplayLink]; + } + } +} + void MTLRenderQueue_CheckPreviousOp(jint op) { if (mtlPreviousOp == op) { @@ -161,35 +174,21 @@ case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY: { CHECK_PREVIOUS_OP(MTL_OP_OTHER); - jint nPoints = NEXT_INT(b); - jboolean isClosed = NEXT_BOOLEAN(b); - jint transX = NEXT_INT(b); - jint transY = NEXT_INT(b); - jint *xPoints = (jint *)b; - jint *yPoints = ((jint *)b) + nPoints; if ([mtlc useXORComposite]) { commitEncodedCommands(); J2dTraceLn(J2D_TRACE_VERBOSE, "DRAW_POLY in XOR mode - Force commit earlier draw calls before DRAW_POLY."); - // draw separate (N-1) lines using N points - for(int point = 0; point < nPoints-1; point++) { - jint x1 = xPoints[point] + transX; - jint y1 = yPoints[point] + transY; - jint x2 = xPoints[point + 1] + transX; - jint y2 = yPoints[point + 1] + transY; - MTLRenderer_DrawLine(mtlc, dstOps, x1, y1, x2, y2); - } - - if (isClosed) { - MTLRenderer_DrawLine(mtlc, dstOps, xPoints[0] + transX, yPoints[0] + transY, - xPoints[nPoints-1] + transX, yPoints[nPoints-1] + transY); - } - } else { - MTLRenderer_DrawPoly(mtlc, dstOps, nPoints, isClosed, transX, transY, xPoints, yPoints); } + jint nPoints = NEXT_INT(b); + jboolean isClosed = NEXT_BOOLEAN(b); + jint transX = NEXT_INT(b); + jint transY = NEXT_INT(b); + jint *xPoints = (jint *)b; + jint *yPoints = ((jint *)b) + nPoints; + MTLRenderer_DrawPoly(mtlc, dstOps, nPoints, isClosed, transX, transY, xPoints, yPoints); SKIP_BYTES(b, nPoints * BYTES_PER_POLY_POINT); break; } @@ -589,6 +588,7 @@ [cbwrapper release]; }]; [commandbuf commit]; + MTLSD_Flush(); } mtlc = [MTLContext setSurfacesEnv:env src:pSrc dst:pDst]; dstOps = (BMTLSDOps *)jlong_to_ptr(pDst); @@ -616,6 +616,7 @@ [cbwrapper release]; }]; [commandbuf commit]; + MTLSD_Flush(); } mtlc = newMtlc; dstOps = NULL; @@ -885,14 +886,7 @@ [cbwrapper release]; }]; [commandbuf commit]; - BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination(); - if (dstOps != NULL) { - MTLSDOps *dstMTLOps = (MTLSDOps *)dstOps->privOps; - MTLLayer *layer = (MTLLayer*)dstMTLOps->layer; - if (layer != NULL) { - [layer startDisplayLink]; - } - } + MTLSD_Flush(); } RESET_PREVIOUS_OP(); } diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/shaders.metal openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/shaders.metal --- openjdk-25-25.0.4.1+1/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/shaders.metal 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/shaders.metal 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -84,13 +84,11 @@ struct ColShaderInOut_XOR { float4 position [[position]]; float ptSize [[point_size]]; - float2 orig_pos; half4 color; }; struct TxtShaderInOut_XOR { float4 position [[position]]; - float2 orig_pos; float2 texCoords; float2 tpCoords; }; @@ -677,7 +675,6 @@ float4 pos4 = float4(in.position, 0.0, 1.0); out.position = transform.transformMatrix*pos4; out.ptSize = 1.0; - out.orig_pos = in.position; out.color = half4(uniforms.color.r, uniforms.color.g, uniforms.color.b, uniforms.color.a); return out; } @@ -685,7 +682,7 @@ fragment half4 frag_col_xorMode(ColShaderInOut_XOR in [[stage_in]], texture2d renderTexture [[texture(0)]]) { - uint2 texCoord = {(unsigned int)(in.orig_pos.x), (unsigned int)(in.orig_pos.y)}; + uint2 texCoord = {(unsigned int)(in.position.x), (unsigned int)(in.position.y)}; float4 pixelColor = renderTexture.read(texCoord); half4 color = in.color; @@ -707,7 +704,6 @@ TxtShaderInOut_XOR out; float4 pos4 = float4(in.position, 0.0, 1.0); out.position = transform.transformMatrix*pos4; - out.orig_pos = in.position; out.texCoords = in.texCoords; return out; } @@ -719,7 +715,7 @@ constant TxtFrameUniforms& uniforms [[buffer(1)]], sampler textureSampler [[sampler(0)]]) { - uint2 texCoord = {(unsigned int)(vert.orig_pos.x), (unsigned int)(vert.orig_pos.y)}; + uint2 texCoord = {(unsigned int)(vert.position.x), (unsigned int)(vert.position.y)}; float4 bgColor = backgroundTexture.read(texCoord); float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords); diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java openjdk-25-25.0.5+8/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java --- openjdk-25-25.0.4.1+1/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.awt.image.MultiPixelPackedSampleModel; import java.awt.image.PixelInterleavedSampleModel; import java.awt.image.SampleModel; +import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.nio.ByteOrder; @@ -650,7 +651,8 @@ // Read blocks of 1-255 bytes, stop at a 0-length block private byte[] concatenateBlocks() throws IOException { - byte[] data = new byte[0]; + ByteArrayOutputStream buffer = new ByteArrayOutputStream(255); + byte[] data = new byte[255]; while (true) { int length = stream.readUnsignedByte(); if (length == 0) { @@ -660,15 +662,10 @@ stream.skipBytes(length); continue; } - byte[] subBlockData = - ReaderUtil.staggeredReadByteStream(stream, length); - byte[] newData = new byte[data.length + length]; - System.arraycopy(data, 0, newData, 0, data.length); - System.arraycopy(subBlockData, 0, newData, - data.length, length); - data = newData; + stream.readFully(data, 0, length); + buffer.write(data, 0, length); } - return data; + return buffer.toByteArray(); } // Stream must be positioned at start of metadata for 'currIndex' diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java openjdk-25-25.0.5+8/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java --- openjdk-25-25.0.4.1+1/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java 2026-10-19 12:10:20.000000000 +0000 @@ -1250,9 +1250,15 @@ int[] sBands = param.getSourceBands(); if (sBands != null) { - srcBands = sBands; + srcBands = sBands.clone(); numRasterBands = srcBands.length; } + for (int b = 0; b < srcBands.length; b++) { + if (srcBands[b] < 0 || srcBands[b] >= numComponents) { + throw new IllegalArgumentException( + "ImageReadParam out of range source band : " + srcBands[b]); + } + } if (!wantRaster) { // ignore dest bands for Raster destinationBands = param.getDestinationBands(); } diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java openjdk-25-25.0.5+8/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java --- openjdk-25-25.0.4.1+1/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package com.sun.media.sound; import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.EOFException; import java.io.File; @@ -229,6 +230,10 @@ private static final boolean DEBUG = false; + private static final int MAX_ALLOWED_ALLOC = 1024*1024; // Maximum allowed memory preallocation + + private static final int TRACK_BUFFER_SIZE = 10*1024; // Read large tracks in 10 KB chunks + int tracks; // number of tracks DataInputStream stream; // the stream to read from @@ -286,19 +291,45 @@ } } // now read track in a byte array - try { - trackData = new byte[trackLength]; - } catch (final OutOfMemoryError oom) { - throw new IOException("Track length too big", oom); - } - try { - // $$fb 2003-08-20: fix for 4910986: MIDI file parser breaks up on http connection - stream.readFully(trackData); - } catch (EOFException eof) { - if (!STRICT_PARSER) { - return false; + if (trackLength <= MAX_ALLOWED_ALLOC) { + try { + trackData = new byte[trackLength]; + } catch (final OutOfMemoryError oom) { + throw new IOException("Track length too big", oom); + } + try { + // $$fb 2003-08-20: fix for 4910986: MIDI file parser breaks up on http connection + stream.readFully(trackData); + } catch (EOFException eof) { + if (!STRICT_PARSER) { + return false; + } + throw new EOFException("invalid MIDI file"); + } + } else { + try { + byte[] buffer = new byte[TRACK_BUFFER_SIZE]; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + long bytesRead = 0; + + while (bytesRead < trackLength) { + int bytesToRead = (int) Math.min(buffer.length, trackLength - bytesRead); + try { + stream.readFully(buffer, 0, bytesToRead); + } catch (EOFException eof) { + if (!STRICT_PARSER) { + return false; + } + throw new EOFException("invalid MIDI file"); + } + + out.write(buffer, 0, bytesToRead); + bytesRead += bytesToRead; + } + trackData = out.toByteArray(); + } catch (final OutOfMemoryError oom) { + throw new IOException("Track length too big", oom); } - throw new EOFException("invalid MIDI file"); } pos = 0; return true; diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java openjdk-25-25.0.5+8/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java --- openjdk-25-25.0.4.1+1/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -301,9 +301,12 @@ ClassLoader cl = Thread.currentThread().getContextClassLoader(); EventListener l = (EventListener)s.readObject(); String name = (String) listenerTypeOrNull; - @SuppressWarnings("unchecked") - Class tmp = (Class)Class.forName(name, true, cl); - add(tmp, l); + Class c = Class.forName(name, false, cl); + if (EventListener.class.isAssignableFrom(c)) { + @SuppressWarnings("unchecked") + Class tmp = (Class) c; + add(tmp, l); + } } } diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c openjdk-25-25.0.5+8/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c --- openjdk-25-25.0.4.1+1/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, 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 @@ -433,6 +433,7 @@ jlong pDst = NEXT_LONG(b); if (oglc != NULL) { RESET_PREVIOUS_OP(); + OGLSD_Flush(env); } oglc = OGLContext_SetSurfaces(env, pSrc, pDst); dstOps = (OGLSDOps *)jlong_to_ptr(pDst); @@ -443,6 +444,7 @@ jlong pConfigInfo = NEXT_LONG(b); if (oglc != NULL) { RESET_PREVIOUS_OP(); + OGLSD_Flush(env); } oglc = OGLSD_SetScratchSurface(env, pConfigInfo); dstOps = NULL; diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/share/native/libfontmanager/freetypeScaler.c openjdk-25-25.0.5+8/src/java.desktop/share/native/libfontmanager/freetypeScaler.c --- openjdk-25-25.0.4.1+1/src/java.desktop/share/native/libfontmanager/freetypeScaler.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/share/native/libfontmanager/freetypeScaler.c 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -864,10 +864,12 @@ srcRow += srcRowBytes; dstRow += dstRowBytes; - for (i = 0; i < width; i++) { + for (i = 0; i < width; i += 2) { srcValue = *src8++; - *dstByte++ = Grey4ToAlpha255(srcValue & 0x0f); *dstByte++ = Grey4ToAlpha255(srcValue >> 4); + if (i < width-1) { + *dstByte++ = Grey4ToAlpha255(srcValue & 0x0f); + } } } } diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/Devices.cpp openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/Devices.cpp --- openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/Devices.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/Devices.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,47 +113,78 @@ return TRUE; } -// Callback for CountMonitors below -static BOOL WINAPI clb_fCountMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorCounter) + +// Callback for CollectMonitors below +static BOOL WINAPI clb_fCollectMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorData) { - if (IsValidMonitor(hMon)) { - (*((int *)lpMonitorCounter))++; + MonitorData* pMonitorData = (MonitorData *)lpMonitorData; + + if (!IsValidMonitor(hMon)) { + return TRUE; + } + + if (pMonitorData->monitorCounter == pMonitorData->monitorLimit) { + TRY; + + int newMonitorLimit = pMonitorData->monitorLimit * 2; + HMONITOR* newMonitors = + (HMONITOR*)SAFE_SIZE_ARRAY_REALLOC( + safe_Realloc, pMonitorData->hmpMonitors, + newMonitorLimit, sizeof(HMONITOR) + ); + pMonitorData->hmpMonitors = newMonitors; + pMonitorData->monitorLimit = newMonitorLimit; + + CATCH_BAD_ALLOC_RET(FALSE); } + pMonitorData->hmpMonitors[pMonitorData->monitorCounter] = hMon; + pMonitorData->monitorCounter++; + return TRUE; } -int WINAPI CountMonitors(void) +static HMONITOR* CollectMonitors(int* numScreens) { - int monitorCounter = 0; - ::EnumDisplayMonitors(NULL, NULL, clb_fCountMonitors, (LPARAM)&monitorCounter); - return monitorCounter; -} + const int initialMonitorLimit = 4; -// Callback for CollectMonitors below -static BOOL WINAPI clb_fCollectMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorData) -{ - MonitorData* pMonitorData = (MonitorData *)lpMonitorData; - if ((pMonitorData->monitorCounter < pMonitorData->monitorLimit) && (IsValidMonitor(hMon))) { - pMonitorData->hmpMonitors[pMonitorData->monitorCounter] = hMon; - pMonitorData->monitorCounter++; + *numScreens = 0; + + MonitorData data; + data.monitorCounter = 0; + data.monitorLimit = initialMonitorLimit; + + TRY; + + data.hmpMonitors = (HMONITOR*)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, + initialMonitorLimit, sizeof(HMONITOR)); + CATCH_BAD_ALLOC_RET(NULL); + + if (!::EnumDisplayMonitors(NULL, NULL, clb_fCollectMonitors, (LPARAM)&data)) { + free(data.hmpMonitors); + return NULL; } - return TRUE; + *numScreens = data.monitorCounter; + return data.hmpMonitors; } -static int WINAPI CollectMonitors(HMONITOR* hmpMonitors, int nNum) +int WINAPI CountMonitors() { - if (NULL != hmpMonitors) { - MonitorData monitorData; - monitorData.monitorCounter = 0; - monitorData.monitorLimit = nNum; - monitorData.hmpMonitors = hmpMonitors; - ::EnumDisplayMonitors(NULL, NULL, clb_fCollectMonitors, (LPARAM)&monitorData); - return monitorData.monitorCounter; - } else { - return 0; + int numScreens = 0; + HMONITOR* monHds = CollectMonitors(&numScreens); + free(monHds); + return numScreens; +} + +static BOOL AreSameMonitorInfo(LPMONITORINFOEX oldInfo, LPMONITORINFOEX newInfo) +{ + if (oldInfo == NULL || newInfo == NULL) { + return FALSE; } + + return oldInfo->dwFlags == newInfo->dwFlags + && ::lstrcmp(oldInfo->szDevice, newInfo->szDevice) == 0; } BOOL WINAPI MonitorBounds(HMONITOR hmMonitor, RECT* rpBounds) @@ -202,17 +233,26 @@ { J2dTraceLn(J2D_TRACE_INFO, "Devices::UpdateInstance"); - int numScreens = CountMonitors(); - HMONITOR *monHds = (HMONITOR *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, - numScreens, sizeof(HMONITOR)); - if (numScreens != CollectMonitors(monHds, numScreens)) { + int numScreens = 0; + HMONITOR *monHds = CollectMonitors(&numScreens); + if (monHds == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, - "Devices::UpdateInstance: Failed to get all "\ + "Devices::UpdateInstance: Failed to get "\ "monitor handles."); free(monHds); return FALSE; } + if (numScreens == 0) { + CriticalSection::Lock l(arrayLock); + if (theInstance != NULL) { + J2dRlsTraceLn(J2D_TRACE_ERROR, + "Devices::UpdateInstance: No valid monitor handles."); + free(monHds); + return FALSE; + } + } + Devices *newDevices = new Devices(numScreens); // This way we know that the array will not be disposed of // at least until we replaced it with a new one. @@ -238,18 +278,26 @@ theInstance = newDevices; if (oldDevices) { - // Invalidate the devices with indexes out of the new set of - // devices. This doesn't cover all cases when the device - // might should be invalidated (like if it's not the last device - // that was removed), but it will have to do for now. int oldNumScreens = oldDevices->GetNumDevices(); - int newNumScreens = theInstance->GetNumDevices(); - J2dTraceLn(J2D_TRACE_VERBOSE, " Invalidating removed devices"); - for (int i = newNumScreens; i < oldNumScreens; i++) { - // removed device, needs to be invalidated + J2dTraceLn(J2D_TRACE_VERBOSE, " Invalidating changed devices"); + for (int i = 0; i < oldNumScreens; i++) { + AwtWin32GraphicsDevice *oldDevice = + oldDevices->GetDevice(i, FALSE); + AwtWin32GraphicsDevice *newDevice = + theInstance->GetDevice(i, FALSE); + BOOL changed = (newDevice == NULL) + || !AreSameMonitorInfo( + (LPMONITORINFOEX) oldDevice->GetMonitorInfo(), + (LPMONITORINFOEX) newDevice->GetMonitorInfo()); + + if (!changed) { + newDevice->TransferJavaDevice(env, oldDevice); + continue; + } + J2dTraceLn1(J2D_TRACE_WARNING, - "Devices::UpdateInstance: device removed: %d", i); - oldDevices->GetDevice(i)->Invalidate(env); + "Devices::UpdateInstance: device changed: %d", i); + oldDevice->Invalidate(env); } // Now that we have a new array in place, remove this (possibly the // last) reference to the old instance. @@ -342,6 +390,12 @@ J2dTraceLn2(J2D_TRACE_INFO, "Devices::GetDevice index=%d adjust?=%d", index, adjust); + if (numDevices <= 0) { + J2dTraceLn(J2D_TRACE_WARNING, + "Devices::GetDevice: "\ + "no devices, returning NULL."); + return NULL; + } if (index < 0 || index >= numDevices) { if (!adjust) { J2dTraceLn1(J2D_TRACE_WARNING, diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/Devices.h openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/Devices.h --- openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/Devices.h 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/Devices.h 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,8 +47,11 @@ class InstanceAccess { public: INLINE InstanceAccess() { devices = Devices::GetInstance(); } - INLINE ~InstanceAccess() { devices->Release(); } + INLINE ~InstanceAccess() { if (devices != NULL) devices->Release(); } Devices* operator->() { return devices; } + INLINE AwtWin32GraphicsDevice* Device(int index, BOOL adjust = TRUE) { + return devices == NULL ? NULL : devices->GetDevice(index, adjust); + } private: Devices* devices; // prevent bad things like copying or getting address of diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp --- openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -65,7 +65,7 @@ #include #include -extern void initScreens(JNIEnv *env); +extern BOOL initScreens(JNIEnv *env); extern "C" void awt_dnd_initialize(); extern "C" void awt_dnd_uninitialize(); extern "C" void awt_clipboard_uninitialize(JNIEnv *env); @@ -157,6 +157,78 @@ } #define IDT_AWT_MOUSECHECK 0x101 +#define IDT_AWT_DISPLAYCHANGE 0x102 + +#define AWT_DISPLAYCHANGE_RETRY_DELAY 250 +#define AWT_DISPLAYCHANGE_RETRY_LIMIT 20 + +class DisplayChangeHandler { +public: + static BOOL Handle(JNIEnv *env, HWND hWnd) { + // Reinitialize screens + if (!initScreens(env)) { + OnDisplayChangeFailed(hWnd); + return FALSE; + } + + OnDisplayChangeSucceeded(hWnd); + + // Notify Java side - call WToolkit.displayChanged() + jclass clazz = env->FindClass("sun/awt/windows/WToolkit"); + DASSERT(clazz != NULL); + if (!clazz) throw std::bad_alloc(); + env->CallStaticVoidMethod(clazz, AwtToolkit::displayChangeMID); + + return !env->ExceptionCheck(); + } + + static void Reset(HWND hWnd) { + ::KillTimer(hWnd, IDT_AWT_DISPLAYCHANGE); + retryCount = 0; + } + + static void ScheduleFromSessionChange(HWND hWnd) { + if (!recoveryPending) { + return; + } + Reset(hWnd); + Schedule(hWnd); + } + +private: + static void OnDisplayChangeFailed(HWND hWnd) { + recoveryPending = TRUE; + Schedule(hWnd); + } + + static void OnDisplayChangeSucceeded(HWND hWnd) { + recoveryPending = FALSE; + Reset(hWnd); + } + + static void Schedule(HWND hWnd) { + if (retryCount >= AWT_DISPLAYCHANGE_RETRY_LIMIT) { + Reset(hWnd); + J2dRlsTraceLn(J2D_TRACE_ERROR, + "AwtToolkit: Display change retry limit exceeded."); + return; + } + + retryCount++; + if (::SetTimer(hWnd, IDT_AWT_DISPLAYCHANGE, + AWT_DISPLAYCHANGE_RETRY_DELAY, NULL) == 0) { + Reset(hWnd); + J2dRlsTraceLn(J2D_TRACE_ERROR, + "AwtToolkit: Failed to schedule display change retry."); + } + } + + static int retryCount; + static BOOL recoveryPending; +}; + +int DisplayChangeHandler::retryCount = 0; +BOOL DisplayChangeHandler::recoveryPending = FALSE; static LPCTSTR szAwtToolkitClassName = TEXT("SunAwtToolkit"); @@ -1004,6 +1076,14 @@ } case WM_TIMER: { + if (wParam == IDT_AWT_DISPLAYCHANGE) { + if (DisplayChangeHandler::Handle(env, hWnd)) { + GetInstance().m_displayChanged = TRUE; + ::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL); + } + return 0; + } + // 6479820. Should check if a window is in manual resizing process: skip // sending any MouseExit/Enter events while inside resize-loop. // Note that window being in manual moving process could still @@ -1245,18 +1325,11 @@ return tk.m_inputMethodData; } case WM_DISPLAYCHANGE: { - // Reinitialize screens - initScreens(env); - - // Notify Java side - call WToolkit.displayChanged() - jclass clazz = env->FindClass("sun/awt/windows/WToolkit"); - DASSERT(clazz != NULL); - if (!clazz) throw std::bad_alloc(); - env->CallStaticVoidMethod(clazz, AwtToolkit::displayChangeMID); - - GetInstance().m_displayChanged = TRUE; - - ::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL); + DisplayChangeHandler::Reset(hWnd); + if (DisplayChangeHandler::Handle(env, hWnd)) { + GetInstance().m_displayChanged = TRUE; + ::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL); + } break; } /* Session management */ @@ -1341,6 +1414,9 @@ activate ? JNI_TRUE : JNI_FALSE, reason); + if (activate) { + DisplayChangeHandler::ScheduleFromSessionChange(hWnd); + } } break; } diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp --- openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -612,13 +612,52 @@ } /** - * Links this native object with its java Win32GraphicsDevice. - * Need this link because the colorModel of the java device - * may be updated from native code. + * Links this native object with its java Win32GraphicsDevice peer. + * + * The link is needed for upcalls to the java peer, such as invalidate() + * and dynamic color model updates. + * + * Passing NULL intentionally clears the link. + * Clearing it here prevents stale peer links and releases + * the old JNI weak global ref. + * + * During display changes, the native device array is recreated, + * changed or removed devices invalidate their java peers. + * Unchanged monitors transfer the existing weak ref to + * the new native device by TransferJavaDevice(). */ void AwtWin32GraphicsDevice::SetJavaDevice(JNIEnv *env, jobject objPtr) { - javaDevice = env->NewWeakGlobalRef(objPtr); + jobject newJavaDevice = NULL; + if (objPtr != NULL) { + newJavaDevice = env->NewWeakGlobalRef(objPtr); + if (newJavaDevice == NULL) { + return; + } + } + + if (javaDevice != NULL) { + env->DeleteWeakGlobalRef(javaDevice); + } + javaDevice = newJavaDevice; +} + +/** + * Transfers the java Win32GraphicsDevice's link from a native device that is + * being replaced by a new native device for the same monitor. + */ +void AwtWin32GraphicsDevice::TransferJavaDevice(JNIEnv *env, + AwtWin32GraphicsDevice *device) +{ + if (device == NULL || device == this || device->javaDevice == NULL) { + return; + } + + if (javaDevice != NULL) { + env->DeleteWeakGlobalRef(javaDevice); + } + javaDevice = device->javaDevice; + device->javaDevice = NULL; } /** @@ -1398,7 +1437,10 @@ (JNIEnv *env, jobject thisPtr, jint screen) { Devices::InstanceAccess devices; - devices->GetDevice(screen)->SetJavaDevice(env, thisPtr); + AwtWin32GraphicsDevice *device = devices.Device(screen, FALSE); + if (device != NULL) { + device->SetJavaDevice(env, thisPtr); + } } /* @@ -1411,9 +1453,8 @@ (JNIEnv *env, jobject thisPtr, jint screen, jfloat scaleX, jfloat scaleY) { Devices::InstanceAccess devices; - AwtWin32GraphicsDevice *device = devices->GetDevice(screen); - - if (device != NULL ) { + AwtWin32GraphicsDevice *device = devices.Device(screen, FALSE); + if (device != NULL) { device->DisableScaleAutoRefresh(); device->SetScale(scaleX, scaleY); } @@ -1429,8 +1470,8 @@ (JNIEnv *env, jobject thisPtr, jint screen) { Devices::InstanceAccess devices; - AwtWin32GraphicsDevice *device = devices->GetDevice(screen); - return (device == NULL) ? 1 : device->GetScaleX(); + AwtWin32GraphicsDevice *device = devices.Device(screen, FALSE); + return device == NULL ? 1 : device->GetScaleX(); } /* @@ -1443,8 +1484,8 @@ (JNIEnv *env, jobject thisPtr, jint screen) { Devices::InstanceAccess devices; - AwtWin32GraphicsDevice *device = devices->GetDevice(screen); - return (device == NULL) ? 1 : device->GetScaleY(); + AwtWin32GraphicsDevice *device = devices.Device(screen, FALSE); + return device == NULL ? 1 : device->GetScaleY(); } /* @@ -1457,8 +1498,7 @@ (JNIEnv *env, jobject thisPtr, jint screen) { Devices::InstanceAccess devices; - AwtWin32GraphicsDevice *device = devices->GetDevice(screen); - + AwtWin32GraphicsDevice *device = devices.Device(screen, FALSE); if (device != NULL) { device->InitDesktopScales(); } diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h --- openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,8 @@ unsigned int *GetSystemPaletteEntries(); unsigned char *GetSystemInverseLUT(); void SetJavaDevice(JNIEnv *env, jobject objPtr); + void TransferJavaDevice(JNIEnv *env, + AwtWin32GraphicsDevice *device); HPALETTE SelectPalette(HDC hDC); void RealizePalette(HDC hDC); HPALETTE GetPalette(); diff -Nru openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp --- openjdk-25-25.0.4.1+1/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,10 +35,12 @@ BOOL DWMIsCompositionEnabled(); -void initScreens(JNIEnv *env) { +BOOL initScreens(JNIEnv *env) { if (!Devices::UpdateInstance(env)) { - JNU_ThrowInternalError(env, "Could not update the devices array."); + J2dRlsTraceLn(J2D_TRACE_ERROR, "initScreens: Could not update the devices array."); + return FALSE; } + return TRUE; } /** @@ -144,7 +146,9 @@ DWMIsCompositionEnabled(); - initScreens(env); + if (!initScreens(env)) { + JNU_ThrowInternalError(env, "Could not update the devices array."); + } } /* diff -Nru openjdk-25-25.0.4.1+1/src/java.instrument/share/native/libinstrument/JPLISAgent.c openjdk-25-25.0.5+8/src/java.instrument/share/native/libinstrument/JPLISAgent.c --- openjdk-25-25.0.4.1+1/src/java.instrument/share/native/libinstrument/JPLISAgent.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.instrument/share/native/libinstrument/JPLISAgent.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, 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 @@ -780,7 +780,7 @@ jobject moduleObject = NULL; /* find last slash in the class name */ - char* last_slash = (cname == NULL) ? NULL : strrchr(cname, '/'); + const char* last_slash = (cname == NULL) ? NULL : strrchr(cname, '/'); int len = (last_slash == NULL) ? 0 : (int)(last_slash - cname); char* pkg_name_buf = (char*)malloc(len + 1); diff -Nru openjdk-25-25.0.4.1+1/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c openjdk-25-25.0.5+8/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c --- openjdk-25-25.0.4.1+1/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, 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 @@ -36,7 +36,7 @@ #define slash '/' char* basePath(const char* path) { - char* last = strrchr(path, slash); + const char* last = strrchr(path, slash); if (last == NULL) { return (char*)path; } else { diff -Nru openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java --- openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ try { obj = NamingManagerHelper.getDirObjectInstance(obj, cn, homeCtx, - homeCtx.envprops, attrs, ObjectFactoriesFilter::checkLdapFilter); + homeCtx.envprops, attrs, ObjectFactoriesFilter.ldapFactoryFilter()); } catch (NamingException e) { throw e; diff -Nru openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java --- openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -388,6 +388,16 @@ initEnv(); } + /** + * Whether this LDAP provider implementation trusts serial data. + * See {@linkplain java.naming/ java.naming module info} for more info. + * + * @return true if this LDAP provider implementation trusts serial data + */ + public static boolean trustSerialData() { + return Obj.trustSerialData(); + } + public LdapContext newInstance(Control[] reqCtls) throws NamingException { LdapContext clone = new LdapCtx(this, currentDN); @@ -1113,7 +1123,7 @@ try { return NamingManagerHelper.getDirObjectInstance(obj, name, this, - envprops, attrs, ObjectFactoriesFilter::checkLdapFilter); + envprops, attrs, ObjectFactoriesFilter.ldapFactoryFilter()); } catch (NamingException e) { throw cont.fillInException(e); diff -Nru openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java --- openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, 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 @@ -118,7 +118,7 @@ Object obj; try { obj = NamingManagerHelper.getObjectInstance(ref, null, null, - env, ObjectFactoriesFilter::checkLdapFilter); + env, ObjectFactoriesFilter.ldapFactoryFilter()); } catch (NamingException e) { if (handleReferrals == LdapClient.LDAP_REF_THROW) { diff -Nru openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java --- openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,7 +124,7 @@ // rcn is either relative to homeCtx or a fully qualified DN obj = NamingManagerHelper.getDirObjectInstance( obj, rcn, (relative ? homeCtx : null), - homeCtx.envprops, attrs, ObjectFactoriesFilter::checkLdapFilter); + homeCtx.envprops, attrs, ObjectFactoriesFilter.ldapFactoryFilter()); } catch (NamingException e) { throw e; } catch (Exception e) { diff -Nru openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java --- openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,6 +120,14 @@ static final int MAR_OBJECT = 4; // auxiliary marshalled object class /** + * Whether deserialization of serial data is allowed + * @return true if deserialization of serial data is allowed + */ + static boolean trustSerialData() { + return trustSerialData; + } + + /** * Encode an object in LDAP attributes. * Supports binding Referenceable or Reference, Serializable, * and DirContext. diff -Nru openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/naming/internal/NamingManagerHelper.java openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/naming/internal/NamingManagerHelper.java --- openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/naming/internal/NamingManagerHelper.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/naming/internal/NamingManagerHelper.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, 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 @@ -88,7 +88,7 @@ // if reference has no factory, check for addresses // containing URLs - answer = processURLAddrs(ref, name, nameCtx, environment); + answer = processURLAddrs(ref, name, nameCtx, environment, factoryFilter); if (answer != null) { return answer; } @@ -156,7 +156,7 @@ // containing URLs // ignore name & attrs params; not used in URL factory // RMI references from ' - answer = processURLAddrs(ref, name, nameCtx, environment); + answer = processURLAddrs(ref, name, nameCtx, environment, factoryFilter); if (answer != null) { return answer; } @@ -239,7 +239,8 @@ * invoking a factory. */ static Object processURLAddrs(Reference ref, Name name, Context nameCtx, - Hashtable environment) + Hashtable environment, + Predicate> factoryFilter) throws NamingException { for (int i = 0; i < ref.size(); i++) { @@ -248,7 +249,7 @@ addr.getType().equalsIgnoreCase("URL")) { String url = (String)addr.getContent(); - Object answer = processURL(url, name, nameCtx, environment); + Object answer = processURL(url, name, nameCtx, environment, factoryFilter); if (answer != null) { return answer; } @@ -258,7 +259,8 @@ } private static Object processURL(Object refInfo, Name name, - Context nameCtx, Hashtable environment) + Context nameCtx, Hashtable environment, + Predicate> factoryFilter) throws NamingException { Object answer; @@ -269,7 +271,7 @@ String scheme = getURLScheme(url); if (scheme != null) { answer = getURLObject(scheme, refInfo, name, nameCtx, - environment); + environment, factoryFilter); if (answer != null) { return answer; } @@ -285,7 +287,7 @@ String scheme = getURLScheme(urls[i]); if (scheme != null) { answer = getURLObject(scheme, refInfo, name, nameCtx, - environment); + environment, factoryFilter); if (answer != null) return answer; } @@ -327,11 +329,16 @@ * @param nameCtx Context whose provider resource file will be searched * for package prefix values (or null if none) * @param environment Environment properties for creating the context + * @param factoryFilter an object factory filter. If the factoryFilter is + * an instance of {@link ObjectFactoriesFilter.ContextFactoryFilter} + * it will be used to check whether the selected URL Context Factory + * is allowed to process a URL Reference of the given URL scheme. * @see javax.naming.InitialContext */ private static Object getURLObject(String scheme, Object urlInfo, Name name, Context nameCtx, - Hashtable environment) + Hashtable environment, + Predicate> factoryFilter) throws NamingException { // e.g. "ftpURLContextFactory" @@ -342,6 +349,10 @@ if (factory == null) return null; + if (!ObjectFactoriesFilter.checkURLContextFactory(scheme, factory, factoryFilter)) { + return null; + } + // Found object factory try { return factory.getObjectInstance(urlInfo, name, nameCtx, environment); diff -Nru openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java --- openjdk-25-25.0.4.1+1/src/java.naming/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.naming/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java 2026-10-19 12:10:20.000000000 +0000 @@ -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,12 +25,19 @@ package com.sun.naming.internal; +import com.sun.jndi.ldap.LdapCtx; import sun.security.util.SecurityProperties; import javax.naming.Reference; +import javax.naming.spi.ObjectFactory; import java.io.ObjectInputFilter; import java.io.ObjectInputFilter.FilterInfo; import java.io.ObjectInputFilter.Status; +import java.util.List; +import java.util.Locale; +import java.util.function.BiPredicate; +import java.util.function.Predicate; +import java.util.stream.Stream; /** * This class implements the filter that validates object factories classes instantiated @@ -48,6 +55,133 @@ public final class ObjectFactoriesFilter { /** + * Defines an Object Factory Filter that can be used to {@linkplain + * #test(Class) validate usage of regular ObjectFactory classes} as + * well as {@linkplain #checkURLContextFactory(String, Class) validate + * usage of URL Context Factory classes}. + */ + public static final class ContextFactoryFilter implements Predicate> { + private final Predicate> factoryFilter; + private final BiPredicate> urlFactoryFilter; + + /** + * Construct a new {@code ContextFactoryFilter} from the given + * {@code factoryFilter} and {@code urlFactoryFilter} + * @param factoryFilter A predicate that tells whether a given + * object factory class can be used to reconstruct an object + * from a given Reference. + * This is typically {@link #checkLdapFilter(Class) + * ObjectFactoriesFilter::checkLdapFilter} + * @param urlFactoryFilter A bi-predicate that tells whether + * a URL reference of a given scheme should be processed + * using the selected URL Context Factory. + * This is typically {@link #checkURLContextFactory(String, Class) + * ObjectFactoriesFilter::checkURLContextFactory} + */ + private ContextFactoryFilter(Predicate> factoryFilter, + BiPredicate> urlFactoryFilter) { + this.factoryFilter = factoryFilter; + this.urlFactoryFilter = urlFactoryFilter; + } + + /** + * Checks whether a URL reference of the given scheme should be processed + * using the selected URL Context Factory. + * @param scheme the URL scheme + * @param urlContextFactoryClass the URL Context Factory class + * @return true if the URL Reference can be processed + */ + public boolean checkURLContextFactory(String scheme, Class urlContextFactoryClass) { + return urlFactoryFilter.test(scheme, urlContextFactoryClass); + } + + @Override + public boolean test(Class factoryClass) { + return factoryFilter.test(factoryClass); + } + + @Override + public ContextFactoryFilter negate() { + return new ContextFactoryFilter(factoryFilter.negate(), urlFactoryFilter.negate()); + } + + private static final ContextFactoryFilter LDAP_CONTEXT_FILTER = + new ContextFactoryFilter(ObjectFactoriesFilter::checkLdapFilter, + ObjectFactoriesFilter::ldapFollowsURL); + } + + private static final class URLSchemes { + private static final String LDAP_DISABLED_URL_SCHEMES_PROP = + "jdk.jndi.ldap.disabledURLSchemes"; + private static final String DEFAULT_LDAP_DISABLED_URL_SCHEMES = + LdapCtx.trustSerialData() ? "" : "rmi"; + private static final String LDAP_DISABLED_URL_SCHEMES = + System.getProperty(LDAP_DISABLED_URL_SCHEMES_PROP, + DEFAULT_LDAP_DISABLED_URL_SCHEMES); + static final List LDAP_DISABLED_URL_SCHEMES_LIST; + + static { + String[] protocols = LDAP_DISABLED_URL_SCHEMES.split(","); + LDAP_DISABLED_URL_SCHEMES_LIST = Stream.of(protocols) + .filter(Predicate.not(String::isEmpty)) + .map(s -> s.toLowerCase(Locale.ROOT)) + .toList(); + } + } + + /** + * Returns a {@code ContextFactoryFilter} used to check whether Reference + * objects retrieved from an LDAP context should be processed. + * The returned {@code ContextFactoryFilter} should be used to check + * whether a given object factory class can be used to reconstruct an object + * from a Reference, or whether a URL Reference of a given scheme can be + * processed using a given URL Context Factory class. + * + * @return a {@code ContextFactoryFilter} used to check whether Reference + * objects retrieved from an LDAP context should be processed. + */ + public static ContextFactoryFilter ldapFactoryFilter() { + return ContextFactoryFilter.LDAP_CONTEXT_FILTER; + } + + /** + * Checks whether URL References of the given scheme should be + * processed with the given URL Context Factory class, when the + * URL Reference was retrieved from LDAP. + * @param scheme the URL scheme + * @param urlContextFactory the URL Context Factory class + * @return true if the URL Reference should be processed by the + * given urlContextFactory class. + */ + public static boolean ldapFollowsURL(String scheme, Class urlContextFactory) { + // do not follow URLs if they are disabled; + for (String p : URLSchemes.LDAP_DISABLED_URL_SCHEMES_LIST) { + if (p.equalsIgnoreCase(scheme)) return false; + } + return true; + } + + /** + * This method is called from NamingManagerHelper to verify whether + * a URL Reference of the given URL scheme can be processed by the + * given ObjectFactory. + * @param scheme the URL scheme + * @param urlContextFactory the URL Context Factory selected for that scheme + * @param factoryFilter the factory filter. If the Reference was retrieved from + * LDAP this is typically an instance of ContextFactoryFilter. + * @return true if a URL Reference of the given URL scheme is allowed to be processed + * by the given ObjectFactory. + */ + public static boolean checkURLContextFactory(String scheme, + ObjectFactory urlContextFactory, + Predicate factoryFilter) { + if (factoryFilter instanceof ContextFactoryFilter ucf) { + return ucf.checkURLContextFactory(scheme, urlContextFactory.getClass()); + } + return true; + } + + /** * Checks if serial filter configured with {@code "jdk.jndi.object.factoriesFilter"} * system property value allows instantiation of the specified objects factory class. * If the filter result is {@linkplain Status#ALLOWED ALLOWED}, the filter will diff -Nru openjdk-25-25.0.4.1+1/src/java.naming/share/classes/module-info.java openjdk-25-25.0.5+8/src/java.naming/share/classes/module-info.java --- openjdk-25-25.0.4.1+1/src/java.naming/share/classes/module-info.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.naming/share/classes/module-info.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,18 +89,34 @@ *

The following implementation specific system properties are supported by the * default LDAP Naming Service Provider implementation in the JDK: *

    - *
  • {@systemProperty com.sun.jndi.ldap.object.trustSerialData}: + *
  • {@systemProperty com.sun.jndi.ldap.object.trustSerialData}: *
    The value of this system property is the string representation of a boolean value * that controls the deserialization of java objects from the {@code javaSerializedData} LDAP * attribute, reconstruction of RMI references from the {@code javaRemoteLocation} LDAP attribute, and * reconstruction of {@linkplain javax.naming.BinaryRefAddr binary reference addresses} from - * the {@code javaReferenceAddress} LDAP attribute. + * the {@code javaReferenceAddress} LDAP attribute. It also controls whether RMI URL References + * obtained from LDAP will be followed. * To allow the deserialization or reconstruction of java objects from {@code javaSerializedData}, * {@code javaRemoteLocation} or {@code javaReferenceAddress} attributes, the system property value * can be set to {@code true} (case insensitive). *
    If the property is not specified the deserialization of java objects * from the {@code javaSerializedData}, the {@code javaRemoteLocation}, or {@code javaReferenceAddress} - * attributes is not allowed. + * attributes is not allowed. In addition URL References obtained from LDAP that use the + * {@code rmi} scheme will not be followed by default, unless the default value of the {@link + * ##disabledURLSchemes jdk.jndi.ldap.disabledURLSchemes} system property is overridden on the + * java command line to allow it. + *
  • + *
  • {@systemProperty jdk.jndi.ldap.disabledURLSchemes}: + *
    The value of this system property is a comma separated list of URL schemes for which + * use of a URL Context Factory is disabled when processing {@linkplain javax.naming.StringRefAddr + * string reference addresses} in the built-in JNDI/LDAP provider. If the value of that property + * is empty then all schemes are allowed. + *
    The default value of that property is empty if {@linkplain ##trustSerialData + * deserialization of java objects} is allowed, and {@code "rmi"} if deserialization of java + * objects is not allowed: in that latter case {@linkplain javax.naming.StringRefAddr string reference + * addresses} of {@linkplain javax.naming.StringRefAddr#getType() type} {@code "URL"} whose {@linkplain + * javax.naming.StringRefAddr#getContent() content} is an URL string with scheme {@code "rmi"} + * will not be followed. *
  • *
  • {@systemProperty jdk.jndi.object.factoriesFilter}: *
    The value of this system property defines a filter used by diff -Nru openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java --- openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -49,7 +49,7 @@ * Implementation of Http Basic authentication. */ class AuthenticationFilter implements HeaderFilter { - volatile MultiExchange exchange; + private static final Base64.Encoder encoder = Base64.getEncoder(); static final int DEFAULT_RETRY_LIMIT = 3; @@ -67,12 +67,12 @@ // A public no-arg constructor is required by FilterFactory public AuthenticationFilter() {} - private PasswordAuthentication getCredentials(String header, + private PasswordAuthentication getCredentials(HttpClientImpl client, + String header, boolean proxy, HttpRequestImpl req) throws IOException { - HttpClientImpl client = exchange.client(); java.net.Authenticator auth = client.authenticator() .orElseThrow(() -> new IOException("No authenticator set")); @@ -144,33 +144,51 @@ } @Override - public void request(HttpRequestImpl r, MultiExchange e) throws IOException { + public void request(HttpRequestImpl r, MultiExchange exchange) throws IOException { // use preemptive authentication if an entry exists. - Cache cache = getCache(e); - this.exchange = e; + Cache cache = getCache(exchange.client()); + AuthInfo serverAuth = exchange.serverauth; + AuthInfo proxyAuth = exchange.proxyauth; + + if (serverAuth != null && !sameOriginAndScheme(serverAuth.requestor, r.uri())) { + serverAuth = exchange.serverauth = null; + } + if (proxyAuth != null && !sameOriginAndScheme(proxyAuth.requestor, getProxyURI(r))) { + proxyAuth = exchange.proxyauth = null; + } // Proxy - if (exchange.proxyauth == null) { + if (proxyAuth == null) { URI proxyURI = getProxyURI(r); if (proxyURI != null) { CacheEntry ca = cache.get(proxyURI, true); if (ca != null) { - exchange.proxyauth = new AuthInfo(true, ca.scheme, null, ca, ca.isUTF8); + exchange.proxyauth = new AuthInfo(true, ca.scheme, proxyURI, null, ca, ca.isUTF8); addBasicCredentials(r, true, ca.value, ca.isUTF8); } } } // Server - if (exchange.serverauth == null) { - CacheEntry ca = cache.get(r.uri(), false); + if (serverAuth == null) { + URI requestor = r.uri(); + CacheEntry ca = cache.get(requestor, false); if (ca != null) { - exchange.serverauth = new AuthInfo(true, ca.scheme, null, ca, ca.isUTF8); + exchange.serverauth = new AuthInfo(true, ca.scheme, requestor, null, ca, ca.isUTF8); addBasicCredentials(r, false, ca.value, ca.isUTF8); } } } + private static boolean sameOriginAndScheme(URI uri, URI other) { + // in this context we don't need to use equalsIgnoreCase. + if (uri == other) return true; + if (uri == null || other == null) return false; + if (!Objects.equals(uri.getScheme(), other.getScheme())) return false; + if (!Objects.equals(uri.getRawAuthority(), other.getRawAuthority())) return false; + return true; + } + // TODO: refactor into per auth scheme class private static void addBasicCredentials(HttpRequestImpl r, boolean proxy, @@ -202,6 +220,7 @@ static class AuthInfo { final boolean fromcache; final String scheme; + final URI requestor; int retries; PasswordAuthentication credentials; // used in request CacheEntry cacheEntry; // if used @@ -209,19 +228,24 @@ AuthInfo(boolean fromcache, String scheme, - PasswordAuthentication credentials, boolean isUTF8) { + URI requestor, + PasswordAuthentication credentials, + boolean isUTF8) { this.fromcache = fromcache; this.scheme = scheme; this.credentials = credentials; + this.requestor = requestor; this.retries = 1; this.isUTF8 = isUTF8; } AuthInfo(boolean fromcache, String scheme, + URI requestor, PasswordAuthentication credentials, - CacheEntry ca, boolean isUTF8) { - this(fromcache, scheme, credentials, isUTF8); + CacheEntry ca, + boolean isUTF8) { + this(fromcache, scheme, requestor, credentials, isUTF8); assert credentials == null || (ca != null && ca.value == null); cacheEntry = ca; } @@ -230,7 +254,9 @@ // If the info was already in the cache we need to create a new // instance with fromCache==false so that it's put back in the // cache if authentication succeeds - AuthInfo res = fromcache ? new AuthInfo(false, scheme, pw, isUTF8) : this; + AuthInfo res = fromcache + ? new AuthInfo(false, scheme, requestor, pw, isUTF8) + : this; res.credentials = Objects.requireNonNull(pw); res.retries = retries; return res; @@ -239,7 +265,9 @@ @Override public HttpRequestImpl response(Response r) throws IOException { - Cache cache = getCache(exchange); + MultiExchange exchange = r.exchange.multi; + HttpClientImpl client = exchange.client(); + Cache cache = getCache(client); int status = r.statusCode(); HttpHeaders hdrs = r.headers(); HttpRequestImpl req = r.request(); @@ -253,28 +281,37 @@ } if (status != PROXY_UNAUTHORIZED) { - if (exchange.proxyauth != null && !exchange.proxyauth.fromcache) { - AuthInfo au = exchange.proxyauth; + AuthInfo au = exchange.proxyauth; + if (au != null && !au.fromcache) { URI proxyURI = getProxyURI(req); if (proxyURI != null) { - exchange.proxyauth = null; - cache.store(au.scheme, proxyURI, true, au.credentials, au.isUTF8); + if (sameOriginAndScheme(au.requestor, proxyURI)) { + exchange.proxyauth = null; + cache.store(au.scheme, au.requestor, true, au.credentials, au.isUTF8); + } } } if (status != UNAUTHORIZED) { + au = exchange.serverauth; // check if any authentication succeeded for first time - if (exchange.serverauth != null && !exchange.serverauth.fromcache) { - AuthInfo au = exchange.serverauth; - cache.store(au.scheme, req.uri(), false, au.credentials, au.isUTF8); + if (au != null && !au.fromcache) { + URI requestor = req.uri(); + if (sameOriginAndScheme(au.requestor, requestor)) { + cache.store(au.scheme, au.requestor, false, au.credentials, au.isUTF8); + } } + assert status != PROXY_UNAUTHORIZED && status != UNAUTHORIZED; return null; } + assert status == UNAUTHORIZED; } + assert status == PROXY_UNAUTHORIZED || status == UNAUTHORIZED; + boolean proxy = status == PROXY_UNAUTHORIZED; String authname = proxy ? "Proxy-Authenticate" : "WWW-Authenticate"; List authvals = hdrs.allValues(authname); - if (authvals.isEmpty() && exchange.client().authenticator().isPresent()) { + if (authvals.isEmpty() && client.authenticator().isPresent()) { throw new IOException(authname + " header missing for response code " + status); } String authval = null; @@ -310,16 +347,17 @@ } AuthInfo au = proxy ? exchange.proxyauth : exchange.serverauth; - if (au == null) { + URI requestor = proxy ? getProxyURI(req) : req.uri(); + if (au == null || !sameOriginAndScheme(au.requestor, requestor)) { // if no authenticator, let the user deal with 407/401 - if (exchange.client().authenticator().isEmpty()) return null; + if (client.authenticator().isEmpty()) return null; - PasswordAuthentication pw = getCredentials(authval, proxy, req); + PasswordAuthentication pw = getCredentials(client, authval, proxy, req); if (pw == null) { throw new IOException("No credentials provided"); } // No authentication in request. Get credentials from user - au = new AuthInfo(false, "Basic", pw, isUTF8); + au = new AuthInfo(false, "Basic",requestor, pw, isUTF8); if (proxy) { exchange.proxyauth = au; } else { @@ -332,16 +370,17 @@ throw new IOException("too many authentication attempts. Limit: " + retry_limit); } else { + assert sameOriginAndScheme(au.requestor, requestor); // we sent credentials, but they were rejected if (au.fromcache) { cache.remove(au.cacheEntry); } // if no authenticator, let the user deal with 407/401 - if (exchange.client().authenticator().isEmpty()) return null; + if (client.authenticator().isEmpty()) return null; // try again - PasswordAuthentication pw = getCredentials(authval, proxy, req); + PasswordAuthentication pw = getCredentials(client, authval, proxy, req); if (pw == null) { throw new IOException("No credentials provided"); } @@ -362,8 +401,7 @@ // be garbage collected when no longer referenced. static final WeakHashMap caches = new WeakHashMap<>(); - static synchronized Cache getCache(MultiExchange exchange) { - HttpClientImpl client = exchange.client(); + static synchronized Cache getCache(HttpClientImpl client) { Cache c = caches.get(client); if (c == null) { c = new Cache(); diff -Nru openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/CheckFilename.java openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/CheckFilename.java --- openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/CheckFilename.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/CheckFilename.java 2026-10-19 12:10:20.000000000 +0000 @@ -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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.net.http; + +import java.util.Set; +import java.util.List; +import java.util.Locale; +import jdk.internal.util.OperatingSystem; + +/** + * Checks for disallowed filenames that may be provided by a server + * which we do not want to write to. On Windows we disallow any filename + * that looks like a DOS legacy device. No restrictions on other platforms. + */ +final class CheckFilename { + + private CheckFilename() { + throw new InternalError(); + } + + private static final boolean isWindows = OperatingSystem.isWindows(); + + /** + * Reserved names documented at: + * https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file + * and other Microsoft api documentation + */ + private static final Set WINDOWS_RESERVED_NAMES = + Set.of("AUX", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", + "COM7", "COM8", "COM9", "COM¹", "COM²", "COM³", "CON", "CONIN$", + "CONOUT$", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", + "LPT9", "LPT¹", "LPT²", "LPT³", "NUL", "PRN"); + + /** + * name must be the final component of the pathname only. + * Possibly including an extension. + */ + public static boolean isAllowed(String name) { + if (!isWindows) + return true; + + // Microsoft documents reserved device names followed by extensions as equivalent to the device name. + // `CON.txt`, `NUL.tar.gz`, `COM1.txt`, etc. should not be allowed. + int dot = name.indexOf('.'); + if (dot != -1) { + name = name.substring(0, dot); + } + name = name.toUpperCase(Locale.ROOT) + .stripTrailing(); + + return !WINDOWS_RESERVED_NAMES.contains(name); + } +} diff -Nru openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java --- openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -1672,8 +1672,8 @@ } private void initFilters() { - addFilter(AuthenticationFilter.class); addFilter(RedirectFilter.class); + addFilter(AuthenticationFilter.class); if (this.cookieHandler != null) { addFilter(CookieFilter.class); } diff -Nru openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/RedirectFilter.java openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/RedirectFilter.java --- openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/RedirectFilter.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/RedirectFilter.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, 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 @@ -28,23 +28,15 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.net.URI; -import java.net.http.HttpClient; +import java.net.http.HttpClient.Redirect; import java.net.http.HttpHeaders; -import java.util.concurrent.locks.ReentrantLock; import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Utils; class RedirectFilter implements HeaderFilter { - private final ReentrantLock stateLock = new ReentrantLock(); - HttpRequestImpl request; - HttpClientImpl client; - HttpClient.Redirect policy; - String method; - MultiExchange exchange; static final int DEFAULT_MAX_REDIRECTS = 5; - URI uri; /* * NOT_MODIFIED status code results from a conditional GET where @@ -62,28 +54,11 @@ @Override public void request(HttpRequestImpl r, MultiExchange e) throws IOException { - stateLock.lock(); - try { - this.request = r; - this.client = e.client(); - this.policy = client.followRedirects(); - - this.method = r.method(); - this.uri = r.uri(); - this.exchange = e; - } finally { - stateLock.unlock(); - } } @Override public HttpRequestImpl response(Response r) throws IOException { - stateLock.lock(); - try { - return handleResponse(r); - } finally { - stateLock.unlock(); - } + return handleResponse(r); } private static String redirectedMethod(int statusCode, String orig) { @@ -120,7 +95,9 @@ */ private HttpRequestImpl handleResponse(Response r) { int rcode = r.statusCode(); - if (rcode == 200 || policy == HttpClient.Redirect.NEVER) { + MultiExchange exchange = r.exchange.multi; + Redirect policy = exchange.client.followRedirects(); + if (rcode == 200 || policy == Redirect.NEVER) { return null; } @@ -128,10 +105,12 @@ return null; if (isRedirecting(rcode)) { - URI redir = getRedirectedURI(r.headers()); - String newMethod = redirectedMethod(rcode, method); + HttpRequestImpl request = r.request(); + URI from = request.uri(); + URI redir = getRedirectedURI(from, r.headers()); + String newMethod = redirectedMethod(rcode, request.method()); Log.logTrace("response code: {0}, redirected URI: {1}", rcode, redir); - if (canRedirect(redir) && ++exchange.numberOfRedirects < max_redirects) { + if (canRedirect(from, redir, policy) && ++exchange.numberOfRedirects < max_redirects) { Log.logTrace("redirect to: {0} with method: {1}", redir, newMethod); return HttpRequestImpl.newInstanceForRedirection(redir, newMethod, request, rcode != 303); } else { @@ -142,7 +121,7 @@ return null; } - private URI getRedirectedURI(HttpHeaders headers) { + private URI getRedirectedURI(URI uri, HttpHeaders headers) { URI redirectedURI; redirectedURI = headers.firstValue("Location") .map(URI::create) @@ -155,7 +134,7 @@ return redirectedURI; } - private boolean canRedirect(URI redir) { + private boolean canRedirect(URI uri, URI redir, Redirect policy) { String newScheme = redir.getScheme(); String oldScheme = uri.getScheme(); return switch (policy) { diff -Nru openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java --- openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java 2026-10-19 12:10:20.000000000 +0000 @@ -320,7 +320,7 @@ filenameParam = filenameParam.trim(); - if (PROHIBITED.contains(filenameParam)) { + if (PROHIBITED.contains(filenameParam) || !CheckFilename.isAllowed(filenameParam)) { throw unchecked(responseInfo, "Prohibited Content-Disposition filename parameter:" + filenameParam); diff -Nru openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/ResponseContent.java openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/ResponseContent.java --- openjdk-25-25.0.4.1+1/src/java.net.http/share/classes/jdk/internal/net/http/ResponseContent.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.net.http/share/classes/jdk/internal/net/http/ResponseContent.java 2026-10-19 12:10:20.000000000 +0000 @@ -26,6 +26,7 @@ package jdk.internal.net.http; import java.io.IOException; +import java.net.ProtocolException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; @@ -141,7 +142,7 @@ volatile boolean cr = false; // tryReadChunkLength has found CR volatile int chunkext = 0; // number of bytes already read in the chunk extension volatile int digits = 0; // number of chunkLength bytes already read - volatile int bytesToConsume; // number of bytes that still need to be consumed before proceeding + volatile int crlfBytesToConsume; // number of CRLF bytes that still need to be consumed volatile ChunkState state = ChunkState.READING_LENGTH; // current state volatile AbstractSubscription sub; ChunkedBodyParser(Consumer onComplete) { @@ -252,8 +253,8 @@ private int tryReadChunkLen(ByteBuffer chunkbuf) throws IOException { assert state == ChunkState.READING_LENGTH; while (chunkbuf.hasRemaining()) { - if (chunkext + digits >= MAX_CHUNK_HEADER_SIZE) { - throw new IOException("Chunk header size too long: " + (chunkext + digits)); + if (chunkext >= MAX_CHUNK_HEADER_SIZE - digits) { + throw new IOException("Chunk header size too long: " + (chunkext + (long) digits)); } int c = chunkbuf.get(); if (cr) { @@ -265,8 +266,8 @@ } if (c == CR) { cr = true; - if (digits == 0 && debug.on()) { - debug.log("tryReadChunkLen: invalid chunk header? No digits in chunkLen?"); + if (digits == 0) { + throw new ProtocolException("Chunk header doesn't contain any digits"); } } else if (cr == false && chunkext > 0) { // we have seen a non digit character after the chunk length. @@ -291,41 +292,33 @@ } } else { digits++; - partialChunklen = partialChunklen * 16 + digit; + long nextPartialChunklen = partialChunklen * 16L + digit; + if (nextPartialChunklen > Integer.MAX_VALUE) { + throw new ProtocolException("chunk length too big: " + nextPartialChunklen); + } + partialChunklen = (int) nextPartialChunklen; } } } return -1; } - - // try to consume as many bytes as specified by bytesToConsume. - // returns the number of bytes that still need to be consumed. - // In practice this method is only called to consume one CRLF pair - // with bytesToConsume set to 2, so it will only return 0 (if completed), - // 1, or 2 (if chunkbuf doesn't have the 2 chars). - private int tryConsumeBytes(ByteBuffer chunkbuf) throws IOException { - int n = bytesToConsume; - if (n > 0) { - int e = Math.min(chunkbuf.remaining(), n); - - // verifies some assertions - // this methods is called only to consume CRLF - if (Utils.ASSERTIONSENABLED) { - assert n <= 2 && e <= 2; - ByteBuffer tmp = chunkbuf.slice(); - // if n == 2 assert that we will first consume CR - assert (n == 2 && e > 0) ? tmp.get() == CR : true; - // if n == 1 || n == 2 && e == 2 assert that we then consume LF - assert (n == 1 || e == 2) ? tmp.get() == LF : true; + private boolean tryConsumeCRLF(ByteBuffer buffer) throws ProtocolException { + assert crlfBytesToConsume >= 0 && crlfBytesToConsume <= 2; + for (; crlfBytesToConsume > 0 && buffer.remaining() > 0; crlfBytesToConsume--) { + byte b = buffer.get(); + if (crlfBytesToConsume == 1) { // 1 byte to go (implies already consumed CR), check LF + if (b != LF) { + throw new ProtocolException("LF expected"); + } + } else { // 2 bytes to go, check CR + assert crlfBytesToConsume == 2; + if (b != CR) { + throw new ProtocolException("CR expected"); + } } - - chunkbuf.position(chunkbuf.position() + e); - n -= e; - bytesToConsume = n; } - assert n >= 0; - return n; + return crlfBytesToConsume == 0; } /** @@ -338,7 +331,7 @@ */ ByteBuffer tryReadOneHunk(ByteBuffer chunk) throws IOException { int unfulfilled = bytesremaining; - int toconsume = bytesToConsume; + int toconsume = crlfBytesToConsume; ChunkState st = state; if (st == ChunkState.READING_LENGTH && chunklen == -1) { if (debug.on()) debug.log(() -> "Trying to read chunk len" @@ -349,7 +342,7 @@ if (debug.on()) debug.log("Got chunk len %d", clen); cr = false; partialChunklen = 0; unfulfilled = bytesremaining = clen; - if (clen == 0) toconsume = bytesToConsume = 2; // that was the last chunk + if (clen == 0) toconsume = crlfBytesToConsume = 2; // that was the last chunk else st = state = ChunkState.READING_DATA; // read the data } @@ -357,12 +350,12 @@ if (debug.on()) debug.log("Trying to consume bytes: %d (remaining in buffer: %s)", toconsume, chunk.remaining()); - if (tryConsumeBytes(chunk) > 0) { + if (!tryConsumeCRLF(chunk)) { return READMORE; } } - toconsume = bytesToConsume; + toconsume = crlfBytesToConsume; assert toconsume == 0; @@ -394,7 +387,7 @@ debug.log( "Returning chunk bytes: %d", bytes2return); returnBuffer = Utils.sliceWithLimitedCapacity(chunk, bytes2return).asReadOnlyBuffer(); unfulfilled = bytesremaining -= bytes2return; - if (unfulfilled == 0) bytesToConsume = 2; + if (unfulfilled == 0) crlfBytesToConsume = 2; } assert unfulfilled >= 0; @@ -408,7 +401,7 @@ // then we will come back here later - skipping the block // that reads data because remaining==0, and finding // that the two bytes are now consumed. - if (tryConsumeBytes(chunk) == 0) { + if (tryConsumeCRLF(chunk)) { // we're done for this chunk! reset all states and // prepare to read the next chunk. chunklen = -1; diff -Nru openjdk-25-25.0.4.1+1/src/java.prefs/unix/native/libprefs/FileSystemPreferences.c openjdk-25-25.0.5+8/src/java.prefs/unix/native/libprefs/FileSystemPreferences.c --- openjdk-25-25.0.4.1+1/src/java.prefs/unix/native/libprefs/FileSystemPreferences.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.prefs/unix/native/libprefs/FileSystemPreferences.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,6 @@ int fd, rc; int result[2] = {0, 0}; jintArray javaResult = NULL; - int old_umask; struct flock fl; if (!fname) @@ -86,10 +85,12 @@ fd = open(fname, O_RDONLY, 0); result[1] = errno; } else { - old_umask = umask(0); fd = open(fname, O_WRONLY|O_CREAT, permission); result[1] = errno; - umask(old_umask); + if (fd >= 0) { + /* lock file created; set correct permissions */ + fchmod(fd, permission); /* assume will succeed, ignore retval & errno */ + } } if (fd < 0) { diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, 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 @@ -39,6 +39,7 @@ import java.security.MessageDigest; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; + import sun.security.krb5.*; import sun.security.krb5.internal.crypto.Aes128Sha2; import sun.security.krb5.internal.crypto.Aes256Sha2; @@ -47,6 +48,7 @@ import sun.security.krb5.internal.crypto.Aes256; import sun.security.krb5.internal.crypto.ArcFourHmac; import sun.security.krb5.internal.crypto.EType; +import sun.security.util.ByteArrays; class CipherHelper { @@ -587,34 +589,43 @@ // decrypt data in the new GSS tokens void decryptData(WrapToken_v2 token, byte[] ciphertext, int cStart, int cLen, byte[] plaintext, int pStart, int key_usage) - throws GSSException { - - /* - Krb5Token.debug("decryptData : ciphertext = " + - Krb5Token.getHexBytes(ciphertext)); - */ + throws GSSException { + byte[] decrypted; switch (etype) { case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96: - aes128Decrypt(token, ciphertext, cStart, cLen, - plaintext, pStart, key_usage); - break; + decrypted = aes128Decrypt(ciphertext, cStart, cLen, key_usage); + break; case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: - aes256Decrypt(token, ciphertext, cStart, cLen, - plaintext, pStart, key_usage); - break; + decrypted = aes256Decrypt(ciphertext, cStart, cLen, key_usage); + break; case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: - aes128Sha2Decrypt(token, ciphertext, cStart, cLen, - plaintext, pStart, key_usage); - break; + decrypted = aes128Sha2Decrypt(ciphertext, cStart, cLen, key_usage); + break; case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: - aes256Sha2Decrypt(token, ciphertext, cStart, cLen, - plaintext, pStart, key_usage); - break; + decrypted = aes256Sha2Decrypt(ciphertext, cStart, cLen, key_usage); + break; default: - throw new GSSException(GSSException.FAILURE, -1, + throw new GSSException(GSSException.FAILURE, -1, "Unsupported etype: " + etype); - } + } + byte[] outerHeader = token.getTokenHeader().clone(); + outerHeader[MessageToken_v2.TOKEN_RRC_POS] = 0; + outerHeader[MessageToken_v2.TOKEN_RRC_POS + 1] = 0; + int len = decrypted.length - WrapToken_v2.CONFOUNDER_SIZE - + WrapToken_v2.TOKEN_HEADER_SIZE - token.getEc(); + if (len < 0) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + if (!ByteArrays.isEqual( + outerHeader, + 0, WrapToken_v2.TOKEN_HEADER_SIZE, + decrypted, + decrypted.length - WrapToken_v2.TOKEN_HEADER_SIZE, decrypted.length)) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + System.arraycopy(decrypted, WrapToken_v2.CONFOUNDER_SIZE, + plaintext, pStart, len); } void decryptData(WrapToken token, InputStream cipherStream, int cLen, @@ -667,44 +678,6 @@ } } - void decryptData(WrapToken_v2 token, InputStream cipherStream, int cLen, - byte[] plaintext, int pStart, int key_usage) - throws GSSException, IOException { - - // Read encrypted data from stream - byte[] ciphertext = new byte[cLen]; - try { - Krb5Token.readFully(cipherStream, ciphertext, 0, cLen); - } catch (IOException e) { - GSSException ge = new GSSException( - GSSException.DEFECTIVE_TOKEN, -1, - "Cannot read complete token"); - ge.initCause(e); - throw ge; - } - switch (etype) { - case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96: - aes128Decrypt(token, ciphertext, 0, cLen, - plaintext, pStart, key_usage); - break; - case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: - aes256Decrypt(token, ciphertext, 0, cLen, - plaintext, pStart, key_usage); - break; - case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: - aes128Sha2Decrypt(token, ciphertext, 0, cLen, - plaintext, pStart, key_usage); - break; - case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: - aes256Sha2Decrypt(token, ciphertext, 0, cLen, - plaintext, pStart, key_usage); - break; - default: - throw new GSSException(GSSException.FAILURE, -1, - "Unsupported etype: " + etype); - } - } - void encryptData(WrapToken token, byte[] confounder, byte[] plaintext, int start, int len, byte[] padding, OutputStream os) throws GSSException, IOException { @@ -824,45 +797,6 @@ } } - /* - * Encrypt data in the new GSS tokens - * - * Wrap Tokens (with confidentiality) - * { Encrypt(16-byte confounder | plaintext | 16-byte token_header) | - * 12-byte HMAC } - * where HMAC is on {16-byte confounder | plaintext | 16-byte token_header} - * HMAC is not encrypted; it is appended at the end. - */ - int encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader, - byte[] plaintext, int pStart, int pLen, byte[] ciphertext, int cStart, - int key_usage) throws GSSException { - - byte[] ctext; - switch (etype) { - case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96: - ctext = aes128Encrypt(confounder, tokenHeader, - plaintext, pStart, pLen, key_usage); - break; - case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: - ctext = aes256Encrypt(confounder, tokenHeader, - plaintext, pStart, pLen, key_usage); - break; - case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: - ctext = aes128Sha2Encrypt(confounder, tokenHeader, - plaintext, pStart, pLen, key_usage); - break; - case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: - ctext = aes256Sha2Encrypt(confounder, tokenHeader, - plaintext, pStart, pLen, key_usage); - break; - default: - throw new GSSException(GSSException.FAILURE, -1, - "Unsupported etype: " + etype); - } - System.arraycopy(ctext, 0, ciphertext, cStart, ctext.length); - return ctext.length; - } - // --------------------- DES methods /** @@ -1408,14 +1342,11 @@ } } - private void aes128Decrypt(WrapToken_v2 token, byte[] ciphertext, - int cStart, int cLen, byte[] plaintext, int pStart, int key_usage) - throws GSSException { - - byte[] ptext; + private byte[] aes128Decrypt(byte[] ciphertext, + int cStart, int cLen, int key_usage) throws GSSException { try { - ptext = Aes128.decryptRaw(keybytes, key_usage, + return Aes128.decryptRaw(keybytes, key_usage, ZERO_IV_AES, ciphertext, cStart, cLen); } catch (GeneralSecurityException e) { GSSException ge = new GSSException(GSSException.FAILURE, -1, @@ -1423,36 +1354,13 @@ ge.initCause(e); throw ge; } - - /* - Krb5Token.debug("\naes128Decrypt in: " + - Krb5Token.getHexBytes(ciphertext, cStart, cLen)); - Krb5Token.debug("\naes128Decrypt plain: " + - Krb5Token.getHexBytes(ptext)); - Krb5Token.debug("\naes128Decrypt ptext: " + - Krb5Token.getHexBytes(ptext)); - */ - - // Strip out confounder and token header - int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE - - WrapToken_v2.TOKEN_HEADER_SIZE; - System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE, - plaintext, pStart, len); - - /* - Krb5Token.debug("\naes128Decrypt plaintext: " + - Krb5Token.getHexBytes(plaintext, pStart, len)); - */ } - private void aes128Sha2Decrypt(WrapToken_v2 token, byte[] ciphertext, - int cStart, int cLen, byte[] plaintext, int pStart, int key_usage) - throws GSSException { - - byte[] ptext; + private byte[] aes128Sha2Decrypt(byte[] ciphertext, + int cStart, int cLen, int key_usage) throws GSSException { try { - ptext = Aes128Sha2.decryptRaw(keybytes, key_usage, + return Aes128Sha2.decryptRaw(keybytes, key_usage, ZERO_IV_AES, ciphertext, cStart, cLen); } catch (GeneralSecurityException e) { GSSException ge = new GSSException(GSSException.FAILURE, -1, @@ -1460,26 +1368,6 @@ ge.initCause(e); throw ge; } - - /* - Krb5Token.debug("\naes128Sha2Decrypt in: " + - Krb5Token.getHexBytes(ciphertext, cStart, cLen)); - Krb5Token.debug("\naes128Sha2Decrypt plain: " + - Krb5Token.getHexBytes(ptext)); - Krb5Token.debug("\naes128Sha2Decrypt ptext: " + - Krb5Token.getHexBytes(ptext)); - */ - - // Strip out confounder and token header - int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE - - WrapToken_v2.TOKEN_HEADER_SIZE; - System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE, - plaintext, pStart, len); - - /* - Krb5Token.debug("\naes128Sha2Decrypt plaintext: " + - Krb5Token.getHexBytes(plaintext, pStart, len)); - */ } private byte[] aes256Encrypt(byte[] confounder, byte[] tokenHeader, @@ -1546,13 +1434,11 @@ } } - private void aes256Decrypt(WrapToken_v2 token, byte[] ciphertext, - int cStart, int cLen, byte[] plaintext, int pStart, int key_usage) - throws GSSException { + private byte[] aes256Decrypt(byte[] ciphertext, + int cStart, int cLen, int key_usage) throws GSSException { - byte[] ptext; try { - ptext = Aes256.decryptRaw(keybytes, key_usage, + return Aes256.decryptRaw(keybytes, key_usage, ZERO_IV_AES, ciphertext, cStart, cLen); } catch (GeneralSecurityException e) { GSSException ge = new GSSException(GSSException.FAILURE, -1, @@ -1560,36 +1446,13 @@ ge.initCause(e); throw ge; } - - /* - Krb5Token.debug("\naes256Decrypt in: " + - Krb5Token.getHexBytes(ciphertext, cStart, cLen)); - Krb5Token.debug("\naes256Decrypt plain: " + - Krb5Token.getHexBytes(ptext)); - Krb5Token.debug("\naes256Decrypt ptext: " + - Krb5Token.getHexBytes(ptext)); - */ - - // Strip out confounder and token header - int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE - - WrapToken_v2.TOKEN_HEADER_SIZE; - System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE, - plaintext, pStart, len); - - /* - Krb5Token.debug("\naes128Decrypt plaintext: " + - Krb5Token.getHexBytes(plaintext, pStart, len)); - */ - } - private void aes256Sha2Decrypt(WrapToken_v2 token, byte[] ciphertext, - int cStart, int cLen, byte[] plaintext, int pStart, int key_usage) - throws GSSException { + private byte[] aes256Sha2Decrypt(byte[] ciphertext, + int cStart, int cLen, int key_usage) throws GSSException { - byte[] ptext; try { - ptext = Aes256Sha2.decryptRaw(keybytes, key_usage, + return Aes256Sha2.decryptRaw(keybytes, key_usage, ZERO_IV_AES, ciphertext, cStart, cLen); } catch (GeneralSecurityException e) { GSSException ge = new GSSException(GSSException.FAILURE, -1, @@ -1597,27 +1460,6 @@ ge.initCause(e); throw ge; } - - /* - Krb5Token.debug("\naes256Sha2Decrypt in: " + - Krb5Token.getHexBytes(ciphertext, cStart, cLen)); - Krb5Token.debug("\naes256Sha2Decrypt plain: " + - Krb5Token.getHexBytes(ptext)); - Krb5Token.debug("\naes256Sha2Decrypt ptext: " + - Krb5Token.getHexBytes(ptext)); - */ - - // Strip out confounder and token header - int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE - - WrapToken_v2.TOKEN_HEADER_SIZE; - System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE, - plaintext, pStart, len); - - /* - Krb5Token.debug("\naes256Sha2Decrypt plaintext: " + - Krb5Token.getHexBytes(plaintext, pStart, len)); - */ - } /** diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -903,39 +903,6 @@ } } - public final int wrap(byte[] inBuf, int inOffset, int len, - byte[] outBuf, int outOffset, - MessageProp msgProp) throws GSSException { - - if (state != STATE_DONE) - throw new GSSException(GSSException.NO_CONTEXT, -1, - "Wrap called in invalid state!"); - - int retVal = 0; - try { - if (cipherHelper.getProto() == 0) { - WrapToken token = - new WrapToken(this, msgProp, inBuf, inOffset, len); - retVal = token.encode(outBuf, outOffset); - } else if (cipherHelper.getProto() == 1) { - WrapToken_v2 token = - new WrapToken_v2(this, msgProp, inBuf, inOffset, len); - retVal = token.encode(outBuf, outOffset); - } - if (DEBUG != null) { - DEBUG.println("Krb5Context.wrap: token=[" - + getHexBytes(outBuf, outOffset, retVal) - + "]"); - } - return retVal; - } catch (IOException e) { - GSSException gssException = - new GSSException(GSSException.FAILURE, -1, e.getMessage()); - gssException.initCause(e); - throw gssException; - } - } - public final void wrap(byte[] inBuf, int offset, int len, OutputStream os, MessageProp msgProp) throws GSSException { @@ -993,79 +960,35 @@ public final byte[] unwrap(byte[] inBuf, int offset, int len, MessageProp msgProp) - throws GSSException { - - if (DEBUG != null) { - DEBUG.println("Krb5Context.unwrap: token=[" - + getHexBytes(inBuf, offset, len) - + "]"); - } - - if (state != STATE_DONE) { - throw new GSSException(GSSException.NO_CONTEXT, -1, - " Unwrap called in invalid state!"); - } - - byte[] data = null; - if (cipherHelper.getProto() == 0) { - WrapToken token = - new WrapToken(this, inBuf, offset, len, msgProp); - data = token.getData(); - setSequencingAndReplayProps(token, msgProp); - } else if (cipherHelper.getProto() == 1) { - WrapToken_v2 token = - new WrapToken_v2(this, inBuf, offset, len, msgProp); - data = token.getData(); - setSequencingAndReplayProps(token, msgProp); - } + throws GSSException { - return data; + if (DEBUG != null) { + DEBUG.println("Krb5Context.unwrap: token=[" + + getHexBytes(inBuf, offset, len) + + "]"); } - public final int unwrap(byte[] inBuf, int inOffset, int len, - byte[] outBuf, int outOffset, - MessageProp msgProp) throws GSSException { - - if (state != STATE_DONE) + if (state != STATE_DONE) { throw new GSSException(GSSException.NO_CONTEXT, -1, - "Unwrap called in invalid state!"); + " Unwrap called in invalid state!"); + } + byte[] data = null; if (cipherHelper.getProto() == 0) { WrapToken token = - new WrapToken(this, inBuf, inOffset, len, msgProp); - len = token.getData(outBuf, outOffset); + new WrapToken(this, inBuf, offset, len, msgProp); + data = token.getData(); setSequencingAndReplayProps(token, msgProp); } else if (cipherHelper.getProto() == 1) { WrapToken_v2 token = - new WrapToken_v2(this, inBuf, inOffset, len, msgProp); - len = token.getData(outBuf, outOffset); + new WrapToken_v2(this, inBuf, offset, len, msgProp); + data = token.getData(); setSequencingAndReplayProps(token, msgProp); } - return len; - } - - public final int unwrap(InputStream is, - byte[] outBuf, int outOffset, - MessageProp msgProp) throws GSSException { - if (state != STATE_DONE) - throw new GSSException(GSSException.NO_CONTEXT, -1, - "Unwrap called in invalid state!"); - - int len = 0; - if (cipherHelper.getProto() == 0) { - WrapToken token = new WrapToken(this, is, msgProp); - len = token.getData(outBuf, outOffset); - setSequencingAndReplayProps(token, msgProp); - } else if (cipherHelper.getProto() == 1) { - WrapToken_v2 token = new WrapToken_v2(this, is, msgProp); - len = token.getData(outBuf, outOffset); - setSequencingAndReplayProps(token, msgProp); - } - return len; + return data; } - public final void unwrap(InputStream is, OutputStream os, MessageProp msgProp) throws GSSException { @@ -1119,31 +1042,6 @@ } } - private int getMIC(byte[] inMsg, int offset, int len, - byte[] outBuf, int outOffset, - MessageProp msgProp) - throws GSSException { - - int retVal = 0; - try { - if (cipherHelper.getProto() == 0) { - MicToken token = - new MicToken(this, msgProp, inMsg, offset, len); - retVal = token.encode(outBuf, outOffset); - } else if (cipherHelper.getProto() == 1) { - MicToken_v2 token = - new MicToken_v2(this, msgProp, inMsg, offset, len); - retVal = token.encode(outBuf, outOffset); - } - return retVal; - } catch (IOException e) { - GSSException gssException = - new GSSException(GSSException.FAILURE, -1, e.getMessage()); - gssException.initCause(e); - throw gssException; - } - } - /* * Checksum calculation requires a byte[]. Hence, might as well pass * a byte[] into the MicToken constructor. However, writing the diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/MessageToken_v2.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/MessageToken_v2.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/MessageToken_v2.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/MessageToken_v2.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -102,7 +102,9 @@ private static final int TOKEN_ID_POS = 0; private static final int TOKEN_FLAG_POS = 2; private static final int TOKEN_EC_POS = 4; - private static final int TOKEN_RRC_POS = 6; + + // Accessed by CipherHelper to normalize RRC + public static final int TOKEN_RRC_POS = 6; /** * The size of the random confounder used in a WrapToken. @@ -235,7 +237,14 @@ } if (tokenId == Krb5Token.WRAP_ID_v2) { - rotate(); + // According to RFC 4121, we should rotate by RRC. However, Windows + // rotates by RRC + EC in DCE-style tokens, and MIT krb5 follows it. + // (https://github.com/krb5/krb5/blob/07818f1/src/lib/gssapi/krb5/k5sealv3iov.c#L119) + // Non-DCE-style tokens observed from Windows shows EC = 0, and normal + // MIT krb5 build hardcoded EC = 0 for non-DCE-style tokens. + // (https://github.com/krb5/krb5/blob/07818f1/src/lib/gssapi/krb5/k5sealv3.c#L130), + // In this case, adding EC does not change the effective rotation. + rotate(prop.getPrivacy() ? (rrc + ec) : rrc); } if (tokenId == Krb5Token.MIC_ID_v2 || @@ -374,13 +383,13 @@ * Our implementation does not do any rotates when sending, only * when receiving, we rotate left as per the RRC count, to revert it. */ - private void rotate() { - if (rrc % tokenDataLen != 0) { - rrc = rrc % tokenDataLen; + private void rotate(int rotateNum) { + rotateNum = rotateNum % tokenDataLen; + if (rotateNum != 0) { byte[] newBytes = new byte[tokenDataLen]; - System.arraycopy(tokenData, rrc, newBytes, 0, tokenDataLen-rrc); - System.arraycopy(tokenData, 0, newBytes, tokenDataLen-rrc, rrc); + System.arraycopy(tokenData, rotateNum, newBytes, 0, tokenDataLen-rotateNum); + System.arraycopy(tokenData, 0, newBytes, tokenDataLen-rotateNum, rotateNum); tokenData = newBytes; } @@ -490,6 +499,15 @@ return (tokenHeader.getBytes()); } + /** + * Returns the EC value for the message token. + * @return the EC value + * @see CipherHelper#decryptData(WrapToken_v2, byte[], int, int, byte[], int, int) + */ + public final int getEc() { + return ec; + } + // ******************************************* // // I N N E R C L A S S E S F O L L O W // ******************************************* // diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/WrapToken_v2.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/WrapToken_v2.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/WrapToken_v2.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/jgss/krb5/WrapToken_v2.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -130,7 +130,7 @@ cipherHelper.decryptData(this, tokenData, 0, tokenDataLen, dataBuf, dataBufOffset, getKeyUsage()); - return tokenDataLen - CONFOUNDER_SIZE - + return tokenDataLen - CONFOUNDER_SIZE - getEc() - TOKEN_HEADER_SIZE - cipherHelper.getChecksumLength(); } else { diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java 2026-10-19 12:10:20.000000000 +0000 @@ -510,7 +510,7 @@ // Check that key is one of the permitted types private static void checkPermittedEType(int target) throws KrbException { int[] etypes = EType.getDefaults("permitted_enctypes"); - if (!EType.isSupported(target, etypes)) { + if (!EType.isOneOf(target, etypes)) { throw new KrbException(EType.toString(target) + " encryption type not in permitted_enctypes list"); } diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,11 +53,14 @@ // message, created by initiator after calling // the decrypt() method - KrbAsRep(byte[] ibuf) throws + KrbAsRep(byte[] ibuf, int[] requestedETypes) throws KrbException, Asn1Exception, IOException { DerValue encoding = new DerValue(ibuf); try { rep = new ASRep(encoding); + if (!EType.isOneOf(rep.encPart.getEType(), requestedETypes)) { + throw new KrbException("AS-REP enc_part not using requested etype"); + } } catch (Asn1Exception e) { rep = null; KRBError err = new KRBError(encoding); diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -344,7 +344,7 @@ } try { req = build(pakey, referralsState); - rep = new KrbAsRep(comm.send(req)); + rep = new KrbAsRep(comm.send(req), req.getMessage().reqBody.eType); return this; } catch (KrbException ke) { if (!preAuthFailedOnce && ( @@ -357,7 +357,7 @@ preAuthFailedOnce = true; KRBError kerr = ke.getError(); int paEType = PAData.getPreferredEType(kerr.getPA(), - EType.getDefaults("default_tkt_enctypes")[0]); + req.getMessage().reqBody.eType); if (password == null) { EncryptionKey[] ks = Krb5Util.keysFromJavaxKeyTab(ktab, cname); pakey = EncryptionKey.findKey(paEType, ks); diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/ETypeInfo2.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/ETypeInfo2.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/ETypeInfo2.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/ETypeInfo2.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, 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 @@ -165,4 +165,7 @@ return ((s2kparams == null) ? null : s2kparams.clone()); } + public boolean hasParams() { + return s2kparams != null; + } } diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java 2026-10-19 12:10:20.000000000 +0000 @@ -77,9 +77,9 @@ public KerberosTime till; public KerberosTime rtime; //optional public HostAddresses addresses; //optional + public int[] eType = null; //a sequence; not optional private int nonce; - private int[] eType = null; //a sequence; not optional private EncryptedData encAuthorizationData; //optional private Ticket[] additionalTickets; //optional diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -188,13 +188,13 @@ * * (This is useful when PA-DATAs from KRB-ERROR and AS-REP are combined). * - * @return the etype, or defaultEType if not enough info + * @return the etype, or requestedETypes[0] if not enough info * @throws Asn1Exception|IOException if there is an encoding error */ - public static int getPreferredEType(PAData[] pas, int defaultEType) + public static int getPreferredEType(PAData[] pas, int[] requestedETypes) throws IOException, Asn1Exception { - if (pas == null) return defaultEType; + if (pas == null) return requestedETypes[0]; DerValue d = null, d2 = null; for (PAData p: pas) { @@ -209,23 +209,34 @@ } } if (d2 != null) { + ArrayList offered = new ArrayList<>(); while (d2.data.available() > 0) { DerValue value = d2.data.getDerValue(); ETypeInfo2 tmp = new ETypeInfo2(value); - if (EType.isNewer(tmp.getEType()) || tmp.getParams() == null) { + if (EType.isNewer(tmp.getEType()) || !tmp.hasParams()) { // we don't support non-null s2kparams for old etypes - return tmp.getEType(); + offered.add(tmp.getEType()); + } + } + for (int etype : requestedETypes) { + if (offered.contains(etype)) { + return etype; } } } if (d != null) { + ArrayList offered = new ArrayList<>(); while (d.data.available() > 0) { DerValue value = d.data.getDerValue(); - ETypeInfo tmp = new ETypeInfo(value); - return tmp.getEType(); + offered.add(new ETypeInfo(value).getEType()); + } + for (int etype : requestedETypes) { + if (offered.contains(etype)) { + return etype; + } } } - return defaultEType; + return requestedETypes[0]; } /** @@ -280,7 +291,7 @@ DerValue value = d2.data.getDerValue(); ETypeInfo2 tmp = new ETypeInfo2(value); if (tmp.getEType() == eType && - (EType.isNewer(eType) || tmp.getParams() == null)) { + (EType.isNewer(eType) || !tmp.hasParams())) { // we don't support non-null s2kparams for old etypes return new SaltAndParams(tmp.getSalt(), tmp.getParams()); } diff -Nru openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java --- openjdk-25-25.0.4.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -293,7 +293,7 @@ } } - public static boolean isSupported(int eTypeConst, int[] config) { + public static boolean isOneOf(int eTypeConst, int[] config) { for (int i = 0; i < config.length; i++) { if (eTypeConst == config[i]) { return true; @@ -303,7 +303,7 @@ } public static boolean isSupported(int eTypeConst) { - return isSupported(eTypeConst, supportedETypes); + return isOneOf(eTypeConst, supportedETypes); } /** diff -Nru openjdk-25-25.0.4.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java --- openjdk-25-25.0.4.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -999,7 +999,7 @@ } /* First, compare MAC's before updating any of our state */ - if (!Arrays.equals(mac, expectedMac)) { + if (!MessageDigest.isEqual(mac, expectedMac)) { // Discard message and do not increment sequence number logger.log(Level.INFO, "DIGEST23:Unmatched MACs"); return EMPTY_BYTE_ARRAY; @@ -1449,7 +1449,7 @@ } // First, compare MACs before updating state - if (!Arrays.equals(mac, expectedMac)) { + if (!MessageDigest.isEqual(mac, expectedMac)) { // Discard message and do not increment sequence number logger.log(Level.INFO, "DIGEST41:Unmatched MACs"); return EMPTY_BYTE_ARRAY; diff -Nru openjdk-25-25.0.4.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java --- openjdk-25-25.0.4.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package com.sun.security.sasl.digest; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -32,7 +33,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Arrays; import java.util.logging.Level; import static java.nio.charset.StandardCharsets.UTF_8; @@ -657,7 +657,7 @@ byte[] expected = generateResponseValue("", digestUri, negotiatedQop, username, negotiatedRealm, passwd, nonce, cnonce, nonceCount, authzidBytes); - if (!Arrays.equals(expected, fromServer)) { + if (!MessageDigest.isEqual(expected, fromServer)) { /* Server's rspauth value does not match */ throw new SaslException( "Server's rspauth value does not match what client expects"); diff -Nru openjdk-25-25.0.4.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java --- openjdk-25-25.0.4.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -27,6 +27,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.StringTokenizer; import java.util.ArrayList; @@ -619,7 +620,7 @@ "DIGEST-MD5: problem duplicating client response", e); } - if (!Arrays.equals(responseFromClient, expectedResponse)) { + if (!MessageDigest.isEqual(responseFromClient, expectedResponse)) { throw new SaslException("DIGEST-MD5: digest response format " + "violation. Mismatched response."); } diff -Nru openjdk-25-25.0.4.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java --- openjdk-25-25.0.4.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, 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 @@ -27,6 +27,8 @@ import com.sun.security.ntlm.Client; import com.sun.security.ntlm.NTLMException; +import sun.security.jca.JCAUtil; + import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; @@ -69,8 +71,9 @@ * * com.sun.security.sasl.ntlm.random * java.util.Random, the nonce source to be used in NTLM v2 or NTLM v1 with - * Client Challenge. Default null, an internal java.util.Random object - * will be used + * Client Challenge. Users are encouraged to provide a + * java.security.SecureRandom object. If not provided, then an internal + * SecureRandom object is used. * * Negotiated Properties: * @@ -127,7 +130,7 @@ rtmp = (Random)props.get(NTLM_RANDOM); hostname = (String)props.get(NTLM_HOSTNAME); } - this.random = rtmp != null ? rtmp : new Random(); + this.random = rtmp != null ? rtmp : JCAUtil.getDefSecureRandom(); if (version == null) { version = System.getProperty("ntlm.version"); diff -Nru openjdk-25-25.0.4.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java --- openjdk-25-25.0.4.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, 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 @@ -27,6 +27,8 @@ import com.sun.security.ntlm.NTLMException; import com.sun.security.ntlm.Server; +import sun.security.jca.JCAUtil; + import java.io.IOException; import java.util.Map; import java.util.Random; @@ -67,8 +69,9 @@ * String, the domain of the server, default is server name (fqdn parameter) * * com.sun.security.sasl.ntlm.random - * java.util.Random, the nonce source. Default null, an internal - * java.util.Random object will be used + * java.util.Random, the nonce source. Users are encouraged to provide + * a java.security.SecureRandom object. If not provided, then an internal + * SecureRandom object is used. * * Negotiated Properties: * @@ -123,7 +126,7 @@ version = (String)props.get(NTLM_VERSION); rtmp = (Random)props.get(NTLM_RANDOM); } - random = rtmp != null ? rtmp : new Random(); + random = rtmp != null ? rtmp : JCAUtil.getDefSecureRandom(); if (version == null) { version = System.getProperty("ntlm.version"); diff -Nru openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/RowSetResourceBundle.properties openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/RowSetResourceBundle.properties --- openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/RowSetResourceBundle.properties 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/RowSetResourceBundle.properties 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -137,9 +137,7 @@ syncrsimpl.valtores = Value to be resolved can either be in the database or in cachedrowset #WebRowSetXmlReader exception -wrsxmlreader.invalidcp = End of RowSet reached. Invalid cursor position wrsxmlreader.readxml = readXML : {0} -wrsxmlreader.parseerr = ** Parsing Error : {0} , line : {1} , uri : {2} #WebRowSetXmlWriter exceptions wrsxmlwriter.ioex = IOException : {0} diff -Nru openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java --- openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -179,27 +179,23 @@ // This will change to a XmlReader, which over-rides the default // Xml that is used when a WRS is instantiated. //WebRowSetXmlReader xmlReader = getXmlReader(); - try { - if (reader != null) { - xmlReader.readXML(this, reader); + if (reader != null) { + xmlReader.readXML(this, reader); - // Position is before the first row - // The cursor position is to be stored while serializng - // and deserializing the WebRowSet Object. - if(curPosBfrWrite == 0) { - this.beforeFirst(); - } - - // Return the position back to place prior to callin writeXml - else { - this.absolute(curPosBfrWrite); - } + // Position is before the first row + // The cursor position is to be stored while serializing + // and deserializing the WebRowSet Object. + if(curPosBfrWrite == 0) { + this.beforeFirst(); + } - } else { - throw new SQLException(resBundle.handleGetObject("webrowsetimpl.invalidrd").toString()); + // Return the position back to place prior to callin writeXml + else { + this.absolute(curPosBfrWrite); } - } catch (Exception e) { - throw new SQLException(e.getMessage()); + + } else { + throw new SQLException(resBundle.handleGetObject("webrowsetimpl.invalidrd").toString()); } } diff -Nru openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java --- openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,18 +25,23 @@ package com.sun.rowset.internal; +import java.net.URL; import java.sql.*; import javax.sql.*; import java.io.*; import org.xml.sax.*; import org.xml.sax.helpers.*; + +import javax.xml.XMLConstants; import javax.xml.parsers.*; import com.sun.rowset.*; import java.text.MessageFormat; import javax.sql.rowset.*; import javax.sql.rowset.spi.*; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; /** * An implementation of the XmlReader interface, which @@ -45,6 +50,13 @@ * as its parser. */ public class WebRowSetXmlReader implements XmlReader, Serializable { + // standard schema + static final String WEBROWSET_XSD = "webrowset.xsd"; + private static final String VALIDATION_PROPERTY = "jdk.sql.rowset.webrowsetValidation"; + + // Error messages + private static final String STD_SCHEMA_MESSAGE = + "readXML : Cannot locate standard WebRowSet schema: %s.".formatted(WEBROWSET_XSD); private JdbcRowSetResourceBundle resBundle; @@ -81,56 +93,7 @@ * @see XmlReaderContentHandler */ public void readXML(WebRowSet caller, java.io.Reader reader) throws SQLException { - try { - // Crimson Parser(as in J2SE 1.4.1 is NOT able to handle - // Reader(s)(FileReader). - // - // But getting the file as a Stream works fine. So we are going to take - // the reader but send it as a InputStream to the parser. Note that this - // functionality needs to work against any parser - // Crimson(J2SE 1.4.x) / Xerces(J2SE 1.5.x). - InputSource is = new InputSource(reader); - DefaultHandler dh = new XmlErrorHandler(); - XmlReaderContentHandler hndr = new XmlReaderContentHandler((RowSet)caller); - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(true); - SAXParser parser = factory.newSAXParser() ; - - parser.setProperty( - "http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); - - XMLReader reader1 = parser.getXMLReader() ; - reader1.setEntityResolver(new XmlResolver()); - reader1.setContentHandler(hndr); - - reader1.setErrorHandler(dh); - - reader1.parse(is); - - } catch (SAXParseException err) { - System.out.println (MessageFormat.format(resBundle.handleGetObject("wrsxmlreader.parseerr").toString(), new Object[]{ err.getMessage (), err.getLineNumber(), err.getSystemId()})); - err.printStackTrace(); - throw new SQLException(err.getMessage()); - - } catch (SAXException e) { - Exception x = e; - if (e.getException () != null) - x = e.getException(); - x.printStackTrace (); - throw new SQLException(x.getMessage()); - - } - - // Will be here if trying to write beyond the RowSet limits - - catch (ArrayIndexOutOfBoundsException aie) { - throw new SQLException(resBundle.handleGetObject("wrsxmlreader.invalidcp").toString()); - } - catch (Throwable e) { - throw new SQLException(MessageFormat.format(resBundle.handleGetObject("wrsxmlreader.readxml").toString() , e.getMessage())); - } - + readXml(caller, new InputSource(reader)); } @@ -160,52 +123,75 @@ * @see XmlReaderContentHandler */ public void readXML(WebRowSet caller, java.io.InputStream iStream) throws SQLException { - try { - InputSource is = new InputSource(iStream); - DefaultHandler dh = new XmlErrorHandler(); + readXml(caller, new InputSource(iStream)); + } - XmlReaderContentHandler hndr = new XmlReaderContentHandler((RowSet)caller); - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(true); - - SAXParser parser = factory.newSAXParser() ; - - parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", - "http://www.w3.org/2001/XMLSchema"); - - XMLReader reader1 = parser.getXMLReader() ; - reader1.setEntityResolver(new XmlResolver()); - reader1.setContentHandler(hndr); - - reader1.setErrorHandler(dh); - - reader1.parse(is); - - } catch (SAXParseException err) { - System.out.println (MessageFormat.format(resBundle.handleGetObject("wrsxmlreader.parseerr").toString(), new Object[]{err.getLineNumber(), err.getSystemId() })); - System.out.println(" " + err.getMessage ()); - err.printStackTrace(); - throw new SQLException(err.getMessage()); - - } catch (SAXException e) { - Exception x = e; - if (e.getException () != null) - x = e.getException(); - x.printStackTrace (); - throw new SQLException(x.getMessage()); + /** + * Parses the supplied XML input into the given {@code WebRowSet}. + * + * The parser validates the XML against the standard WebRowSet schema by default. + * Validation can be disabled by setting {@systemProperty jdk.sql.rowset.webrowsetValidation} + * to {@code false} so that the parser can read legacy WebRowSet XML. + * + * @param caller the rowset to populate + * @param is the SAX input source to parse + * @throws SQLException if parsing or rowset population fails + */ + private void readXml(WebRowSet caller, InputSource is) throws SQLException { + try { + boolean validating = validationEnabled(); + SAXParserFactory spf = SAXParserFactory.newDefaultNSInstance(); + spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + if (validating) { + spf.setSchema(getSchema()); + } + + XMLReader reader = spf.newSAXParser().getXMLReader(); + reader.setEntityResolver(new XmlResolver()); + reader.setContentHandler(new XmlReaderContentHandler(caller, validating)); + reader.setErrorHandler(new XmlErrorHandler()); + reader.parse(is); + } catch (SAXException | ParserConfigurationException | IOException err) { + throw new SQLException(MessageFormat.format(resBundle.handleGetObject("wrsxmlreader.readxml").toString(), + err.getMessage()), err); } + } - // Will be here if trying to write beyond the RowSet limits - - catch (ArrayIndexOutOfBoundsException aie) { - throw new SQLException(resBundle.handleGetObject("wrsxmlreader.invalidcp").toString()); + /** + * Returns the standard WebRowSet schema bundled in the + * {@code java.sql.rowset} module. + * + * A new schema is created for each call so parser instances do not share + * validator implementation state. This can be revisited once the bundled + * schema implementation is safe to share. + * + * @return the WebRowSet schema + * @throws SAXException if the schema cannot be located or parsed + */ + private Schema getSchema() throws SAXException { + URL stdSchema = WebRowSet.class.getResource(WEBROWSET_XSD); + if (stdSchema == null) { + throw new SAXException(STD_SCHEMA_MESSAGE); } - catch (Throwable e) { - throw new SQLException(MessageFormat.format(resBundle.handleGetObject("wrsxmlreader.readxml").toString() , e.getMessage())); - } + SchemaFactory sf = SchemaFactory.newDefaultInstance(); + sf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + return sf.newSchema(stdSchema); + } + + /** + * Returns whether WebRowSet XML validation is enabled. + * + * Validation is enabled by default. It is disabled only when the + * {@systemProperty jdk.sql.rowset.webrowsetValidation} is set to + * {@code false}, case-insensitive. + * + * @return {@code true} if XML should be schema-validated + */ + private static boolean validationEnabled() { + return !"false".equalsIgnoreCase( + System.getProperty(VALIDATION_PROPERTY, "true").trim()); } /** diff -Nru openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java --- openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -148,6 +148,7 @@ writeData(caller); endHeader(); + writer.flush(); } catch (java.io.IOException ex) { throw new SQLException(MessageFormat.format(resBundle.handleGetObject("wrsxmlwriter.ioex").toString(), ex.getMessage())); @@ -321,12 +322,19 @@ caller.beforeFirst(); caller.setShowDeleted(true); while (caller.next()) { - if (caller.rowDeleted() && caller.rowInserted()) { + boolean rowDeleted = caller.rowDeleted(); + boolean rowInserted = caller.rowInserted(); + boolean rowUpdated = caller.rowUpdated(); + boolean writeUpdateValues = rowDeleted || rowUpdated; + + if (rowDeleted && rowInserted) { beginSection("modifyRow"); - } else if (caller.rowDeleted()) { + } else if (rowDeleted) { beginSection("deleteRow"); - } else if (caller.rowInserted()) { + } else if (rowInserted) { beginSection("insertRow"); + } else if (rowUpdated) { + beginSection("modifyRow"); } else { beginSection("currentRow"); } @@ -338,13 +346,17 @@ beginTag("columnValue"); writeValue(i, (RowSet)rs); endTag("columnValue"); - beginTag("updateRow"); + beginTag("updateValue"); writeValue(i, caller); - endTag("updateRow"); + endTag("updateValue"); } else { beginTag("columnValue"); writeValue(i, caller); endTag("columnValue"); + if (writeUpdateValues) { + beginTag("updateValue"); + endTag("updateValue"); + } } } @@ -482,7 +494,6 @@ } else { ; } - writer.flush(); } private void endSection() throws java.io.IOException { @@ -492,7 +503,6 @@ String beginTag = getTag(); writer.write("\n"); - writer.flush(); } private void beginTag(String tag) throws java.io.IOException { @@ -513,7 +523,6 @@ } else { ; } - writer.flush(); } private void emptyTag(String tag) throws java.io.IOException { @@ -550,8 +559,6 @@ private void writeString(String s) throws java.io.IOException { if (s != null) { writer.write(s); - } else { - writeNull(); } } @@ -595,9 +602,14 @@ } private void propString(String tag, String s) throws java.io.IOException { - beginTag(tag); - writeString(s); - endTag(tag); + if (s == null) { + writeIndent(stack.size()); + writer.write("<" + tag + "/>\n"); + } else { + beginTag(tag); + writeString(s); + endTag(tag); + } } private void propInteger(String tag, int i) throws java.io.IOException { diff -Nru openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlErrorHandler.java openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlErrorHandler.java --- openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlErrorHandler.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlErrorHandler.java 2026-10-19 12:10:20.000000000 +0000 @@ -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. * 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,10 @@ package com.sun.rowset.internal; -import org.xml.sax.*; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; -import com.sun.rowset.*; -import javax.sql.rowset.*; - /** * An implementation of the DefaultHandler interface, which @@ -38,22 +36,16 @@ * This is the ErrorHandler which helps WebRowSetXmlReader * to handle any errors while reading the xml data. */ - - public class XmlErrorHandler extends DefaultHandler { - public int errorCounter = 0; - - public void error(SAXParseException e) throws SAXException { - errorCounter++; - - } - - public void fatalError(SAXParseException e) throws SAXException { - errorCounter++; - - } - - public void warning(SAXParseException exception) throws SAXException { - - } + @Override + public void error(SAXParseException e) throws SAXException { + throw e; + } + + @Override + public void warning(SAXParseException e) throws SAXException { + // to ensure consistent handling of all XML parsing and validation diagnostics + // warnings are not ignored, though unlikely to happen + throw e; + } } diff -Nru openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java --- openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -84,7 +84,7 @@ private String propertyValue; private String metaDataValue; - private int tag; + private int tag = -1; private int state; private WebRowSetImpl rs; @@ -370,16 +370,25 @@ */ private static final int MetaNullTag = 19; - private String [] data = {"currentRow", "columnValue", "insertRow", "deleteRow", "insdel", "updateRow", "null" , "emptyString"}; + private String [] data = {"currentRow", "columnValue", "insertRow", "deleteRow", + "modifyRow", "updateValue", "null" , "emptyString"}; private static final int RowTag = 0; private static final int ColTag = 1; private static final int InsTag = 2; private static final int DelTag = 3; - private static final int InsDelTag = 4; + private static final int ModTag = 4; private static final int UpdTag = 5; private static final int NullTag = 6; private static final int EmptyStringTag = 7; + private static final int InsDelTag = 8; + private static final int UpdRowTag = 9; + + private static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance"; + + // Error messages + private static final String SCHEMA_LOC_MESSAGE = "readXML : Malformed xsi:schemaLocation: %s."; + private static final String SCHEMA_MESSAGE = "readXML : Non-standard schema specified for namespace %s : %s."; /** * A constant indicating the state of this XmlReaderContentHandler @@ -419,6 +428,9 @@ private JdbcRowSetResourceBundle resBundle; + private boolean sawRoot; + private final boolean validating; + /** * Constructs a new XmlReaderContentHandler object that will * assist the SAX parser in reading a WebRowSet object in the @@ -431,6 +443,20 @@ * @param r the RowSet object in XML format that will be read */ public XmlReaderContentHandler(RowSet r) { + this(r, true); + } + + /** + * Constructs a new {@code XmlReaderContentHandler} with a validation flag. + * When validation is disabled, the handler accepts legacy WebRowSet XML tags + * in addition to the standard tags. + * + * @param r the {@code RowSet} object in XML format that will be read + * @param validating the flag indicating whether schema validation is on + */ + XmlReaderContentHandler(RowSet r, boolean validating) { + this.validating = validating; + // keep the rowset we've been given rs = (WebRowSetImpl)r; @@ -481,21 +507,27 @@ items = properties.length; for (i=0;i(); items = colDef.length; for (i=0;i(); items = data.length; for (i=0;iThe XML parser is configured with the standard WebRowSet schema + * explicitly through the JAXP Validation API, so schema validation does + * not depend on xsi:schemaLocation being present in the XML instance + * document. This method therefore performs only an additional consistency + * check on the schema hint provided by the document.

    + * + * @param attributes the attributes of the root webRowSet element + * @throws SAXException if a non-standard schema location is specified + */ + private void checkSchemaLocation(Attributes attributes) throws SAXException { + String schemaLocation = attributes.getValue(XSI_NS, "schemaLocation"); + + // schemaLocation is optional when schema is supplied explicitly + if (schemaLocation == null || schemaLocation.isBlank()) { + return; + } + + String[] tokens = schemaLocation.trim().split("\\s+"); + if (tokens.length % 2 != 0) { + throw new SAXException(SCHEMA_LOC_MESSAGE.formatted(schemaLocation)); + } + + for (int i = 0; i < tokens.length; i += 2) { + String ns = tokens[i]; + String xsd = tokens[i + 1]; + + if (!isWebRowSetSchema(xsd)) { + throw new SAXException(SCHEMA_MESSAGE.formatted(ns, xsd)); + } + } + } + + private static boolean isWebRowSetSchema(String xsd) { + return xsd.equals(WebRowSetXmlReader.WEBROWSET_XSD) + || xsd.endsWith("/" + WebRowSetXmlReader.WEBROWSET_XSD); + } + + /** * Sets the value for the given element if name is one of * the array elements in the fields properties, * colDef, or data and this @@ -742,6 +821,8 @@ } break; case RowTag: + case ModTag: + case InsDelTag: try { rs.insertRow(); rs.moveToCurrentRow(); @@ -751,6 +832,8 @@ // rowInserted flagging rs.setOriginalRow(); + // Legacy currentRow elements can carry update tags when + // schema validation is disabled. applyUpdates(); } catch (SQLException ex) { throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errconstr").toString(), ex.getMessage())); @@ -762,6 +845,8 @@ rs.moveToCurrentRow(); rs.next(); rs.setOriginalRow(); + // Legacy deleteRow elements may omit update tags when + // schema validation is disabled. applyUpdates(); rs.deleteRow(); } catch (SQLException ex) { @@ -779,33 +864,20 @@ } break; - case InsDelTag: - try { - rs.insertRow(); - rs.moveToCurrentRow(); - rs.next(); - rs.setOriginalRow(); - applyUpdates(); - } catch (SQLException ex) { - throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errinsdel").toString() , ex.getMessage())); - } - break; - case UpdTag: - try { - if(getNullValue()) - { - insertValue(null); - setNullValue(false); - } else if(getEmptyStringValue()) { - insertValue(""); - setEmptyStringValue(false); - } else { - updates.add(upd); - } - } catch(SQLException ex) { - throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errupdate").toString() , ex.getMessage())); - } + case UpdRowTag: + // Empty updateValue/updateRow placeholders are ignored when + // they carry no value. + if(getNullValue()) + { + addUpdate(null); + setNullValue(false); + } else if(getEmptyStringValue()) { + addUpdate(""); + setEmptyStringValue(false); + } else if(!tempUpdate.isEmpty()) { + addUpdate(tempUpdate); + } break; default: @@ -825,10 +897,7 @@ while (i.hasNext()) { upd = (Object [])i.next(); idx = ((Integer)upd[0]).intValue(); - - if(!(lastval.equals(upd[1]))){ - insertValue((String)(upd[1])); - } + insertValue((String)(upd[1])); } rs.updateRow(); @@ -842,6 +911,19 @@ } /** + * Queues an update value for the current column to be applied when the + * row element is complete. + * + * @param value the update value, can be {@code null} + */ + private void addUpdate(String value) { + upd = new Object[2]; + upd[0] = Integer.valueOf(idx); + upd[1] = value; + updates.add(upd); + } + + /** * Sets a property, metadata, or data value with the characters in * the given array of characters, starting with the array element * indicated by start and continuing for length @@ -861,6 +943,13 @@ try { switch (getState()) { case PROPERTIES: + + // If tag is -1, startElement has not registered a valid tag + // Thus, we are in whitespace between elements, and should exit + if (tag == -1) { + break; + } + propertyValue = new String(ch, start, length); /** @@ -1027,10 +1116,12 @@ private void setPropertyValue(String s) throws SQLException { // find out if we are going to be dealing with a null boolean nullValue = getNullValue(); + // Empty nullable properties preserve the legacy behavior while + // remaining schema-valid. switch(getTag()) { case CommandTag: - if (nullValue) + if (nullValue || s == null || s.isEmpty()) ; //rs.setCommand(null); else rs.setCommand(s); @@ -1042,7 +1133,7 @@ rs.setConcurrency(getIntegerValue(s)); break; case DatasourceTag: - if (nullValue) + if (nullValue || s == null || s.isEmpty()) rs.setDataSourceName(null); else rs.setDataSourceName(s); @@ -1129,14 +1220,14 @@ rs.setShowDeleted(getBooleanValue(s)); break; case TableNameTag: - if (nullValue) + if (nullValue || s == null || s.isEmpty()) //rs.setTableName(null); ; else rs.setTableName(s); break; case UrlTag: - if (nullValue) + if (nullValue || s == null || s.isEmpty()) rs.setUrl(null); else rs.setUrl(s); @@ -1305,8 +1396,7 @@ tempStr = tempStr.concat(columnValue); break; case UpdTag: - upd = new Object[2]; - + case UpdRowTag: /** * This has been added for handling of special characters. When special * characters are encountered the characters function gets called for @@ -1316,12 +1406,6 @@ **/ tempUpdate = tempUpdate.concat(new String(ch,start,len)); - upd[0] = Integer.valueOf(idx); - upd[1] = tempUpdate; - //updates.add(upd); - - lastval = (String)upd[1]; - //insertValue(ch, start, len); break; case InsTag: @@ -1330,7 +1414,7 @@ private void insertValue(String s) throws SQLException { - if (getNullValue()) { + if (s == null || getNullValue()) { rs.updateNull(idx); return; } diff -Nru openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlResolver.java openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlResolver.java --- openjdk-25-25.0.4.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlResolver.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlResolver.java 2026-10-19 12:10:20.000000000 +0000 @@ -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. * 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,27 +30,35 @@ import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; +import javax.sql.rowset.WebRowSet; +import java.io.IOException; +import java.io.StringReader; + /** * An implementation of the EntityResolver interface, which * reads and parses an XML formatted WebRowSet object. * This is an implementation of org.xml.sax - * */ public class XmlResolver implements EntityResolver { - - public InputSource resolveEntity(String publicId, String systemId) { - String schemaName = systemId.substring(systemId.lastIndexOf('/')); - - if(systemId.startsWith("http://java.sun.com/xml/ns/jdbc")) { - return new InputSource(this.getClass().getResourceAsStream(schemaName)); - - } else { - // use the default behaviour - return null; - } - - - - - } + //The standard WebRowSet XML Schema as defined in WebRowSet + public static final String STD_SCHEMA_ID = "http://xmlns.jcp.org/xml/ns//jdbc/webrowset.xsd"; + // Error messages + private static final String ENTITY_MESSAGE = + "readXML : external entity %s other than the standard schema is not allowed."; + + + @Override + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { + + // accepts the standard schema without resolving it + // the schema is explicitly provided via the validation API + if (WebRowSet.SCHEMA_SYSTEM_ID.equals(systemId) || + STD_SCHEMA_ID.equals(systemId)) { + return new InputSource(new StringReader("")); + } + + // reports error upon any external entity other than the standard schema + throw new SAXException(ENTITY_MESSAGE.formatted(systemId)); + } } diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -1037,6 +1037,11 @@ "smaller templates." }, + {ErrorMsg.DESERIALIZE_TRANSLET_ERR, + "Support for deserializing TemplatesImpl is disabled. This can be " + + "overridden by setting the ''jdk.xml.enableTemplatesImplDeserialization'' " + + "property to ''true''."}, + {ErrorMsg.XPATH_GROUP_LIMIT, "JAXP0801001: the compiler encountered an XPath expression containing " + "''{0}'' groups that exceeds the ''{1}'' limit set by ''{2}''."}, diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -174,6 +174,7 @@ public static final String XPATH_GROUP_LIMIT = "XPATH_GROUP_LIMIT"; public static final String XPATH_OPERATOR_LIMIT = "XPATH_OPERATOR_LIMIT"; public static final String XPATH_TOTAL_OPERATOR_LIMIT = "XPATH_TOTAL_OPERATOR_LIMIT"; + public static final String DESERIALIZE_TRANSLET_ERR = "DESERIALIZE_TEMPLATES_ERR"; // All error messages are localized and are stored in resource bundles. // This array and the following 4 strings are read from that bundle. diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -58,6 +58,7 @@ import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.URIResolver; import jdk.xml.internal.JdkConstants; +import jdk.xml.internal.JdkXmlFeatures; /** @@ -258,6 +259,14 @@ private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { + TransformerFactoryImpl tfactory = new TransformerFactoryImpl(); + + if (!tfactory.getFeature( + JdkXmlFeatures.XmlFeature.ENABLE_TEMPLATESIMPL_DESERIALIZATION.apiProperty())) { + ErrorMsg err = new ErrorMsg(ErrorMsg.DESERIALIZE_TRANSLET_ERR); + throw new UnsupportedOperationException(err.toString()); + } + // We have to read serialized fields first. ObjectInputStream.GetField gf = is.readFields(); _name = (String)gf.get("_name", null); @@ -272,7 +281,7 @@ _uriResolver = (URIResolver) is.readObject(); } - _tfactory = new TransformerFactoryImpl(); + _tfactory = tfactory; } diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/SchemaNamespaceSupport.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/SchemaNamespaceSupport.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/SchemaNamespaceSupport.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/SchemaNamespaceSupport.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -32,6 +31,7 @@ * * @author Neil Graham, IBM * + * @LastModified: June 2026 */ public class SchemaNamespaceSupport extends NamespaceSupport { @@ -50,6 +50,7 @@ if (fContext.length <= fCurrentContext) fContext = new int[fCurrentContext+1]; System.arraycopy(nSupport.fContext, 0, fContext, 0, fCurrentContext+1); + rebuildNamespaceTable(); } // end constructor /** @@ -76,6 +77,7 @@ System.arraycopy(namespaceDecls, 0, fNamespace, fNamespaceSize, namespaceDecls.length); fNamespaceSize = newSize; + rebuildNamespaceTable(); } // setEffectiveContext(String):void /** @@ -108,6 +110,7 @@ if (fCurrentContext >= 3) { fCurrentContext = 3; fNamespaceSize = fContext[3]; + rebuildNamespaceTable(); } } // makeGlobal } // class NamespaceSupport diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java 2026-10-19 12:10:20.000000000 +0000 @@ -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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -23,6 +23,7 @@ import com.sun.org.apache.xerces.internal.xni.NamespaceContext; import java.util.ArrayList; import java.util.Enumeration; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; @@ -35,11 +36,18 @@ * * @author Andy Clark, IBM * - * @LastModified: Oct 2017 + * @LastModified: June 2026 */ public class NamespaceSupport implements NamespaceContext { // + // Constants + // + + /** No previous active namespace declaration exists for the prefix. */ + protected static final int NO_PREVIOUS_DECLARATION = -1; + + // // Data // @@ -57,6 +65,17 @@ /** The top of the namespace information array. */ protected int fNamespaceSize; + /** + * Previous active declaration for the prefix at the same tuple index in + * {@link #fNamespace}, or {@link #NO_PREVIOUS_DECLARATION} if none exists. + * This allows {@link #popContext()} to restore {@link #fNamespaceTable} + * to the previous active binding without searching ancestor contexts. + */ + protected int[] fNamespacePrev = new int[16]; + + /** Active namespace declaration indexes, keyed by prefix identity. */ + protected IdentityHashMap fNamespaceTable = new IdentityHashMap<>(); + // NOTE: The constructor depends on the initial context size // being at least 1. -Ac @@ -111,14 +130,19 @@ // reset namespace and context info fNamespaceSize = 0; fCurrentContext = 0; + fNamespaceTable.clear(); // bind "xml" prefix to the XML uri + fNamespacePrev[0] = NO_PREVIOUS_DECLARATION; fNamespace[fNamespaceSize++] = XMLSymbols.PREFIX_XML; fNamespace[fNamespaceSize++] = NamespaceContext.XML_URI; + fNamespaceTable.put(XMLSymbols.PREFIX_XML, 0); // bind "xmlns" prefix to the XMLNS uri + fNamespacePrev[1] = NO_PREVIOUS_DECLARATION; fNamespace[fNamespaceSize++] = XMLSymbols.PREFIX_XMLNS; fNamespace[fNamespaceSize++] = NamespaceContext.XMLNS_URI; + fNamespaceTable.put(XMLSymbols.PREFIX_XMLNS, 2); fContext[fCurrentContext] = fNamespaceSize; //++fCurrentContext; @@ -148,8 +172,19 @@ * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#popContext() */ public void popContext() { - fNamespaceSize = fContext[fCurrentContext--]; - //System.out.println("Calling popContext, fCurrentContext = " + fCurrentContext); + final int context = fContext[fCurrentContext]; + for (int prefixIndex = fNamespaceSize - 2; prefixIndex >= context; prefixIndex -= 2) { + final String prefix = fNamespace[prefixIndex]; + final int prev = fNamespacePrev[prefixIndex >> 1]; + if (prev == NO_PREVIOUS_DECLARATION) { + fNamespaceTable.remove(prefix); + } + else { + fNamespaceTable.put(prefix, prev); + } + } + fNamespaceSize = context; + fCurrentContext--; } // popContext() /** @@ -161,18 +196,14 @@ return false; } + final int activeIndex = fNamespaceTable.getOrDefault(prefix, NO_PREVIOUS_DECLARATION); + // see if prefix already exists in current context - for (int i = fNamespaceSize; i > fContext[fCurrentContext]; i -= 2) { - if (fNamespace[i - 2] == prefix) { - // REVISIT: [Q] Should the new binding override the - // previously declared binding or should it - // it be ignored? -Ac - // NOTE: The SAX2 "NamespaceSupport" helper allows - // re-bindings with the new binding overwriting - // the previous binding. -Ac - fNamespace[i - 1] = uri; - return true; - } + if (activeIndex >= fContext[fCurrentContext]) { + // A duplicate declaration in the current context overwrites the + // existing binding in place, preserving the active table entry. + fNamespace[activeIndex + 1] = uri; + return true; } // resize array, if needed @@ -180,9 +211,15 @@ String[] namespacearray = new String[fNamespaceSize * 2]; System.arraycopy(fNamespace, 0, namespacearray, 0, fNamespaceSize); fNamespace = namespacearray; + + int[] namespacePrev = new int[namespacearray.length >> 1]; + System.arraycopy(fNamespacePrev, 0, namespacePrev, 0, fNamespacePrev.length); + fNamespacePrev = namespacePrev; } // bind prefix to uri in current context + fNamespacePrev[fNamespaceSize >> 1] = activeIndex; + fNamespaceTable.put(prefix, fNamespaceSize); fNamespace[fNamespaceSize++] = prefix; fNamespace[fNamespaceSize++] = uri; @@ -191,19 +228,29 @@ } // declarePrefix(String,String):boolean /** + * Rebuilds the active namespace table from {@link #fNamespace}. Subclasses + * that directly replace or truncate namespace tuples must call this method. + */ + protected void rebuildNamespaceTable() { + if (fNamespacePrev.length < (fNamespace.length >> 1)) { + fNamespacePrev = new int[fNamespace.length >> 1]; + } + fNamespaceTable.clear(); + for (int i = 0; i < fNamespaceSize; i += 2) { + final String prefix = fNamespace[i]; + fNamespacePrev[i >> 1] = fNamespaceTable.getOrDefault(prefix, NO_PREVIOUS_DECLARATION); + fNamespaceTable.put(prefix, i); + } + } + + /** * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#getURI(String) */ public String getURI(String prefix) { // find prefix in current context - for (int i = fNamespaceSize; i > 0; i -= 2) { - if (fNamespace[i - 2] == prefix) { - return fNamespace[i - 1]; - } - } - - // prefix not found - return null; + final int active = fNamespaceTable.getOrDefault(prefix, NO_PREVIOUS_DECLARATION); + return active != NO_PREVIOUS_DECLARATION ? fNamespace[active + 1] : null; } // getURI(String):String @@ -241,71 +288,46 @@ } // getDeclaredPrefixAt(int):String public Iterator getPrefixes(){ - int count = 0; - if (fPrefixes.length < (fNamespace.length/2)) { - // resize prefix array - String[] prefixes = new String[fNamespaceSize]; - fPrefixes = prefixes; - } - String prefix = null; - boolean unique = true; - for (int i = 2; i < (fNamespaceSize-2); i += 2) { - prefix = fNamespace[i + 2]; - for (int k=0;k getAllPrefixes() { - int count = 0; - if (fPrefixes.length < (fNamespace.length/2)) { - // resize prefix array - String[] prefixes = new String[fNamespaceSize]; - fPrefixes = prefixes; - } - String prefix = null; - boolean unique = true; - for (int i = 2; i < (fNamespaceSize-2); i += 2) { - prefix = fNamespace[i + 2]; - for (int k=0;k getPrefixes(String uri){ - int count = 0; - String prefix = null; - boolean unique = true; List prefixList = new ArrayList<>(); - for (int i = fNamespaceSize; i >0 ; i -= 2) { - if(fNamespace[i-1] == uri){ - if(!prefixList.contains(fNamespace[i-2])) - prefixList.add(fNamespace[i-2]); + for (int i = fNamespaceSize; i > 0; i -= 2) { + final int prefixIndex = i - 2; + if (fNamespace[prefixIndex + 1] == uri) { + final String prefix = fNamespace[prefixIndex]; + if (fNamespaceTable.getOrDefault(prefix, NO_PREVIOUS_DECLARATION) == prefixIndex) { + prefixList.add(prefix); + } } } return prefixList; } + protected int collectPrefixes(int start, int end) { + if (fPrefixes.length < (fNamespace.length / 2)) { + // resize prefix array + fPrefixes = new String[fNamespace.length / 2]; + } + int count = 0; + for (int i = start; i < end; i += 2) { + if (fNamespacePrev[i >> 1] < start) { + fPrefixes[count++] = fNamespace[i]; + } + } + return count; + } + /* * non-NamespaceContext methods */ @@ -321,14 +343,7 @@ public boolean containsPrefix(String prefix) { // find prefix in context - for (int i = fNamespaceSize; i > 0; i -= 2) { - if (fNamespace[i - 2] == prefix) { - return true; - } - } - - // prefix not found - return false; + return fNamespaceTable.containsKey(prefix); } /** @@ -340,16 +355,8 @@ * @return true if the given prefix exists in the current context */ public boolean containsPrefixInCurrentContext(String prefix) { - // find prefix in current context - for (int i = fContext[fCurrentContext]; i < fNamespaceSize; i += 2) { - if (fNamespace[i] == prefix) { - return true; - } - } - - // prefix not found - return false; + return fNamespaceTable.getOrDefault(prefix, NO_PREVIOUS_DECLARATION) >= fContext[fCurrentContext]; } protected final class IteratorPrefixes implements Iterator { diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/MultipleScopeNamespaceSupport.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/MultipleScopeNamespaceSupport.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/MultipleScopeNamespaceSupport.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/MultipleScopeNamespaceSupport.java 2026-10-19 12:10:20.000000000 +0000 @@ -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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -37,7 +37,7 @@ * * @author Peter McCracken, IBM * - * @LastModified: Oct 2017 + * @LastModified: June 2026 */ public class MultipleScopeNamespaceSupport extends NamespaceSupport { @@ -66,29 +66,7 @@ * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#getAllPrefixes() */ public Enumeration getAllPrefixes() { - int count = 0; - if (fPrefixes.length < (fNamespace.length / 2)) { - // resize prefix array - String[] prefixes = new String[fNamespaceSize]; - fPrefixes = prefixes; - } - String prefix = null; - boolean unique = true; - for (int i = fContext[fScope[fCurrentScope]]; - i <= (fNamespaceSize - 2); - i += 2) { - prefix = fNamespace[i]; - for (int k = 0; k < count; k++) { - if (fPrefixes[k] == prefix) { - unique = false; - break; - } - } - if (unique) { - fPrefixes[count++] = prefix; - } - unique = true; - } + int count = collectPrefixes(fContext[fScope[fCurrentScope]], fNamespaceSize); return new Prefixes(fPrefixes, count); } @@ -131,10 +109,10 @@ return XMLSymbols.PREFIX_XMLNS; } - // find uri in current context + // find uri in the requested context range within the current scope for (int i = start; i > end; i -= 2) { if (fNamespace[i - 1] == uri) { - if (getURI(fNamespace[i - 2]) == uri) + if (getURI(fNamespace[i - 2], start, end) == uri) return fNamespace[i - 2]; } } @@ -152,15 +130,18 @@ return NamespaceContext.XMLNS_URI; } - // find prefix in current context - for (int i = start; i > end; i -= 2) { - if (fNamespace[i - 2] == prefix) { - return fNamespace[i - 1]; - } - } + int prefixIndex = getPrefixIndex(prefix, start, end); + return prefixIndex != NO_PREVIOUS_DECLARATION + ? fNamespace[prefixIndex + 1] : null; + } - // prefix not found - return null; + private int getPrefixIndex(String prefix, int start, int end) { + final Integer active = fNamespaceTable.get(prefix); + int prefixIndex = active != null ? active : NO_PREVIOUS_DECLARATION; + while (prefixIndex >= start) { + prefixIndex = fNamespacePrev[prefixIndex >> 1]; + } + return prefixIndex >= end ? prefixIndex : NO_PREVIOUS_DECLARATION; } /** @@ -170,6 +151,7 @@ public void reset() { fCurrentContext = fScope[fCurrentScope]; fNamespaceSize = fContext[fCurrentContext]; + rebuildNamespaceTable(); } /** diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathContext.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathContext.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathContext.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathContext.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -49,6 +49,8 @@ import javax.xml.transform.ErrorListener; import javax.xml.transform.SourceLocator; import javax.xml.transform.URIResolver; +import jdk.xml.internal.JdkXmlConfig; +import jdk.xml.internal.JdkXmlFeatures; import org.xml.sax.XMLReader; /** @@ -56,7 +58,7 @@ * *

    This class extends DTMManager but does not directly implement it.

    * @xsl.usage advanced - * @LastModified: Jan 2019 + * @LastModified: June 2026 */ public class XPathContext extends DTMManager // implements ExpressionContext { @@ -95,6 +97,11 @@ private boolean m_overrideDefaultParser; /** + * JDK XML feature settings + */ + private JdkXmlFeatures m_jdkXmlFeatures; + + /** * Though XPathContext context extends * the DTMManager, it really is a proxy for this object, which * is the real DTMManager. @@ -129,6 +136,27 @@ } /** + * Sets the JDK XML feature settings for this XPath evaluation. + */ + public void setJdkXmlFeatures(JdkXmlFeatures features) + { + m_jdkXmlFeatures = features; + } + + /** + * {@return the JDK XML feature settings for this XPath evaluation} + * + * The settings are initialized from the global configuration if needed. + */ + public JdkXmlFeatures getJdkXmlFeatures() + { + if (m_jdkXmlFeatures == null) { + m_jdkXmlFeatures = JdkXmlConfig.getInstance(false).getXMLFeatures(true); + } + return m_jdkXmlFeatures; + } + + /** * Get an instance of a DTM, loaded with the content from the * specified source. If the unique flag is true, a new instance will * always be returned. Otherwise it is up to the DTMManager to return a diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java 2026-10-19 12:10:20.000000000 +0000 @@ -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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -20,19 +20,22 @@ package com.sun.org.apache.xpath.internal.functions; +import com.sun.org.apache.xalan.internal.res.XSLMessages; import com.sun.org.apache.xpath.internal.XPathContext; import com.sun.org.apache.xpath.internal.objects.XObject; import com.sun.org.apache.xpath.internal.objects.XString; import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; -import java.io.BufferedInputStream; import java.io.InputStream; import java.util.Properties; +import javax.xml.transform.TransformerException; +import jdk.xml.internal.JdkConstants; +import jdk.xml.internal.JdkXmlFeatures; import jdk.xml.internal.SecuritySupport; /** * Execute the SystemProperty() function. * @xsl.usage advanced - * @LastModified: Nov 2024 + * @LastModified: June 2026 */ public class FuncSystemProperty extends FunctionOneArg { @@ -96,6 +99,7 @@ new Object[]{ namespace, fullName }); //"Don't currently do anything with namespace "+namespace+" in property: "+fullName); + checkSysPropAccess(xctxt, fullName); result = System.getProperty(propName); if (null == result) { @@ -106,6 +110,7 @@ } else { + checkSysPropAccess(xctxt, fullName); result = System.getProperty(fullName); if (null == result) @@ -132,6 +137,22 @@ } /** + * Checks whether XPath may access non-XSLT-defined system properties. + */ + private void checkSysPropAccess(XPathContext xctxt, String name) + throws TransformerException + { + JdkXmlFeatures features = xctxt.getJdkXmlFeatures(); + + if (!features.getFeature(JdkXmlFeatures.XmlFeature.JDK_XPATH_SYSTEM_PROPERTY)) { + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_NON_XSLT_SYSTEM_PROPERTY, + new Object[] {name, JdkConstants.XPATH_ALLOW_NON_XSLT_SYS_PROPS}); + throw new TransformerException(fmsg); + } + } + + /** * Retrieve a property bundle from XSLT_PROPERTIES * * @param target The target property bag the file will be placed into. diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java 2026-10-19 12:10:20.000000000 +0000 @@ -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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -35,7 +35,7 @@ * * @author Ramesh Mandava * - * @LastModified: June 2025 + * @LastModified: June 2026 */ public class XPathFactoryImpl extends XPathFactory { @@ -185,6 +185,8 @@ if (value && _featureManager != null) { _featureManager.setFeature(JdkXmlFeatures.XmlFeature.ENABLE_EXTENSION_FUNCTION, JdkProperty.State.FSP, false); + _featureManager.setFeature(JdkXmlFeatures.XmlFeature.JDK_XPATH_SYSTEM_PROPERTY, + JdkProperty.State.FSP, false); _xmlSecMgr.setSecureProcessing(value); } diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -56,7 +56,7 @@ * This class contains several utility methods used by XPathImpl and * XPathExpressionImpl * - * @LastModified: June 2025 + * @LastModified: June 2026 */ class XPathImplUtil { XPathFunctionResolver functionResolver; @@ -94,6 +94,7 @@ xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); } + xpathSupport.setJdkXmlFeatures(featureManager); xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); XObject xobj; diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java 2026-10-19 12:10:20.000000000 +0000 @@ -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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -31,7 +31,7 @@ * Also you need to update the count of messages(MAX_CODE)or * the count of warnings(MAX_WARNING) [ Information purpose only] * @xsl.usage advanced - * @LastModified: Apr 2025 + * @LastModified: June 2026 */ public class XPATHErrorResources extends ListResourceBundle { @@ -327,6 +327,7 @@ public static final String ER_GETTING_UNKNOWN_PROPERTY = "ER_GETTING_UNKNOWN_PROPERTY"; public static final String ER_XPATH_GROUP_LIMIT = "ER_XPATH_GROUP_LIMIT"; public static final String ER_XPATH_OPERATOR_LIMIT = "ER_XPATH_OPERATOR_LIMIT"; + public static final String ER_NON_XSLT_SYSTEM_PROPERTY = "ER_NON_XSLT_SYSTEM_PROPERTY"; //END: Keys needed for exception messages of JAXP 1.3 XPath API implementation @@ -862,6 +863,10 @@ "JAXP0801002: the compiler encountered an XPath expression containing " + "''{0}'' operators that exceeds the ''{1}'' limit set by ''{2}''."}, + { ER_NON_XSLT_SYSTEM_PROPERTY, + "Access to non-XSLT system property ''{0}'' is not allowed. Set " + + "''{1}'' to ''true'' to allow it."}, + //END: Definitions of error keys used in exception messages of JAXP 1.3 XPath API implementation // Warnings... diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java openjdk-25-25.0.5+8/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,6 +221,13 @@ public static final String XPATH_TOTALOP_LIMIT = "jdk.xml.xpathTotalOpLimit"; /** + * jdk.xml.allowNonXSLTSysProps: controls whether XPath's system-property() + * function is permitted to access non-XSLT-defined JVM system properties. + */ + public static final String XPATH_ALLOW_NON_XSLT_SYS_PROPS = + "jdk.xml.allowNonXSLTSysProps"; + + /** * JDK TransformerFactory and Transformer attribute that specifies a class * loader that will be used for extension functions class loading * Value: a "null", the default value, means that the default EF class loading @@ -417,4 +424,9 @@ public static final int CDATA_CHUNK_SIZE_DEFAULT = SecuritySupport.getJAXPSystemProperty(Integer.class, CDATA_CHUNK_SIZE, "0"); + /** + * Enable TemplatesImpl deserialization. + */ + public static final String SP_ENABLE_TEMPLATESIMPL_DESERIALIZATION = + "jdk.xml.enableTemplatesImplDeserialization"; } diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/jdk/xml/internal/JdkXmlFeatures.java openjdk-25-25.0.5+8/src/java.xml/share/classes/jdk/xml/internal/JdkXmlFeatures.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/jdk/xml/internal/JdkXmlFeatures.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/jdk/xml/internal/JdkXmlFeatures.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,10 @@ import javax.xml.XMLConstants; import jdk.xml.internal.JdkProperty.ImplPropMap; import jdk.xml.internal.JdkProperty.State; + +import static jdk.xml.internal.JdkConstants.XPATH_ALLOW_NON_XSLT_SYS_PROPS; import static jdk.xml.internal.JdkXmlUtils.SP_USE_CATALOG; +import static jdk.xml.internal.JdkConstants.SP_ENABLE_TEMPLATESIMPL_DESERIALIZATION; /** * This class manages JDK's XML Features. Previously added features and properties @@ -72,7 +75,25 @@ * FSP: not enforced by FSP. */ JDK_OVERRIDE_PARSER(ImplPropMap.OVERRIDEPARSER, null, null, false, - null, null, false, false, true, false); + null, null, false, false, true, false), + + /** + * Feature allowNonXSLTSysProps: controls whether XPath's system-property() + * function is permitted to access non-XSLT-defined JVM system properties. + * FSP: when FSP is on, accessing non-XSLT-defined JVM system properties is disabled + */ + JDK_XPATH_SYSTEM_PROPERTY(null, XPATH_ALLOW_NON_XSLT_SYS_PROPS, + XPATH_ALLOW_NON_XSLT_SYS_PROPS, false, + null, null, false, false, true, true), + + /* + * Feature TemplatesImplDeserialization + * FSP: TemplatesImpl deserialization is enforced by FSP. When FSP is on, + * TemplatesImpl deserialization is disabled. + */ + ENABLE_TEMPLATESIMPL_DESERIALIZATION(null, + SP_ENABLE_TEMPLATESIMPL_DESERIALIZATION, SP_ENABLE_TEMPLATESIMPL_DESERIALIZATION, + false, null, null, false, false, true, true); private final ImplPropMap implMap; private final String name; @@ -92,16 +113,18 @@ * parameters. * @param name the name of the feature * @param nameSP the name of the System Property + * @param differ * @param nameOld the name of the corresponding legacy property * @param nameOldSP the system property of the legacy property - * @param value the value of the feature - * @param hasSystem a flag to indicate whether the feature is supported + * @param valueDefault the default value of the feature + * @param valueEnforced the FSP-enforced value of the feature + * @param hasSystem a flag indicating whether a system property is supported for the feature * @param enforced a flag indicating whether the feature is * FSP (Feature_Secure_Processing) enforced * with a System property */ XmlFeature(ImplPropMap implMap, String name, String nameSP, boolean differ, - String nameOld, String nameOldSP, boolean value, boolean valueEnforced, + String nameOld, String nameOldSP, boolean valueDefault, boolean valueEnforced, boolean hasSystem, boolean enforced) { this.implMap = implMap; if (implMap != null) { @@ -116,7 +139,7 @@ this.nameOldSP = nameOldSP; } this.differ = differ; - this.valueDefault = value; + this.valueDefault = valueDefault; this.valueEnforced = valueEnforced; this.hasSystem = hasSystem; this.enforced = enforced; diff -Nru openjdk-25-25.0.4.1+1/src/java.xml/share/classes/module-info.java openjdk-25-25.0.5+8/src/java.xml/share/classes/module-info.java --- openjdk-25-25.0.4.1+1/src/java.xml/share/classes/module-info.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/java.xml/share/classes/module-info.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -819,7 +819,7 @@ * 9 * * - * jdk.xml.extensionClassLoader + * {@systemProperty jdk.xml.extensionClassLoader} * Sets a non-null ClassLoader instance to be used for loading XSLTC java * extension functions. * @@ -833,7 +833,7 @@ * 9 * * - * jdk.xml.xpathExprGrpLimit + * {@systemProperty jdk.xml.xpathExprGrpLimit} * Limits the number of groups an XPath expression can contain. * * yes @@ -850,14 +850,14 @@ * 19 * * - * jdk.xml.xpathExprOpLimit + * {@systemProperty jdk.xml.xpathExprOpLimit} * Limits the number of operators an XPath expression can contain. * * 100 * 100 * * - * jdk.xml.xpathTotalOpLimit + * {@systemProperty jdk.xml.xpathTotalOpLimit} * Limits the total number of XPath operators in an XSL Stylesheet. * * 10000 @@ -867,6 +867,28 @@ * * * + * {@systemProperty jdk.xml.allowNonXSLTSysProps} + * controls whether XPath's {@code system-property()} function is permitted to + * access non-XSLT-defined JVM system properties in addition to the standard XSLT-defined + * properties supported by the JDK. Attempts to access non-XSLT-defined properties will + * fail with an XPathExpressionException during XPath expression evaluation. + * + * yes + * Boolean + * + * true or false. True allows access to non-XSLT JVM system properties; False + * restricts access to only XSLT-defined properties. + * + * false + * false + * Yes + * + * XPath + * + * Method 2 + * 27 + * + * * {@systemProperty jdk.xml.enableExtensionFunctions} * Determines whether extension functions in the Transform API are to be allowed. * The extension functions in the XPath API are not affected by this property. @@ -994,6 +1016,24 @@ * Method 1 * 22 * + * + * {@systemProperty jdk.xml.enableTemplatesImplDeserialization} + * Enables or disables deserialization of the JDK's implementation of the + * {@link javax.xml.transform.Templates} interface. + * + * yes + * boolean + * true or false. True indicates that deserialization is allowed. False indicates that + * deserialization is disallowed. + * false + * false + * Yes + * + * Transform + * + * [8] + * 7 + * * * *

    @@ -1037,6 +1077,10 @@ * These three properties control whether DTDs as a whole shall be processed. When * they are set to deny or ignore, other properties that regulate a part or an * aspect of DTD shall have no effect. + *

    + * [8] This property can be set only via a system property or in the + * JAXP Configuration File. Setting this property + * on a transformer factory or on a {@code Transformer} instance has no effect. * *

    Legacy Property Names (deprecated)

    * JDK releases prior to JDK 17 support the use of URI style prefix for properties. @@ -1111,7 +1155,7 @@ * {@code http://www.oracle.com/xml/jaxp/properties/xsltcIsStandalone} * * - * {@code jdk.xml.extensionClassLoader} + * {@systemProperty jdk.xml.extensionClassLoader} * {@code jdk.xml.transform.extensionClassLoader} * * diff -Nru openjdk-25-25.0.4.1+1/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c openjdk-25-25.0.5+8/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c --- openjdk-25-25.0.4.1+1/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2015, 2024 SAP SE. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,13 +132,14 @@ memset(&sb, 0, sizeof(struct stat)); /* - * Check that the path is owned by the effective uid/gid of this - * process. Also check that group/other access is not allowed. + * Check that the path itself (not following symbolic links) is + * owned by the effective uid/gid of this process and that it is + * a socket. Also check that group/other access is not allowed. */ uid = geteuid(); gid = getegid(); - res = stat(p, &sb); + res = lstat(p, &sb); if (res != 0) { /* save errno */ res = errno; @@ -147,7 +148,11 @@ if (res == 0) { char msg[100]; jboolean isError = JNI_FALSE; - if (sb.st_uid != uid && uid != ROOT_UID) { + if (!S_ISSOCK(sb.st_mode)) { + snprintf(msg, sizeof(msg), + "file is expected to be a socket: S_ISSOCK(sb.st_mode): %d", S_ISSOCK(sb.st_mode)); + isError = JNI_TRUE; + } else if (sb.st_uid != uid && uid != ROOT_UID) { snprintf(msg, sizeof(msg), "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid); isError = JNI_TRUE; diff -Nru openjdk-25-25.0.4.1+1/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c openjdk-25-25.0.5+8/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c --- openjdk-25-25.0.4.1+1/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,13 +137,14 @@ memset(&sb, 0, sizeof(struct stat)); /* - * Check that the path is owned by the effective uid/gid of this - * process. Also check that group/other access is not allowed. + * Check that the path itself (not following symbolic links) is + * owned by the effective uid/gid of this process and that it is + * a socket. Also check that group/other access is not allowed. */ uid = geteuid(); gid = getegid(); - res = stat(p, &sb); + res = lstat(p, &sb); if (res != 0) { /* save errno */ res = errno; @@ -152,7 +153,11 @@ if (res == 0) { char msg[100]; jboolean isError = JNI_FALSE; - if (sb.st_uid != uid && uid != ROOT_UID) { + if (!S_ISSOCK(sb.st_mode)) { + snprintf(msg, sizeof(msg), + "file is expected to be a socket: S_ISSOCK(sb.st_mode): %d", S_ISSOCK(sb.st_mode)); + isError = JNI_TRUE; + } else if (sb.st_uid != uid && uid != ROOT_UID) { snprintf(msg, sizeof(msg), "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid); isError = JNI_TRUE; diff -Nru openjdk-25-25.0.4.1+1/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c openjdk-25-25.0.5+8/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c --- openjdk-25-25.0.4.1+1/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,13 +180,14 @@ memset(&sb, 0, sizeof(struct stat)); /* - * Check that the path is owned by the effective uid/gid of this - * process. Also check that group/other access is not allowed. + * Check that the path itself (not following symbolic links) is + * owned by the effective uid/gid of this process and that it is + * a socket. Also check that group/other access is not allowed. */ uid = geteuid(); gid = getegid(); - res = stat(p, &sb); + res = lstat(p, &sb); if (res != 0) { /* save errno */ res = errno; @@ -195,7 +196,11 @@ if (res == 0) { char msg[100]; jboolean isError = JNI_FALSE; - if (sb.st_uid != uid && uid != ROOT_UID) { + if (!S_ISSOCK(sb.st_mode)) { + snprintf(msg, sizeof(msg), + "file is expected to be a socket: S_ISSOCK(sb.st_mode): %d", S_ISSOCK(sb.st_mode)); + isError = JNI_TRUE; + } else if (sb.st_uid != uid && uid != ROOT_UID) { snprintf(msg, sizeof(msg), "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid); isError = JNI_TRUE; diff -Nru openjdk-25-25.0.4.1+1/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java openjdk-25-25.0.5+8/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java --- openjdk-25-25.0.4.1+1/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java 2026-10-19 12:10:20.000000000 +0000 @@ -4266,7 +4266,7 @@ } List expectedRecordTypes; - if (site.tsym.kind == Kind.TYP && ((ClassSymbol) site.tsym).isRecord()) { + if (site.tsym instanceof ClassSymbol clazz && clazz.isRecord()) { ClassSymbol record = (ClassSymbol) site.tsym; expectedRecordTypes = record.getRecordComponents() .stream() diff -Nru openjdk-25-25.0.4.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java --- openjdk-25-25.0.4.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -71,9 +71,8 @@ int setPaddingBytes(byte[] paddingBuffer, int startOff, int padLen); // DEC: return the length of trailing padding bytes given the specified - // padded data - int unpad(byte[] paddedData, int len) - throws BadPaddingException, IllegalBlockSizeException; + // padded data, returns -1 if invalid + int unpad(byte[] paddedData, int len) throws IllegalBlockSizeException; } private static class PKCS5Padding implements Padding { @@ -95,23 +94,32 @@ } public int unpad(byte[] paddedData, int len) - throws BadPaddingException, IllegalBlockSizeException { + throws IllegalBlockSizeException { if ((len < 1) || (len % blockSize != 0)) { throw new IllegalBlockSizeException ("Input length must be multiples of " + blockSize); } - byte padValue = paddedData[len - 1]; - if (padValue < 1 || padValue > blockSize) { - throw new BadPaddingException("Invalid pad value!"); - } - // sanity check padding bytes - int padStartIndex = len - padValue; - for (int i = padStartIndex; i < len; i++) { - if (paddedData[i] != padValue) { - throw new BadPaddingException("Invalid pad bytes!"); - } - } - return padValue; + + int padValue = paddedData[len - 1] & 0x0ff; + // check padValue >= 1; negative if fail + int invalid = (padValue - 1); + // check padValue <= blockSize; negative if fail + invalid |= (blockSize - padValue); + + // check the last block for the padding bytes + for (int i = len - blockSize; i < len; i++) { + // mask = 0 for the first (blockSize - padValue) bytes in the + // block. Otherwise, use 0xffff to preserve the value + int mask = (len - padValue - i - 1) >> 8 ; + int valueCheck = ((paddedData[i] & 0x0ff) ^ padValue) & mask; + // again, assign negative value if fail + invalid |= -valueCheck; + } + // convert 'invalid' to -1 when 'invalid' is not 0 + // right shifting by 8 should be sufficient since value range is + // small + invalid >>= 8; // 0 or -1 + return (invalid | padValue); } } @@ -970,6 +978,9 @@ padBuffer.length - k); int actualPadLen = paddingObj.unpad(padBuffer, k); + if (actualPadLen < 0) { + throw new BadPaddingException("Invalid pad value!"); + } k -= actualPadLen; System.arraycopy(padBuffer, 0, out, outOfs, k); } else { @@ -1084,6 +1095,9 @@ 0, padBuffer, k, padBuffer.length - k); int actualPadLen = paddingObj.unpad(padBuffer, k); + if (actualPadLen < 0) { + throw new BadPaddingException("Invalid pad value!"); + } k -= actualPadLen; outArray = padBuffer; outOfs = 0; diff -Nru openjdk-25-25.0.4.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11HKDF.java openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11HKDF.java --- openjdk-25-25.0.4.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11HKDF.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11HKDF.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (c) 2025, Red Hat, Inc. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,32 +168,45 @@ checkDerivedKeyType(ki, alg); P11KeyGenerator.checkKeySize(ki.keyGenMech, outLen * 8, token); - P11Key p11BaseKey = convertKey(baseKey, (isExtract ? "IKM" : "PRK") + - " could not be converted to a token key for HKDF derivation."); - + long baseKeyID; + P11Key p11BaseKey = null; + try { + p11BaseKey = convertKey(baseKey, (isExtract ? "IKM" : "PRK") + + " could not be converted to a token key for HKDF derivation."); + baseKeyID = p11BaseKey.getKeyID(); + } catch (ProviderException pe) { + if (p11BaseKey != null) { + throw pe; + } + // special handling for FIPS mode when key cannot be imported + if (isExtract) { + baseKeyID = convertKeyToData(baseKey, pe); + } else { + throw pe; + } + } + Session session = null; long saltType = CKF_HKDF_SALT_NULL; byte[] saltBytes = null; P11Key p11SaltKey = null; - if (salt instanceof SecretKeySpec) { - saltType = CKF_HKDF_SALT_DATA; - saltBytes = salt.getEncoded(); - } else if (salt != EMPTY_KEY) { - // consolidateKeyMaterial returns a salt from the token. - saltType = CKF_HKDF_SALT_KEY; - p11SaltKey = (P11Key.P11SecretKey) salt; - assert p11SaltKey.token == token : "salt must be from the same " + - "token as service."; - } - - long derivedKeyClass = isData ? CKO_DATA : CKO_SECRET_KEY; - CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { - new CK_ATTRIBUTE(CKA_CLASS, derivedKeyClass), - new CK_ATTRIBUTE(CKA_KEY_TYPE, ki.keyType), - new CK_ATTRIBUTE(CKA_VALUE_LEN, outLen) - }; - Session session = null; - long baseKeyID = p11BaseKey.getKeyID(); try { + if (salt instanceof SecretKeySpec) { + saltType = CKF_HKDF_SALT_DATA; + saltBytes = salt.getEncoded(); + } else if (salt != EMPTY_KEY) { + // consolidateKeyMaterial returns a salt from the token. + saltType = CKF_HKDF_SALT_KEY; + p11SaltKey = (P11Key.P11SecretKey) salt; + assert p11SaltKey.token == token : "salt must be from the same " + + "token as service."; + } + + long derivedKeyClass = isData ? CKO_DATA : CKO_SECRET_KEY; + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, derivedKeyClass), + new CK_ATTRIBUTE(CKA_KEY_TYPE, ki.keyType), + new CK_ATTRIBUTE(CKA_VALUE_LEN, outLen) + }; session = token.getOpSession(); CK_HKDF_PARAMS params = new CK_HKDF_PARAMS(isExtract, isExpand, svcKi.hmacMech, saltType, saltBytes, p11SaltKey != null ? @@ -230,11 +244,54 @@ if (p11SaltKey != null) { p11SaltKey.releaseKeyID(); } - p11BaseKey.releaseKeyID(); + if (p11BaseKey != null) { + p11BaseKey.releaseKeyID(); + } else { + destroyDataObject(baseKeyID); + } token.releaseSession(session); } } + private void destroyDataObject(long baseKeyID) { + try { + Session session = token.getObjSession(); + try { + token.p11.C_DestroyObject(session.id(), baseKeyID); + } finally { + token.releaseSession(session); + } + } catch (PKCS11Exception e) { + throw new ProviderException("Failed to destroy IKM data object.", e); + } + } + + private long convertKeyToData(SecretKey key, ProviderException pe) { + if (!"RAW".equalsIgnoreCase(key.getFormat())) { + throw pe; + } + byte[] keyBytes = key.getEncoded(); + if (keyBytes == null) { + throw pe; + } + CK_ATTRIBUTE[] inputAttributes = new CK_ATTRIBUTE[]{ + new CK_ATTRIBUTE(CKA_CLASS, CKO_DATA), + new CK_ATTRIBUTE(CKA_VALUE, keyBytes), + }; + try { + Session session = token.getObjSession(); + try { + return token.p11.C_CreateObject(session.id(), inputAttributes); + } finally { + token.releaseSession(session); + } + } catch (PKCS11Exception e) { + throw new ProviderException("Failed to create IKM data object.", e); + } finally { + Arrays.fill(keyBytes, (byte)0); + } + } + private static boolean canDeriveKeyInfoType(long t) { return (t == CKK_DES || t == CKK_DES3 || t == CKK_AES || t == CKK_RC4 || t == CKK_BLOWFISH || t == CKK_CHACHA20 || diff -Nru openjdk-25-25.0.4.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java --- openjdk-25-25.0.4.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java 2026-10-19 12:10:20.000000000 +0000 @@ -200,6 +200,7 @@ CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET), + new CK_ATTRIBUTE(CKA_VALUE_LEN, secretLen), }; attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes); @@ -213,22 +214,11 @@ token.p11.C_GetAttributeValue(session.id(), keyID, attributes); byte[] secret = attributes[0].getByteArray(); token.p11.C_DestroyObject(session.id(), keyID); - // Some vendors, e.g. NSS, trim off the leading 0x00 byte(s) from - // the generated secret. Thus, we need to check the secret length - // and trim/pad it so the returned value has the same length as - // the modulus size - if (secret.length == secretLen) { - return secret; - } else { - if (secret.length > secretLen) { - // Shouldn't happen; but check just in case - throw new ProviderException("generated secret is out-of-range"); - } - byte[] newSecret = new byte[secretLen]; - System.arraycopy(secret, 0, newSecret, secretLen - secret.length, - secret.length); - return newSecret; + if (secret.length != secretLen) { + // Shouldn't happen; but check just in case + throw new ProviderException("generated secret is out-of-range"); } + return secret; } catch (PKCS11Exception e) { throw new ProviderException("Could not derive key", e); } finally { @@ -321,10 +311,20 @@ long privKeyID = privateKey.getKeyID(); try { session = token.getObjSession(); - CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { - new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), - new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), - }; + CK_ATTRIBUTE[] attributes; + if ("TlsPremasterSecret".equalsIgnoreCase(algorithm)) { + attributes = new CK_ATTRIBUTE[]{ + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), + }; + } else { + // keep the leading zeroes + attributes = new CK_ATTRIBUTE[]{ + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), + new CK_ATTRIBUTE(CKA_VALUE_LEN, secretLen), + }; + } attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); long keyID = token.p11.C_DeriveKey(session.id(), @@ -337,19 +337,6 @@ int keyLen = (int)lenAttributes[0].getLong(); SecretKey key = P11Key.secretKey (session, keyID, algorithm, keyLen << 3, attributes); - if ("RAW".equals(key.getFormat()) - && algorithm.equalsIgnoreCase("TlsPremasterSecret")) { - // Workaround for Solaris bug 6318543. - // Strip leading zeroes ourselves if possible (key not sensitive). - // This should be removed once the Solaris fix is available - // as here we always retrieve the CKA_VALUE even for tokens - // that do not have that bug. - byte[] keyBytes = key.getEncoded(); - byte[] newBytes = KeyUtil.trimZeroes(keyBytes); - if (keyBytes != newBytes) { - key = new SecretKeySpec(newBytes, algorithm); - } - } return key; } catch (PKCS11Exception e) { throw new InvalidKeyException("Could not derive key", e); diff -Nru openjdk-25-25.0.4.1+1/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c --- openjdk-25-25.0.4.1+1/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c 2026-10-19 12:10:20.000000000 +0000 @@ -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. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -79,10 +79,6 @@ jstring jGetFunctionList) { void *hModule; - int i; - CK_ULONG ulCount = 0; - CK_C_GetInterfaceList C_GetInterfaceList = NULL; - CK_INTERFACE_PTR iList = NULL; CK_C_GetInterface C_GetInterface = NULL; CK_INTERFACE_PTR interface = NULL; CK_C_GetFunctionList C_GetFunctionList = NULL; @@ -124,27 +120,31 @@ } #ifdef DEBUG - C_GetInterfaceList = (CK_C_GetInterfaceList) dlsym(hModule, - "C_GetInterfaceList"); + CK_C_GetInterfaceList C_GetInterfaceList = (CK_C_GetInterfaceList) dlsym(hModule, "C_GetInterfaceList"); if (C_GetInterfaceList != NULL) { + CK_ULONG ulCount = 0; TRACE0("Connect: Found C_GetInterfaceList func\n"); rv = (C_GetInterfaceList)(NULL, &ulCount); if (rv == CKR_OK) { TRACE1("Connect: interface list size %ld \n", ulCount); // retrieve available interfaces and report their info - iList = (CK_INTERFACE_PTR) - malloc(ulCount*sizeof(CK_INTERFACE)); - rv = C_GetInterfaceList(iList, &ulCount); - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { - TRACE0("Connect: error polling interface list\n"); - goto cleanup; - } - for (i=0; i < (int)ulCount; i++) { - TRACE4("Connect: name %s, version %d.%d, flags 0x%lX\n", - iList[i].pInterfaceName, - ((CK_VERSION *)iList[i].pFunctionList)->major, - ((CK_VERSION *)iList[i].pFunctionList)->minor, - iList[i].flags); + CK_INTERFACE_PTR iList = (CK_INTERFACE_PTR) malloc(ulCount*sizeof(CK_INTERFACE)); + if (iList == NULL) { + TRACE0("Connect: error allocating interface list\n"); + } else { + rv = C_GetInterfaceList(iList, &ulCount); + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + TRACE0("Connect: error polling interface list\n"); + goto cleanup; + } + for (int i=0; i < (int)ulCount; i++) { + TRACE4("Connect: name %s, version %d.%d, flags 0x%lX\n", + iList[i].pInterfaceName, + ((CK_VERSION *)iList[i].pFunctionList)->major, + ((CK_VERSION *)iList[i].pFunctionList)->minor, + iList[i].flags); + } + free(iList); } } else { TRACE0("Connect: error polling interface list size\n"); diff -Nru openjdk-25-25.0.4.1+1/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c --- openjdk-25-25.0.4.1+1/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c 2026-10-19 12:10:20.000000000 +0000 @@ -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. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -79,10 +79,6 @@ jstring jGetFunctionList) { HINSTANCE hModule; - int i = 0; - CK_ULONG ulCount = 0; - CK_C_GetInterfaceList C_GetInterfaceList = NULL; - CK_INTERFACE_PTR iList = NULL; CK_C_GetInterface C_GetInterface = NULL; CK_INTERFACE_PTR interface = NULL; CK_C_GetFunctionList C_GetFunctionList = NULL; @@ -129,22 +125,27 @@ /* * Get function pointer to C_GetInterfaceList */ - C_GetInterfaceList = (CK_C_GetInterfaceList) GetProcAddress(hModule, + CK_C_GetInterfaceList C_GetInterfaceList = (CK_C_GetInterfaceList) GetProcAddress(hModule, "C_GetInterfaceList"); if (C_GetInterfaceList != NULL) { + CK_ULONG ulCount = 0; TRACE0("Found C_GetInterfaceList func\n"); rv = (C_GetInterfaceList)(NULL, &ulCount); if (rv == CKR_OK) { /* get copy of interfaces */ - iList = (CK_INTERFACE_PTR) - malloc(ulCount*sizeof(CK_INTERFACE)); - rv = C_GetInterfaceList(iList, &ulCount); - for (i=0; i < (int)ulCount; i++) { - printf("interface %s version %d.%d funcs %p flags 0x%lu\n", - iList[i].pInterfaceName, - ((CK_VERSION *)iList[i].pFunctionList)->major, - ((CK_VERSION *)iList[i].pFunctionList)->minor, - iList[i].pFunctionList, iList[i].flags); + CK_INTERFACE_PTR iList = (CK_INTERFACE_PTR) malloc(ulCount*sizeof(CK_INTERFACE)); + if (iList == NULL) { + TRACE0("Connect: error allocating interface list\n"); + } else { + rv = C_GetInterfaceList(iList, &ulCount); + for (int i=0; i < (int)ulCount; i++) { + printf("interface %s version %d.%d funcs %p flags 0x%lu\n", + iList[i].pInterfaceName, + ((CK_VERSION *)iList[i].pFunctionList)->major, + ((CK_VERSION *)iList[i].pFunctionList)->minor, + iList[i].pFunctionList, iList[i].flags); + } + free(iList); } } else { TRACE0("Connect: error polling interface list size\n"); diff -Nru openjdk-25-25.0.4.1+1/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java openjdk-25-25.0.5+8/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java --- openjdk-25-25.0.4.1+1/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,8 +88,11 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("ConstantPool"); tags = type.getAddressField("_tags"); - operands = type.getAddressField("_operands"); cache = type.getAddressField("_cache"); + bsm_entries = type.getField("_bsm_entries").getOffset(); + Type bsmae_type = db.lookupType("BSMAttributeEntries"); + bsm_entries_offsets = bsmae_type.getAddressField("_offsets"); + bsm_entries_bootstrap_methods = bsmae_type.getAddressField("_bootstrap_methods"); poolHolder = new MetadataField(type.getAddressField("_pool_holder"), 0); length = new CIntField(type.getCIntegerField("_length"), 0); resolved_klasses = type.getAddressField("_resolved_klasses"); @@ -100,9 +103,9 @@ headerSize = type.getSize(); elementSize = 0; // fetch constants: - INDY_BSM_OFFSET = db.lookupIntConstant("ConstantPool::_indy_bsm_offset").intValue(); - INDY_ARGC_OFFSET = db.lookupIntConstant("ConstantPool::_indy_argc_offset").intValue(); - INDY_ARGV_OFFSET = db.lookupIntConstant("ConstantPool::_indy_argv_offset").intValue(); + INDY_BSM_OFFSET = db.lookupIntConstant("BSMAttributeEntry::_bsmi_offset").intValue(); + INDY_ARGC_OFFSET = db.lookupIntConstant("BSMAttributeEntry::_argc_offset").intValue(); + INDY_ARGV_OFFSET = db.lookupIntConstant("BSMAttributeEntry::_argv_offset").intValue(); } public ConstantPool(Address addr) { @@ -112,9 +115,11 @@ public boolean isConstantPool() { return true; } private static AddressField tags; - private static AddressField operands; private static AddressField cache; private static AddressField resolved_klasses; + private static long bsm_entries; // Offset in the constantpool where the Bsm_Entries are found + private static AddressField bsm_entries_offsets; + private static AddressField bsm_entries_bootstrap_methods; private static MetadataField poolHolder; private static CIntField length; // number of elements in oop private static CIntField majorVersion; @@ -130,10 +135,6 @@ private static int INDY_ARGV_OFFSET; public U1Array getTags() { return new U1Array(tags.getValue(getAddress())); } - public U2Array getOperands() { - Address addr = operands.getValue(getAddress()); - return VMObjectFactory.newObject(U2Array.class, addr); - } public ConstantPoolCache getCache() { Address addr = cache.getValue(getAddress()); return VMObjectFactory.newObject(ConstantPoolCache.class, addr); @@ -435,26 +436,23 @@ return res; } + private U4Array getOffsets() { + Address a = getAddress().addOffsetTo(bsm_entries); + if (a == null) return null; + a = bsm_entries_offsets.getValue(a); + return VMObjectFactory.newObject(U4Array.class, a); + } + private U2Array getBootstrapMethods() { + Address a = getAddress().addOffsetTo(bsm_entries); + if (a == null) return null; + return VMObjectFactory.newObject(U2Array.class, bsm_entries_bootstrap_methods.getValue(a)); + } + public int getBootstrapMethodsCount() { - U2Array operands = getOperands(); + U4Array offsets = getOffsets(); int count = 0; - if (operands != null) { - // Operands array consists of two parts. First part is an array of 32-bit values which denote - // index of the bootstrap method data in the operands array. Note that elements of operands array are of type short. - // So each element of first part occupies two slots in the array. - // Second part is the bootstrap methods data. - // This layout allows us to get BSM count by getting the index of first BSM and dividing it by 2. - // - // The example below shows layout of operands array with 3 bootstrap methods. - // First part has 3 32-bit values indicating the index of the respective bootstrap methods in - // the operands array. - // The first BSM is at index 6. So the count in this case is 6/2=3. - // - // <-----first part----><-------second part-------> - // index: 0 2 4 6 i2 i3 - // operands: | 6 | i2 | i3 | bsm1 | bsm2 | bsm3 | - // - count = getOperandOffsetAt(operands, 0) / 2; + if (offsets != null) { + count = offsets.length(); } if (DEBUG) { System.err.println("ConstantPool.getBootstrapMethodsCount: count = " + count); @@ -463,12 +461,12 @@ } public int getBootstrapMethodArgsCount(int bsmIndex) { - U2Array operands = getOperands(); + U4Array offs = getOffsets(); + U2Array bsms = getBootstrapMethods(); if (Assert.ASSERTS_ENABLED) { - Assert.that(operands != null, "Operands is not present"); + Assert.that(offs != null && bsms != null, "BSM attribute is not present"); } - int bsmOffset = getOperandOffsetAt(operands, bsmIndex); - int argc = operands.at(bsmOffset + INDY_ARGC_OFFSET); + int argc = bsms.at(offs.at(bsmIndex) + INDY_ARGC_OFFSET); if (DEBUG) { System.err.println("ConstantPool.getBootstrapMethodArgsCount: bsm index = " + bsmIndex + ", args count = " + argc); } @@ -476,15 +474,16 @@ } public short[] getBootstrapMethodAt(int bsmIndex) { - U2Array operands = getOperands(); - if (operands == null) return null; // safety first - int basePos = getOperandOffsetAt(operands, bsmIndex); + U4Array offs = getOffsets(); + U2Array bsms = getBootstrapMethods(); + if (offs == null || bsms == null) return null; // safety first + int basePos = offs.at(bsmIndex); int argv = basePos + INDY_ARGV_OFFSET; - int argc = operands.at(basePos + INDY_ARGC_OFFSET); + int argc = getBootstrapMethodArgsCount(bsmIndex); int endPos = argv + argc; short[] values = new short[endPos - basePos]; for (int j = 0; j < values.length; j++) { - values[j] = operands.at(basePos+j); + values[j] = bsms.at(basePos+j); } return values; } @@ -773,8 +772,7 @@ // Return the offset of the requested Bootstrap Method in the operands array private int getOperandOffsetAt(U2Array operands, int bsmIndex) { - return VM.getVM().buildIntFromShorts(operands.at(bsmIndex * 2), - operands.at(bsmIndex * 2 + 1)); + return 0; } } diff -Nru openjdk-25-25.0.4.1+1/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U4Array.java openjdk-25-25.0.5+8/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U4Array.java --- openjdk-25-25.0.4.1+1/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U4Array.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U4Array.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.utilities; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.TypeDataBase; +import sun.jvm.hotspot.types.WrongTypeException; +import sun.jvm.hotspot.utilities.Observable; +import sun.jvm.hotspot.utilities.Observer; + +public class U4Array extends GenericArray { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { + elemType = db.lookupType("u4"); + Type type = db.lookupType("Array"); + dataFieldOffset = type.getAddressField("_data").getOffset(); + } + + private static long dataFieldOffset; + protected static Type elemType; + + public U4Array(Address addr) { + super(addr, dataFieldOffset); + } + + public int at(int i) { + return (int)getIntegerAt(i); + } + + public Type getElemType() { + return elemType; + } +} diff -Nru openjdk-25-25.0.4.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java --- openjdk-25-25.0.4.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java 2026-10-19 12:10:20.000000000 +0000 @@ -26,11 +26,11 @@ package sun.net.httpserver; import java.io.*; -import java.net.*; -import com.sun.net.httpserver.*; -import com.sun.net.httpserver.spi.*; class ChunkedInputStream extends LeftOverInputStream { + + private IOException readFailure = null; + ChunkedInputStream (ExchangeImpl t, InputStream src) { super (t, src); } @@ -50,6 +50,9 @@ private int numeric (char[] arr, int nchars) throws IOException { assert arr.length >= nchars; + if (nchars == 0) { + throw new IOException("missing chunk length"); + } int len = 0; for (int i=0; i Integer.MAX_VALUE) { + throw new IOException("chunk length too big: " + nextLen); + } + len = (int) nextLen; } return len; } @@ -111,14 +118,27 @@ } protected int readImpl (byte[]b, int off, int len) throws IOException { + // Chunk reader is stateful, don't retry after a failure + if (readFailure != null) { + throw readFailure; + } + try { + return readImpl0(b, off, len); + } catch (IOException ioe) { + readFailure = ioe; + throw ioe; + } + } + + private int readImpl0(byte[] b, int off, int len) throws IOException { if (eof) { return -1; } if (needToReadHeader) { remaining = readChunkHeader(); if (remaining == 0) { - eof = true; consumeCRLF(); + eof = true; t.getServerImpl().requestCompleted (t.getConnection()); return -1; } diff -Nru openjdk-25-25.0.4.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java --- openjdk-25-25.0.4.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package sun.net.httpserver; +import java.net.ProtocolException; import java.nio.*; import java.io.*; import java.nio.channels.*; @@ -36,18 +37,20 @@ */ class Request { - static final int BUF_LEN = 2048; static final byte CR = 13; static final byte LF = 10; + static final byte FIRST_CHAR = 32; private String startLine; private SocketChannel chan; private InputStream is; private OutputStream os; private final int maxReqHeaderSize; + private final boolean firstClearRequest; - Request (InputStream rawInputStream, OutputStream rawout) throws IOException { + Request(InputStream rawInputStream, OutputStream rawout, boolean firstClearRequest) throws IOException { this.maxReqHeaderSize = ServerConfig.getMaxReqHeaderSize(); + this.firstClearRequest = firstClearRequest; is = rawInputStream; os = rawout; do { @@ -57,10 +60,6 @@ } - char[] buf = new char [BUF_LEN]; - int pos; - StringBuffer lineBuf; - public InputStream inputStream () { return is; } @@ -75,30 +74,46 @@ */ public String readLine () throws IOException { - boolean gotCR = false, gotLF = false; - pos = 0; lineBuf = new StringBuffer(); + boolean gotLF = false; + StringBuilder lineBuf = new StringBuilder(); long lsize = 32; + + // For the first request that comes on a clear connection + // we will check that the first non CR/LF char on the + // request line is eligible. This should be the first char + // of a method name, so it should be at least greater or equal + // to 32 (FIRST_CHAR) which is the space character. + // The main goal here is to fail fast if we receive 0x16 (22) which + // happens to be the first byte of a TLS handshake record. + // This is typically what would be received if a TLS client opened + // a TLS connection on a non-TLS server. + // If we receive 0x16 we should close the connection immediately as + // it indicates we're receiving a ClientHello on a clear + // connection, and we will never receive the expected CRLF that + // terminates the first request line. + // Though we could check only for 0x16, any characters < 32 + // (excluding CRLF) is not expected at this position in a + // request line, so we can still fail here early if any of + // those are detected. + int offset = 0; while (!gotLF) { int c = is.read(); if (c == -1) { return null; } - if (gotCR) { - if (c == LF) { - gotLF = true; - } else { - gotCR = false; - consume (CR); - consume (c); - lsize = lsize + 2; - } + if (c == CR || c == LF) { + checkCRLF(c); + gotLF = true; } else { - if (c == CR) { - gotCR = true; - } else { - consume (c); - lsize = lsize + 1; + if (firstClearRequest && offset == 0) { + if (c < FIRST_CHAR) { + throw new ProtocolException("Unexpected start of request line"); + } + offset++; } + checkCtl(c); + lineBuf.append((char)c); + lsize = lsize + 1; } if (maxReqHeaderSize > 0 && lsize > maxReqHeaderSize) { throw new IOException("Maximum header (" + @@ -106,16 +121,7 @@ ServerConfig.getMaxReqHeaderSize() + "."); } } - lineBuf.append (buf, 0, pos); - return new String (lineBuf); - } - - private void consume (int c) throws IOException { - if (pos == BUF_LEN) { - lineBuf.append (buf); - pos = 0; - } - buf[pos++] = (char)c; + return lineBuf.toString(); } /** @@ -125,8 +131,24 @@ return startLine; } + void checkCtl(int c) throws IOException { + if (c == 0x7f || + c < ' ' && c != CR && c!= LF && c != '\t') { + throw new ProtocolException("Invalid character in request header"); + } + } + Headers hdrs = null; - @SuppressWarnings("fallthrough") + + void checkCRLF(int firstc) throws IOException { + if (firstc == CR) { + int c = is.read(); + if (c != LF) { + throw new ProtocolException("Invalid CR in request header"); + } + } + } + Headers headers () throws IOException { if (hdrs != null) { return hdrs; @@ -140,20 +162,16 @@ // check for empty headers if (firstc == CR || firstc == LF) { - int c = is.read(); - if (c == CR || c == LF) { - return hdrs; - } - s[0] = (char)firstc; - len = 1; - firstc = c; + checkCRLF(firstc); + return hdrs; } long hsize = startLine.length() + 32L; while (firstc != LF && firstc != CR && firstc >= 0) { int keyend = -1; int c; - boolean inKey = firstc > ' '; + boolean inKey = firstc != ' ' && firstc != '\t'; + checkCtl(firstc); s[len++] = (char) firstc; hsize = hsize + 1; parseloop:{ @@ -165,27 +183,26 @@ ? maxReqHeaderSize - hsize - 32 : Long.MAX_VALUE; while ((c = is.read()) >= 0) { + checkCtl(c); switch (c) { - /*fallthrough*/ case ':': - if (inKey && len > 0) + if (inKey && len > 0) { keyend = len; - inKey = false; + inKey = false; + } break; case '\t': c = ' '; - case ' ': - inKey = false; break; case CR: case LF: - firstc = is.read(); - if (c == CR && firstc == LF) { - firstc = is.read(); - if (firstc == CR) - firstc = is.read(); + checkCRLF(c); + if (inKey) { + throw new ProtocolException("Missing field separator"); } - if (firstc == LF || firstc == CR || firstc > ' ') + firstc = is.read(); + checkCRLF(firstc); + if (firstc != ' ' && firstc != '\t') break parseloop; /* continuation */ c = ' '; @@ -220,7 +237,7 @@ } String v; if (keyend >= len) - v = new String(); + v = ""; else v = String.copyValueOf(s, keyend, len - keyend); diff -Nru openjdk-25-25.0.4.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java --- openjdk-25-25.0.4.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,6 +71,7 @@ // the value of the TCP_NODELAY socket-level option private static final boolean noDelay; + private static final boolean hostValidationDisabled; static { @@ -116,6 +117,7 @@ debug = Boolean.getBoolean("sun.net.httpserver.debug"); noDelay = Boolean.getBoolean("sun.net.httpserver.nodelay"); + hostValidationDisabled = Boolean.getBoolean("sun.net.httpserver.disableHostValidation"); } @@ -219,4 +221,8 @@ static boolean noDelay() { return noDelay; } + + static boolean isHostValidationDisabled() { + return hostValidationDisabled; + } } diff -Nru openjdk-25-25.0.4.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java --- openjdk-25-25.0.4.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java 2026-10-19 12:10:20.000000000 +0000 @@ -45,6 +45,7 @@ import java.lang.System.Logger.Level; import java.net.BindException; import java.net.InetSocketAddress; +import java.net.ProtocolException; import java.net.ServerSocket; import java.net.URI; import java.net.URISyntaxException; @@ -109,6 +110,7 @@ static final long REQ_RSP_TIMER_SCHEDULE = ServerConfig.getReqRspTimerScheduleMillis(); static final long MAX_REQ_TIME = getTimeMillis(ServerConfig.getMaxReqTime()); static final long MAX_RSP_TIME = getTimeMillis(ServerConfig.getMaxRspTime()); + static final boolean HOST_VALIDATION_DISABLED = ServerConfig.isHostValidationDisabled();; static final boolean reqRspTimeoutEnabled = MAX_REQ_TIME != -1 || MAX_RSP_TIME != -1; // the maximum idle duration for a connection which is currently idle but has served // some request in the past @@ -733,7 +735,16 @@ connection.raw = rawin; connection.rawout = rawout; } - Request req = new Request (rawin, rawout); + + Request req; + try { + req = new Request(rawin, rawout, newconnection && !https); + } catch (ProtocolException pe) { + logger.log(Level.DEBUG, "closing due to: " + pe); + reject(Code.HTTP_BAD_REQUEST, "", pe.getMessage()); + return; + } + requestLine = req.requestLine(); if (requestLine == null) { /* connection closed */ @@ -776,7 +787,14 @@ start = space+1; String version = requestLine.substring (start); - Headers headers = req.headers(); + Headers headers; + try { + headers = req.headers(); + } catch (ProtocolException pe) { + reject(Code.HTTP_BAD_REQUEST, requestLine, + "Failed to parse headers: " + pe.getMessage()); + return; + } /* check key for illegal characters */ for (var k : headers.keySet()) { if (!isValidName(k)) { @@ -826,6 +844,25 @@ requestCompleted(connection); } } + /* check if there's a single Host header */ + if (!HOST_VALIDATION_DISABLED) { + List hostValueList = headers.get("Host"); + if (hostValueList == null || hostValueList.isEmpty()) { + if (!version.equalsIgnoreCase("http/1.0")) { + reject(400, requestLine, "Missing Host header"); + return; + } + } else if (hostValueList.size() > 1) { + reject(400, requestLine, "Multiple Host headers"); + return; + } else { + String host = hostValueList.get(0); + if (host.indexOf(',') != -1) { + reject(400, requestLine, "Multiple Host header values"); + return; + } + } + } ctx = contexts.findContext (protocol, uri.getPath()); if (ctx == null) { reject (Code.HTTP_NOT_FOUND, diff -Nru openjdk-25-25.0.4.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java --- openjdk-25-25.0.4.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java 2026-10-19 12:10:20.000000000 +0000 @@ -25,6 +25,7 @@ package sun.net.httpserver.simpleserver; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -220,7 +221,8 @@ // resolve each path segment against the root Path path = root; for (var segment : pathSegment) { - if (!URIPathSegment.isSupported(segment)) { + if (!URIPathSegment.isSupported(segment) || segment.contains(File.separator)) { + // checking for separator rules out anomalies like UNCs on Windows return null; // stop resolution, null results in 404 response } path = path.resolve(segment); diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java 2026-10-19 12:10:20.000000000 +0000 @@ -995,12 +995,6 @@ return super.fromArray0Template(Byte128Mask.class, a, offset, (Byte128Mask) m, offsetInRange); // specialize } - @ForceInline - @Override - final - ByteVector fromArray0(byte[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - return super.fromArray0Template(Byte128Mask.class, a, offset, indexMap, mapOffset, (Byte128Mask) m); - } @ForceInline diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java 2026-10-19 12:10:20.000000000 +0000 @@ -1027,12 +1027,6 @@ return super.fromArray0Template(Byte256Mask.class, a, offset, (Byte256Mask) m, offsetInRange); // specialize } - @ForceInline - @Override - final - ByteVector fromArray0(byte[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - return super.fromArray0Template(Byte256Mask.class, a, offset, indexMap, mapOffset, (Byte256Mask) m); - } @ForceInline diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java 2026-10-19 12:10:20.000000000 +0000 @@ -1091,12 +1091,6 @@ return super.fromArray0Template(Byte512Mask.class, a, offset, (Byte512Mask) m, offsetInRange); // specialize } - @ForceInline - @Override - final - ByteVector fromArray0(byte[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - return super.fromArray0Template(Byte512Mask.class, a, offset, indexMap, mapOffset, (Byte512Mask) m); - } @ForceInline diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java 2026-10-19 12:10:20.000000000 +0000 @@ -979,12 +979,6 @@ return super.fromArray0Template(Byte64Mask.class, a, offset, (Byte64Mask) m, offsetInRange); // specialize } - @ForceInline - @Override - final - ByteVector fromArray0(byte[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - return super.fromArray0Template(Byte64Mask.class, a, offset, indexMap, mapOffset, (Byte64Mask) m); - } @ForceInline diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java 2026-10-19 12:10:20.000000000 +0000 @@ -965,12 +965,6 @@ return super.fromArray0Template(ByteMaxMask.class, a, offset, (ByteMaxMask) m, offsetInRange); // specialize } - @ForceInline - @Override - final - ByteVector fromArray0(byte[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - return super.fromArray0Template(ByteMaxMask.class, a, offset, indexMap, mapOffset, (ByteMaxMask) m); - } @ForceInline diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java 2026-10-19 12:10:20.000000000 +0000 @@ -3105,35 +3105,7 @@ byte[] a, int offset, int[] indexMap, int mapOffset) { ByteSpecies vsp = (ByteSpecies) species; - IntVector.IntSpecies isp = IntVector.species(vsp.indexShape()); - Objects.requireNonNull(a); - Objects.requireNonNull(indexMap); - Class vectorType = vsp.vectorType(); - - - // Constant folding should sweep out following conditonal logic. - VectorSpecies lsp; - if (isp.length() > IntVector.SPECIES_PREFERRED.length()) { - lsp = IntVector.SPECIES_PREFERRED; - } else { - lsp = isp; - } - - // Check indices are within array bounds. - for (int i = 0; i < vsp.length(); i += lsp.length()) { - IntVector vix = IntVector - .fromArray(lsp, indexMap, mapOffset + i) - .add(offset); - VectorIntrinsics.checkIndex(vix, a.length); - } - - return VectorSupport.loadWithMap( - vectorType, null, byte.class, vsp.laneCount(), - lsp.vectorType(), - a, ARRAY_BASE, null, null, - a, offset, indexMap, mapOffset, vsp, - (c, idx, iMap, idy, s, vm) -> - s.vOp(n -> c[idx + iMap[idy+n]])); + return vsp.vOp(n -> a[offset + indexMap[mapOffset + n]]); } /** @@ -3178,13 +3150,8 @@ byte[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - if (m.allTrue()) { - return fromArray(species, a, offset, indexMap, mapOffset); - } - else { - ByteSpecies vsp = (ByteSpecies) species; - return vsp.dummyVector().fromArray0(a, offset, indexMap, mapOffset, m); - } + ByteSpecies vsp = (ByteSpecies) species; + return vsp.vOp(m, n -> a[offset + indexMap[mapOffset + n]]); } @@ -3854,49 +3821,6 @@ (arr_, off_, i) -> arr_[off_ + i])); } - /*package-private*/ - abstract - ByteVector fromArray0(byte[] a, int offset, - int[] indexMap, int mapOffset, - VectorMask m); - @ForceInline - final - > - ByteVector fromArray0Template(Class maskClass, byte[] a, int offset, - int[] indexMap, int mapOffset, M m) { - ByteSpecies vsp = vspecies(); - IntVector.IntSpecies isp = IntVector.species(vsp.indexShape()); - Objects.requireNonNull(a); - Objects.requireNonNull(indexMap); - m.check(vsp); - Class vectorType = vsp.vectorType(); - - - // Constant folding should sweep out following conditonal logic. - VectorSpecies lsp; - if (isp.length() > IntVector.SPECIES_PREFERRED.length()) { - lsp = IntVector.SPECIES_PREFERRED; - } else { - lsp = isp; - } - - // Check indices are within array bounds. - // FIXME: Check index under mask controlling. - for (int i = 0; i < vsp.length(); i += lsp.length()) { - IntVector vix = IntVector - .fromArray(lsp, indexMap, mapOffset + i) - .add(offset); - VectorIntrinsics.checkIndex(vix, a.length); - } - - return VectorSupport.loadWithMap( - vectorType, maskClass, byte.class, vsp.laneCount(), - lsp.vectorType(), - a, ARRAY_BASE, null, m, - a, offset, indexMap, mapOffset, vsp, - (c, idx, iMap, idy, s, vm) -> - s.vOp(vm, n -> c[idx + iMap[idy+n]])); - } /*package-private*/ diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java 2026-10-19 12:10:20.000000000 +0000 @@ -967,12 +967,6 @@ return super.fromArray0Template(Short128Mask.class, a, offset, (Short128Mask) m, offsetInRange); // specialize } - @ForceInline - @Override - final - ShortVector fromArray0(short[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - return super.fromArray0Template(Short128Mask.class, a, offset, indexMap, mapOffset, (Short128Mask) m); - } @ForceInline @Override diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java 2026-10-19 12:10:20.000000000 +0000 @@ -983,12 +983,6 @@ return super.fromArray0Template(Short256Mask.class, a, offset, (Short256Mask) m, offsetInRange); // specialize } - @ForceInline - @Override - final - ShortVector fromArray0(short[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - return super.fromArray0Template(Short256Mask.class, a, offset, indexMap, mapOffset, (Short256Mask) m); - } @ForceInline @Override diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java 2026-10-19 12:10:20.000000000 +0000 @@ -1015,12 +1015,6 @@ return super.fromArray0Template(Short512Mask.class, a, offset, (Short512Mask) m, offsetInRange); // specialize } - @ForceInline - @Override - final - ShortVector fromArray0(short[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - return super.fromArray0Template(Short512Mask.class, a, offset, indexMap, mapOffset, (Short512Mask) m); - } @ForceInline @Override diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java 2026-10-19 12:10:20.000000000 +0000 @@ -959,12 +959,6 @@ return super.fromArray0Template(Short64Mask.class, a, offset, (Short64Mask) m, offsetInRange); // specialize } - @ForceInline - @Override - final - ShortVector fromArray0(short[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - return super.fromArray0Template(Short64Mask.class, a, offset, indexMap, mapOffset, (Short64Mask) m); - } @ForceInline @Override diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java 2026-10-19 12:10:20.000000000 +0000 @@ -953,12 +953,6 @@ return super.fromArray0Template(ShortMaxMask.class, a, offset, (ShortMaxMask) m, offsetInRange); // specialize } - @ForceInline - @Override - final - ShortVector fromArray0(short[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - return super.fromArray0Template(ShortMaxMask.class, a, offset, indexMap, mapOffset, (ShortMaxMask) m); - } @ForceInline @Override diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java 2026-10-19 12:10:20.000000000 +0000 @@ -3106,35 +3106,7 @@ short[] a, int offset, int[] indexMap, int mapOffset) { ShortSpecies vsp = (ShortSpecies) species; - IntVector.IntSpecies isp = IntVector.species(vsp.indexShape()); - Objects.requireNonNull(a); - Objects.requireNonNull(indexMap); - Class vectorType = vsp.vectorType(); - - - // Constant folding should sweep out following conditonal logic. - VectorSpecies lsp; - if (isp.length() > IntVector.SPECIES_PREFERRED.length()) { - lsp = IntVector.SPECIES_PREFERRED; - } else { - lsp = isp; - } - - // Check indices are within array bounds. - for (int i = 0; i < vsp.length(); i += lsp.length()) { - IntVector vix = IntVector - .fromArray(lsp, indexMap, mapOffset + i) - .add(offset); - VectorIntrinsics.checkIndex(vix, a.length); - } - - return VectorSupport.loadWithMap( - vectorType, null, short.class, vsp.laneCount(), - lsp.vectorType(), - a, ARRAY_BASE, null, null, - a, offset, indexMap, mapOffset, vsp, - (c, idx, iMap, idy, s, vm) -> - s.vOp(n -> c[idx + iMap[idy+n]])); + return vsp.vOp(n -> a[offset + indexMap[mapOffset + n]]); } /** @@ -3179,13 +3151,8 @@ short[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { - if (m.allTrue()) { - return fromArray(species, a, offset, indexMap, mapOffset); - } - else { - ShortSpecies vsp = (ShortSpecies) species; - return vsp.dummyVector().fromArray0(a, offset, indexMap, mapOffset, m); - } + ShortSpecies vsp = (ShortSpecies) species; + return vsp.vOp(m, n -> a[offset + indexMap[mapOffset + n]]); } /** @@ -3840,49 +3807,6 @@ (arr_, off_, i) -> arr_[off_ + i])); } - /*package-private*/ - abstract - ShortVector fromArray0(short[] a, int offset, - int[] indexMap, int mapOffset, - VectorMask m); - @ForceInline - final - > - ShortVector fromArray0Template(Class maskClass, short[] a, int offset, - int[] indexMap, int mapOffset, M m) { - ShortSpecies vsp = vspecies(); - IntVector.IntSpecies isp = IntVector.species(vsp.indexShape()); - Objects.requireNonNull(a); - Objects.requireNonNull(indexMap); - m.check(vsp); - Class vectorType = vsp.vectorType(); - - - // Constant folding should sweep out following conditonal logic. - VectorSpecies lsp; - if (isp.length() > IntVector.SPECIES_PREFERRED.length()) { - lsp = IntVector.SPECIES_PREFERRED; - } else { - lsp = isp; - } - - // Check indices are within array bounds. - // FIXME: Check index under mask controlling. - for (int i = 0; i < vsp.length(); i += lsp.length()) { - IntVector vix = IntVector - .fromArray(lsp, indexMap, mapOffset + i) - .add(offset); - VectorIntrinsics.checkIndex(vix, a.length); - } - - return VectorSupport.loadWithMap( - vectorType, maskClass, short.class, vsp.laneCount(), - lsp.vectorType(), - a, ARRAY_BASE, null, m, - a, offset, indexMap, mapOffset, vsp, - (c, idx, iMap, idy, s, vm) -> - s.vOp(vm, n -> c[idx + iMap[idy+n]])); - } /*package-private*/ abstract diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template 2026-10-19 12:10:20.000000000 +0000 @@ -3748,35 +3748,7 @@ $type$[] a, int offset, int[] indexMap, int mapOffset) { $Type$Species vsp = ($Type$Species) species; - IntVector.IntSpecies isp = IntVector.species(vsp.indexShape()); - Objects.requireNonNull(a); - Objects.requireNonNull(indexMap); - Class vectorType = vsp.vectorType(); - - - // Constant folding should sweep out following conditonal logic. - VectorSpecies lsp; - if (isp.length() > IntVector.SPECIES_PREFERRED.length()) { - lsp = IntVector.SPECIES_PREFERRED; - } else { - lsp = isp; - } - - // Check indices are within array bounds. - for (int i = 0; i < vsp.length(); i += lsp.length()) { - IntVector vix = IntVector - .fromArray(lsp, indexMap, mapOffset + i) - .add(offset); - VectorIntrinsics.checkIndex(vix, a.length); - } - - return VectorSupport.loadWithMap( - vectorType, null, $type$.class, vsp.laneCount(), - lsp.vectorType(), - a, ARRAY_BASE, null, null, - a, offset, indexMap, mapOffset, vsp, - (c, idx, iMap, idy, s, vm) -> - s.vOp(n -> c[idx + iMap[idy+n]])); + return vsp.vOp(n -> a[offset + indexMap[mapOffset + n]]); } #else[byteOrShort] @ForceInline @@ -3868,6 +3840,17 @@ * where the mask is set * @see $abstractvectortype$#toIntArray() */ +#if[byteOrShort] + @ForceInline + public static + $abstractvectortype$ fromArray(VectorSpecies<$Boxtype$> species, + $type$[] a, int offset, + int[] indexMap, int mapOffset, + VectorMask<$Boxtype$> m) { + $Type$Species vsp = ($Type$Species) species; + return vsp.vOp(m, n -> a[offset + indexMap[mapOffset + n]]); + } +#else[byteOrShort] @ForceInline public static $abstractvectortype$ fromArray(VectorSpecies<$Boxtype$> species, @@ -3882,6 +3865,7 @@ return vsp.dummyVector().fromArray0(a, offset, indexMap, mapOffset, m); } } +#end[byteOrShort] #if[short] /** @@ -4942,51 +4926,12 @@ (arr_, off_, i) -> arr_[off_ + i])); } +#if[!byteOrShort] /*package-private*/ abstract $abstractvectortype$ fromArray0($type$[] a, int offset, int[] indexMap, int mapOffset, VectorMask<$Boxtype$> m); -#if[byteOrShort] - @ForceInline - final - > - $abstractvectortype$ fromArray0Template(Class maskClass, $type$[] a, int offset, - int[] indexMap, int mapOffset, M m) { - $Type$Species vsp = vspecies(); - IntVector.IntSpecies isp = IntVector.species(vsp.indexShape()); - Objects.requireNonNull(a); - Objects.requireNonNull(indexMap); - m.check(vsp); - Class vectorType = vsp.vectorType(); - - - // Constant folding should sweep out following conditonal logic. - VectorSpecies lsp; - if (isp.length() > IntVector.SPECIES_PREFERRED.length()) { - lsp = IntVector.SPECIES_PREFERRED; - } else { - lsp = isp; - } - - // Check indices are within array bounds. - // FIXME: Check index under mask controlling. - for (int i = 0; i < vsp.length(); i += lsp.length()) { - IntVector vix = IntVector - .fromArray(lsp, indexMap, mapOffset + i) - .add(offset); - VectorIntrinsics.checkIndex(vix, a.length); - } - - return VectorSupport.loadWithMap( - vectorType, maskClass, $type$.class, vsp.laneCount(), - lsp.vectorType(), - a, ARRAY_BASE, null, m, - a, offset, indexMap, mapOffset, vsp, - (c, idx, iMap, idy, s, vm) -> - s.vOp(vm, n -> c[idx + iMap[idy+n]])); - } -#else[byteOrShort] @ForceInline final > @@ -5040,7 +4985,7 @@ (c, idx, iMap, idy, s, vm) -> s.vOp(vm, n -> c[idx + iMap[idy+n]])); } -#end[byteOrShort] +#end[!byteOrShort] #if[short] /*package-private*/ diff -Nru openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template --- openjdk-25-25.0.4.1+1/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template 2026-10-19 12:10:20.000000000 +0000 @@ -1365,12 +1365,14 @@ return super.fromArray0Template($masktype$.class, a, offset, ($masktype$) m, offsetInRange); // specialize } +#if[!byteOrShort] @ForceInline @Override final $abstractvectortype$ fromArray0($type$[] a, int offset, int[] indexMap, int mapOffset, VectorMask<$Boxtype$> m) { return super.fromArray0Template($masktype$.class, a, offset, indexMap, mapOffset, ($masktype$) m); } +#end[!byteOrShort] #if[short] @ForceInline diff -Nru openjdk-25-25.0.4.1+1/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template openjdk-25-25.0.5+8/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template --- openjdk-25-25.0.4.1+1/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template 2026-10-19 12:10:20.000000000 +0000 @@ -224,13 +224,13 @@ function switchCopyLabel(button, span) { var copied = span.getAttribute("data-copied"); button.classList.add("visible"); - var initialLabel = span.innerHTML; - span.innerHTML = copied; + var initialLabel = span.textContent; + span.textContent = copied; setTimeout(function() { button.classList.remove("visible"); setTimeout(function() { if (initialLabel !== copied) { - span.innerHTML = initialLabel; + span.textContent = initialLabel; } }, 100); }, 1900); diff -Nru openjdk-25-25.0.4.1+1/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js openjdk-25-25.0.5+8/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js --- openjdk-25-25.0.4.1+1/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js 2026-10-19 12:10:20.000000000 +0000 @@ -17,7 +17,7 @@ if (redirect.is(":checked")) { href += "&r=1"; } - searchLink.html(href); + searchLink.text(href); copy[0].onmouseenter(); } function copyLink(e) { @@ -55,11 +55,11 @@ const MIN_TABBED_RESULTS = 10; function renderResults(result) { if (!result.length) { - notify.html(messages.noResult); + notify.text(messages.noResult); } else if (result.length === 1) { - notify.html(messages.oneResult); + notify.text(messages.oneResult); } else { - notify.html(messages.manyResults.replace("{0}", result.length)); + notify.text(messages.manyResults.replace("{0}", result.length)); } resultContainer.empty(); var r = { @@ -78,7 +78,7 @@ activeTab = Object.keys(r).find(category => r[category].length > 0); } if (feelingLucky && activeTab) { - notify.html(messages.redirecting) + notify.text(messages.redirecting) var firstItem = r[activeTab][0]; window.location = getURL(firstItem.indexItem, firstItem.category); return; @@ -105,10 +105,10 @@ .attr("tabIndex", "-1") .addClass("page-search-header") .append($("") - .html(categories[key]) + .text(categories[key]) .append($("") .attr("style", "font-weight:normal;") - .html(" (" + count + ")"))) + .text(" (" + count + ")"))) .on("click", null, key, function(e) { fixedTab = true; renderResult(e.data, $(this)); @@ -155,8 +155,8 @@ } col2 = descDesc; $("
    ") - .append($("").html(col1)) - .append($("").html(col2)) + .append($("").text(col1)) + .append($("").text(col2)) .appendTo(table); $.each(items, function(index, item) { renderItem(item, table); @@ -185,7 +185,7 @@ .on("mouseleave", unselect.bind(link[0])) .on("blur", unselect.bind(link[0])) .append($("").addClass("search-result-label").html(label)) - .append($("").addClass("search-result-desc").html(desc)) + .append($("").addClass("search-result-desc").text(desc)) .appendTo(table); } var timeout; @@ -201,13 +201,13 @@ setSearchUrl(); var term = searchTerm = input.val().trim(); if (term === "") { - notify.html(messages.enterTerm); + notify.text(messages.enterTerm); activeTab = ""; fixedTab = false; resultContainer.empty(); resultSection.hide(); } else { - notify.html(messages.searching); + notify.text(messages.searching); var module = modules.val(); doSearch({ term: term, maxResults: 1200, module: module}, renderResults); } @@ -295,7 +295,7 @@ } }); reset.on("click", function() { - notify.html(messages.enterTerm); + notify.text(messages.enterTerm); resultSection.hide(); activeTab = ""; fixedTab = false; @@ -342,7 +342,7 @@ if (input.val()) { doPageSearch(); } else { - notify.html(messages.enterTerm); + notify.text(messages.enterTerm); } input.select().focus(); }); diff -Nru openjdk-25-25.0.4.1+1/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template openjdk-25-25.0.5+8/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template --- openjdk-25-25.0.4.1+1/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template 2026-10-19 12:10:20.000000000 +0000 @@ -425,7 +425,7 @@ return $("
  • ") .append($("
    ") .append($("").addClass("search-result-label").html(label)) - .append($("").addClass("search-result-desc").html(resultDesc))) + .append($("").addClass("search-result-desc").text(resultDesc))) .appendTo(ul); }, _resizeMenu: function () { diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c openjdk-25-25.0.5+8/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c --- openjdk-25-25.0.4.1+1/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -90,8 +90,8 @@ static const char * file_basename(const char *file) { - char *p1; - char *p2; + const char* p1; + const char* p2; if ( file==NULL ) return "unknown"; diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java openjdk-25-25.0.5+8/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java --- openjdk-25-25.0.4.1+1/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java 2026-10-19 12:10:20.000000000 +0000 @@ -51,6 +51,7 @@ import jdk.tools.jlink.internal.plugins.DefaultStripDebugPlugin; import jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin; import jdk.tools.jlink.internal.plugins.PluginsResourceBundle; +import jdk.tools.jlink.internal.plugins.StripJavaDebugAttributesPlugin; import jdk.tools.jlink.plugin.Plugin; import jdk.tools.jlink.plugin.Plugin.Category; @@ -418,6 +419,9 @@ List pluginsList = new ArrayList<>(); Set seenPlugins = new HashSet<>(); + // reference to the enabled DefaultStripDebugPlugin + DefaultStripDebugPlugin defaultStripDebugPlugin = null; + for (Entry>> entry : pluginToMaps.entrySet()) { Plugin plugin = entry.getKey(); List> argsMaps = entry.getValue(); @@ -438,6 +442,10 @@ } if (!Utils.isDisabled(plugin)) { + if (plugin instanceof DefaultStripDebugPlugin p) { + defaultStripDebugPlugin = p; + } + // make sure that --strip-debug and --strip-native-debug-symbols // aren't being used at the same time. --strip-debug invokes --strip-native-debug-symbols on // platforms that support it, so it makes little sense to allow both at the same time. @@ -452,6 +460,11 @@ } } + // disable StripJavaDebugAttributesPlugin within DefaultStripDebug plugin if both enabled + if (seenPlugins.contains(StripJavaDebugAttributesPlugin.NAME) && defaultStripDebugPlugin != null) { + defaultStripDebugPlugin.enableJavaStripPlugin(false); + } + // recreate or postprocessing don't require an output directory. ImageBuilder builder = null; if (output != null) { diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin.java openjdk-25-25.0.5+8/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin.java --- openjdk-25-25.0.4.1+1/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin.java 2026-10-19 12:10:20.000000000 +0000 @@ -47,6 +47,8 @@ private final Plugin javaStripPlugin; private final NativePluginFactory stripNativePluginFactory; + private boolean isJavaStripPluginEnabled = true; + public DefaultStripDebugPlugin() { this(new StripJavaDebugAttributesPlugin(), new DefaultNativePluginFactory()); @@ -59,6 +61,10 @@ this.stripNativePluginFactory = nativeStripPluginFact; } + public void enableJavaStripPlugin(boolean enableJavaStripPlugin) { + isJavaStripPluginEnabled = enableJavaStripPlugin; + } + @Override public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) { Plugin stripNativePlugin = stripNativePluginFactory.create(); @@ -66,14 +72,21 @@ Map stripNativeConfig = Map.of( STRIP_NATIVE_DEBUG_PLUGIN, EXCLUDE_DEBUGINFO); stripNativePlugin.configure(stripNativeConfig); + + if (!isJavaStripPluginEnabled) { + return stripNativePlugin.transform(in, out); + } + ResourcePoolManager outRes = new ResourcePoolManager(in.byteOrder(), ((ResourcePoolImpl)in).getStringTable()); ResourcePool strippedJava = javaStripPlugin.transform(in, outRes.resourcePoolBuilder()); return stripNativePlugin.transform(strippedJava, out); - } else { + } else if (isJavaStripPluginEnabled) { return javaStripPlugin.transform(in, out); + } else { + return in; } } diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java openjdk-25-25.0.5+8/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java --- openjdk-25-25.0.4.1+1/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java 2026-10-19 12:10:20.000000000 +0000 @@ -43,13 +43,14 @@ */ public final class StripJavaDebugAttributesPlugin extends AbstractPlugin { private final Predicate predicate; + public static final String NAME = "strip-java-debug-attributes"; public StripJavaDebugAttributesPlugin() { this((path) -> false); } StripJavaDebugAttributesPlugin(Predicate predicate) { - super("strip-java-debug-attributes"); + super(NAME); this.predicate = predicate; } @@ -69,11 +70,9 @@ ClassFile.LineNumbersOption.DROP_LINE_NUMBERS); byte[] content = ClassFile.of().transformClass(clm, ClassTransform .dropping(cle -> cle instanceof SourceFileAttribute - || cle instanceof SourceDebugExtensionAttribute) - .andThen(ClassTransform.transformingMethods(MethodTransform - .dropping(me -> me instanceof MethodParametersAttribute) - .andThen(MethodTransform - .transformingCode(CodeTransform.ACCEPT_ALL))))); + || cle instanceof SourceDebugExtensionAttribute) + .andThen(ClassTransform.transformingMethods(MethodTransform + .transformingCode(CodeTransform.ACCEPT_ALL)))); res = resource.copyWithContent(content); } } diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/applauncher/ExecCommand.c openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/ExecCommand.c --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/applauncher/ExecCommand.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/ExecCommand.c 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ExecCommand.h" +#include "JvmLauncher.h" + + +static bool logCommandLine(const char* format, const char* const argv[]) { + char* formattedCommandLine = NULL; + int formattedCommandLineLength = 0; + const char* arg; + int i; + bool success = false; + + for (i = 0; (arg = argv[i]) != NULL; i++) { + /* Count trailing whitespace */ + formattedCommandLineLength += strlen(arg) + 1; + if (strchr(arg, ' ') != NULL) { + /* Enclose the argument into single quotes */ + formattedCommandLineLength += 2; + } + } + + if (!formattedCommandLineLength) { + /* Empty command line is an error */ + goto cleanup; + } + + formattedCommandLine = malloc(formattedCommandLineLength + 1 /* \0 */); + if (!formattedCommandLine) { + JP_LOG_ERRNO; + goto cleanup; + } + + formattedCommandLine[0] = '\0'; + for (i = 0; (arg = argv[i]) != NULL; i++) { + if (strchr(arg, ' ') != NULL) { + strcat(formattedCommandLine, "'"); + strcat(formattedCommandLine, arg); + strcat(formattedCommandLine, "'"); + } else { + strcat(formattedCommandLine, arg); + } + strcat(formattedCommandLine, " "); + } + + /* Trim trailing whitespace */ + formattedCommandLine[formattedCommandLineLength - 1] = '\0'; + + JP_LOG_TRACE(format, formattedCommandLine); + + success = true; + +cleanup: + free(formattedCommandLine); + + return success; +} + +static bool invokeCallback( + FILE* stream, + ExecCommandCallbackType callback, + void* callbackData) { + + char* strBufBegin = NULL; + char* strBufEnd = NULL; + char* strBufNextChar = NULL; + char* strNewBufBegin = NULL; + size_t strBufCapacity = 0; + int callbackMode = EXEC_CALLBACK_USE; + int c; + ptrdiff_t charOffset; + int success = false; + int tailCharCount = 0; + + for (;;) { + c = fgetc(stream); + if (EOF == c || '\n' == c) { + if (EXEC_CALLBACK_USE == callbackMode + && strBufBegin != strBufNextChar) { + *strBufNextChar = 0; + JP_LOG_TRACE("execCommand: [%s]", strBufBegin); + callbackMode = (*callback)(callbackData, strBufBegin); + strBufNextChar = strBufBegin; + } + + if (EOF == c) { + break; + } + + continue; + } + + if (EXEC_CALLBACK_USE != callbackMode) { + /* Fetch the stream */ + for (; EOF != c; c = fgetc(stream)) { + tailCharCount++; + } + if (tailCharCount) { + JP_LOG_TRACE( + "execCommand: fetched %d trailing chars", + tailCharCount); + } + break; + } + + if (strBufNextChar == strBufEnd) { + /* Double buffer size */ + if (strBufCapacity) { + strBufCapacity = strBufCapacity * 2; + } else { + strBufCapacity = 1; + } + + if (strBufNextChar && strBufBegin) { + charOffset = strBufNextChar - strBufBegin; + } else { + charOffset = 0; + } + + strNewBufBegin = realloc( strBufBegin, + /* Account for the terminal '\0' */ + strBufCapacity + 1); + if (!strNewBufBegin) { + JP_LOG_ERRNO; + goto cleanup; + } + + strBufNextChar = strNewBufBegin + charOffset; + strBufEnd = strNewBufBegin + strBufCapacity; + strBufBegin = strNewBufBegin; + } + + *strBufNextChar++ = (char)c; + } + + success = (EXEC_CALLBACK_ERROR != callbackMode); + +cleanup: + if (strBufBegin) { + free(strBufBegin); + } + + return success; +} + + +int execCommand( + const char* const argv[], + ExecCommandCallbackType callback, + void* callbackData) { + + int pipefd[] = { -1, -1 }; + pid_t cpid = -1; + FILE* stream = NULL; + int exitCode = -1; + int devNull = -1; + int savedStderr = -1; + int savedErrno = 0; + bool callbackSuccess = false; + int childExitCode = 1; + int waitpidStatus = -1; + + if (!logCommandLine("execCommand: cmdline=[%s]", argv)) { + return -1; + } + + if (pipe(pipefd) == -1) { + JP_LOG_ERRNO; + goto cleanup; + } + + cpid = fork(); + if (cpid == -1) { + JP_LOG_ERRNO; + } else if (cpid == 0) /* Child process */ { + /* Close unused read end */ + closePipeEnd(pipefd, 0); + + /* Save original stderr */ + if ((savedStderr = dup(STDERR_FILENO)) == -1) { + JP_LOG_ERRNO; + goto cleanupChild; + } + + /* Redirect stdout of the child process into the pipe's end */ + if (dup2(pipefd[1], STDOUT_FILENO) == -1) { + JP_LOG_ERRNO; + goto cleanupChild; + } + + devNull = open("/dev/null", O_WRONLY); + if (devNull == -1) { + JP_LOG_ERRNO; + goto cleanupChild; + } + + /* Silence stderr in the child process */ + if (dup2(devNull, STDERR_FILENO) == -1) { + JP_LOG_ERRNO; + goto cleanupChild; + } + + childExitCode = 0; + +cleanupChild: + if (devNull != -1) { + close(devNull); + } + + closePipeEnd(pipefd, 0); + + if (childExitCode == 0) { + execvp(argv[0], (char* const*)argv); + + /* + Normally, execvp() doesn't return. + If control flow reaches this point, execvp() failed. + Restore stderr to make JP_LOG_ERRNO macro work and report error. + */ + savedErrno = errno; + dup2(savedStderr, STDERR_FILENO); + errno = savedErrno; + JP_LOG_ERRNO; + + close(savedStderr); + + childExitCode = 127; /* Command not found */ + } + + _exit(childExitCode); + } + + /* Close unused write end */ + closePipeEnd(pipefd, 1); + + stream = fdopen(pipefd[0], "r"); + if (!stream) { + JP_LOG_ERRNO; + goto cleanup; + } + pipefd[0] = -1; + + callbackSuccess = invokeCallback(stream, callback, callbackData); + if (!callbackSuccess) { + JP_LOG_TRACE("Callback failed"); + goto cleanup; + } + +cleanup: + if (stream) { + fclose(stream); + } + + closePipeEnd(pipefd, 0); + closePipeEnd(pipefd, 1); + + if (cpid > 0) { + while (waitpid(cpid, &waitpidStatus, 0) == -1 && errno == EINTR) { + } + + if (WIFEXITED(waitpidStatus)) { + exitCode = WEXITSTATUS(waitpidStatus); + } + } + + JP_LOG_TRACE("execCommand: exit=%d", exitCode); + + if (exitCode == 0 && !callbackSuccess) { + exitCode = 1; + } + + return exitCode; +} + + +void closePipeEnd(int* pipefd, int idx) { + if (pipefd[idx] >= 0) { + close(pipefd[idx]); + pipefd[idx] = -1; + } +} diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/applauncher/ExecCommand.h openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/ExecCommand.h --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/applauncher/ExecCommand.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/ExecCommand.h 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef ExecCommand_h +#define ExecCommand_h + +#ifdef __cplusplus +extern "C" { +#endif + +#define EXEC_CALLBACK_IGNORE 0 +#define EXEC_CALLBACK_USE 1 +#define EXEC_CALLBACK_ERROR 2 + +typedef int (*ExecCommandCallbackType)(void*, char*); + +int execCommand(const char* const argv[], + ExecCommandCallbackType callback, + void* callbackData); + +void closePipeEnd(int* pipefd, int idx); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ExecCommand_h */ diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxLauncher.c openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/LinuxLauncher.c --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxLauncher.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/LinuxLauncher.c 2026-10-19 12:10:20.000000000 +0000 @@ -35,31 +35,40 @@ #include #include "JvmLauncher.h" #include "LinuxPackage.h" +#include "ExecCommand.h" #define STATUS_FAILURE 1 -typedef JvmlLauncherHandle (*JvmlLauncherAPI_CreateFunType)(int argc, char *argv[]); +typedef JvmlLauncherHandle (*JvmlLauncherAPI_CreateFunType)( + const PackageDesc* pkg, + int argc, + char* argv[]); static int appArgc; static char **appArgv; static JvmlLauncherData* initJvmlLauncherData(int* size) { - char* launcherLibPath = 0; + JvmLauncherDesc* jvmLauncherDesc = 0; + PackageDesc pkg; void* jvmLauncherLibHandle = 0; JvmlLauncherAPI_GetAPIFunc getApi = 0; - JvmlLauncherAPI_CreateFunType createJvmlLauncher = 0; + JvmlLauncherAPI_CreateFunType createJvmLauncher = 0; JvmlLauncherAPI* api = 0; JvmlLauncherHandle jvmLauncherHandle = 0; JvmlLauncherData* result = 0; - launcherLibPath = getJvmLauncherLibPath(); - if (!launcherLibPath) { + jvmLauncherDesc = getJvmLauncherDesc(); + if (!jvmLauncherDesc) { goto cleanup; } - jvmLauncherLibHandle = dlopen(launcherLibPath, RTLD_NOW | RTLD_LOCAL); + pkg.name = jvmLauncherDesc->packageName; + pkg.type = jvmLauncherDesc->packageType; + + jvmLauncherLibHandle = dlopen( jvmLauncherDesc->jvmLauncherLibPath, + RTLD_NOW | RTLD_LOCAL); if (!jvmLauncherLibHandle) { JP_LOG_ERRMSG(dlerror()); goto cleanup; @@ -77,13 +86,13 @@ goto cleanup; } - createJvmlLauncher = dlsym(jvmLauncherLibHandle, "jvmLauncherCreate"); - if (!createJvmlLauncher) { + createJvmLauncher = dlsym(jvmLauncherLibHandle, "jvmLauncherCreate"); + if (!createJvmLauncher) { JP_LOG_ERRMSG(dlerror()); goto cleanup; } - jvmLauncherHandle = (*createJvmlLauncher)(appArgc, appArgv); + jvmLauncherHandle = (*createJvmLauncher)(&pkg, appArgc, appArgv); if (!jvmLauncherHandle) { goto cleanup; } @@ -99,7 +108,7 @@ if (jvmLauncherLibHandle) { dlclose(jvmLauncherLibHandle); } - free(launcherLibPath); + freeJvmLauncherDesc(jvmLauncherDesc); return result; } @@ -133,13 +142,6 @@ } -static void closePipeEnd(int* pipefd, int idx) { - if (pipefd[idx] >= 0) { - close(pipefd[idx]); - pipefd[idx] = -1; - } -} - static void initJvmlLauncherDataPointers(void* baseAddress, JvmlLauncherData* jvmLauncherData) { diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -23,16 +23,16 @@ * questions. */ -#include #include -#include #include #include #include #include #include +#include #include "JvmLauncher.h" #include "LinuxPackage.h" +#include "ExecCommand.h" static char* getModulePath(void) { @@ -56,19 +56,9 @@ } -# define PACKAGE_TYPE_UNKNOWN 0 -# define PACKAGE_TYPE_RPM 1 -# define PACKAGE_TYPE_DEB 2 - -typedef struct { - char* name; - int type; -} PackageDesc; - - static void freePackageDesc(PackageDesc* desc) { if (desc) { - free(desc->name); + free((void*)desc->name); free(desc); } } @@ -91,116 +81,73 @@ } -static PackageDesc* initPackageDesc(PackageDesc* desc, const char* str, - int type) { +static bool initPackageDesc(PackageDesc* desc, const char* str, int type) { char *newStr = strdup(str); if (!newStr) { JP_LOG_ERRNO; - return 0; + return false; } - free(desc->name); + free((void*)desc->name); desc->name = newStr; desc->type = type; - return desc; + return true; } -#define POPEN_CALLBACK_USE 1 -#define POPEN_CALLBACK_IGNORE 0 +static JvmLauncherDesc* createJvmLauncherDesc(void) { + JvmLauncherDesc* result = 0; -typedef int (*popenCallbackType)(void*, const char*); - -static int popenCommand(const char* cmdlineFormat, const char* arg, - popenCallbackType callback, void* callbackData) { - char* cmdline = 0; - FILE *stream = 0; - const size_t cmdlineLenth = strlen(cmdlineFormat) + strlen(arg); - char* strBufBegin = 0; - char* strBufEnd = 0; - char* strBufNextChar = 0; - char* strNewBufBegin = 0; - size_t strBufCapacity = 0; - int callbackMode = POPEN_CALLBACK_USE; - int exitCode = -1; - int c; - ptrdiff_t char_offset; - - cmdline = malloc(cmdlineLenth + 1 /* \0 */); - if (!cmdline) { - JP_LOG_ERRNO; - goto cleanup; - } - -#if defined(__GNUC__) && __GNUC__ >= 5 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif - if (0 > snprintf(cmdline, cmdlineLenth, cmdlineFormat, arg)) { + result = malloc(sizeof(JvmLauncherDesc)); + if (!result) { JP_LOG_ERRNO; goto cleanup; } -#if defined(__GNUC__) && __GNUC__ >= 5 -#pragma GCC diagnostic pop -#endif - JP_LOG_TRACE("popen: (%s)", cmdline); + result->packageType = PACKAGE_TYPE_UNKNOWN; + result->packageName = NULL; + result->jvmLauncherLibPath = NULL; - stream = popen(cmdline, "r"); - if (!stream) { - JP_LOG_ERRNO; - goto cleanup; - } +cleanup: + return result; +} - for (;;) { - c = fgetc(stream); - if((EOF == c || '\n' == c)) { - if (POPEN_CALLBACK_USE == callbackMode - && strBufBegin != strBufNextChar) { - *strBufNextChar = 0; - JP_LOG_TRACE("popen: [%s]", strBufBegin); - callbackMode = (*callback)(callbackData, strBufBegin); - strBufNextChar = strBufBegin; - } - - if (EOF == c) { - break; - } - continue; - } +static bool initJvmLauncherDesc( + JvmLauncherDesc* desc, + const PackageDesc* packageDesc, + const char* jvmLauncherLibPath) { - if (strBufNextChar == strBufEnd) { - /* Double buffer size */ - strBufCapacity = strBufCapacity * 2 + 1; - char_offset = strBufNextChar - strBufBegin; - strNewBufBegin = realloc(strBufBegin, strBufCapacity); - if (!strNewBufBegin) { - JP_LOG_ERRNO; - goto cleanup; - } - - strBufNextChar = strNewBufBegin + char_offset; - strBufEnd = strNewBufBegin + strBufCapacity; - strBufBegin = strNewBufBegin; - } + char* newJvmLauncherLibPath = NULL; + char* newPackageName = NULL; - *strBufNextChar++ = (char)c; + newJvmLauncherLibPath = strdup(jvmLauncherLibPath); + if (!newJvmLauncherLibPath) { + JP_LOG_ERRNO; + return false; } -cleanup: - if (stream) { - exitCode = pclose(stream); + if (packageDesc && packageDesc->name) { + newPackageName = strdup(packageDesc->name); + if (!newPackageName) { + JP_LOG_ERRNO; + free(newJvmLauncherLibPath); + return false; + } } - if (strBufBegin) { - free(strBufBegin); - } + free((void*)desc->packageName); + free((void*)desc->jvmLauncherLibPath); - free(cmdline); + desc->packageName = newPackageName; + if (packageDesc) { + desc->packageType = packageDesc->type; + } else { + desc->packageType = PACKAGE_TYPE_UNKNOWN; + } + desc->jvmLauncherLibPath = newJvmLauncherLibPath; - JP_LOG_TRACE("popen: exit: %d", exitCode); - return exitCode; + return true; } @@ -220,25 +167,32 @@ } -static int initRpmPackage(void* desc, const char* str) { - initPackageDesc((PackageDesc*)desc, str, PACKAGE_TYPE_RPM); - return POPEN_CALLBACK_IGNORE; +static int initRpmPackage(void* desc, char* str) { + if (initPackageDesc((PackageDesc*)desc, str, PACKAGE_TYPE_RPM)) { + return EXEC_CALLBACK_IGNORE; + } else { + return EXEC_CALLBACK_ERROR; + } } -static int initDebPackage(void* desc, const char* str) { +static int initDebPackage(void* desc, char* str) { char* colonChrPos = strchr(str, ':'); if (colonChrPos) { *colonChrPos = 0; } - initPackageDesc((PackageDesc*)desc, str, PACKAGE_TYPE_DEB); - return POPEN_CALLBACK_IGNORE; + + if (initPackageDesc((PackageDesc*)desc, str, PACKAGE_TYPE_DEB)) { + return EXEC_CALLBACK_IGNORE; + } else { + return EXEC_CALLBACK_ERROR; + } } #define LAUNCHER_LIB_NAME "/libapplauncher.so" -static int findLauncherLib(void* launcherLibPath, const char* str) { +static int findLauncherLib(void* launcherLibPath, char* str) { char* buf = 0; const size_t strLen = strlen(str); const size_t launcherLibNameLen = strlen(LAUNCHER_LIB_NAME); @@ -248,34 +202,38 @@ buf = strdup(str); if (!buf) { JP_LOG_ERRNO; + return EXEC_CALLBACK_ERROR; } else { *(char**)launcherLibPath = buf; } - return POPEN_CALLBACK_IGNORE; + return EXEC_CALLBACK_IGNORE; } - return POPEN_CALLBACK_USE; + return EXEC_CALLBACK_USE; } static PackageDesc* findOwnerOfFile(const char* path) { - int popenStatus = -1; + int execStatus = -1; PackageDesc* pkg = 0; + const char* rpmOwner[] = { + "rpm", "--queryformat", "%{NAME}", "-qf", path, NULL + }; + const char* debOwner[] = { + "dpkg", "-S", path, NULL + }; pkg = createPackageDesc(); if (!pkg) { return 0; } - popenStatus = popenCommand( - "rpm --queryformat '%{NAME}' -qf '%s' 2>/dev/null", path, - initRpmPackage, pkg); - if (popenStatus) { + execStatus = execCommand(rpmOwner, initRpmPackage, pkg); + if (execStatus) { pkg->type = PACKAGE_TYPE_UNKNOWN; - popenStatus = popenCommand("dpkg -S '%s' 2>/dev/null", path, - initDebPackage, pkg); + execStatus = execCommand(debOwner, initDebPackage, pkg); } - if (popenStatus) { + if (execStatus) { pkg->type = PACKAGE_TYPE_UNKNOWN; } @@ -292,13 +250,25 @@ } -char* getJvmLauncherLibPath(void) { +void freeJvmLauncherDesc(JvmLauncherDesc* desc) { + if (desc) { + free((void*)desc->packageName); + free((void*)desc->jvmLauncherLibPath); + free(desc); + } +} + + +JvmLauncherDesc* getJvmLauncherDesc(void) { char* modulePath = 0; char* appImageDir = 0; char* launcherLibPath = 0; - const char* pkgQueryCmd = 0; - int popenStatus = -1; + const char* pkgQueryCmd[] = { + NULL, NULL, NULL, NULL + }; PackageDesc* pkg = 0; + JvmLauncherDesc* result = 0; + bool resultReady = false; modulePath = getModulePath(); if (!modulePath) { @@ -314,27 +284,45 @@ launcherLibPath = concat(appImageDir, "/lib" LAUNCHER_LIB_NAME); } else { if (PACKAGE_TYPE_RPM == pkg->type) { - pkgQueryCmd = "rpm -ql '%s' 2>/dev/null"; + pkgQueryCmd[0] = "rpm"; + pkgQueryCmd[1] = "-ql"; + pkgQueryCmd[2] = pkg->name; } else if (PACKAGE_TYPE_DEB == pkg->type) { - pkgQueryCmd = "dpkg -L '%s' 2>/dev/null"; + pkgQueryCmd[0] = "dpkg"; + pkgQueryCmd[1] = "-L"; + pkgQueryCmd[2] = pkg->name; } else { /* Should never happen */ JP_LOG_ERRMSG("Internal error"); goto cleanup; } - popenStatus = popenCommand(pkgQueryCmd, pkg->name, findLauncherLib, - &launcherLibPath); - if (popenStatus) { - free(launcherLibPath); - launcherLibPath = NULL; + if (execCommand(pkgQueryCmd, findLauncherLib, &launcherLibPath)) { goto cleanup; } } + if (!launcherLibPath) { + goto cleanup; + } + + result = createJvmLauncherDesc(); + if (result && initJvmLauncherDesc(result, pkg, launcherLibPath)) { + JP_LOG_TRACE("JvmLauncherDesc(%s|%d|%s)", + result->packageName ? result->packageName : "(null)", + result->packageType, + result->jvmLauncherLibPath); + resultReady = true; + } + cleanup: free(modulePath); freePackageDesc(pkg); + if (!resultReady) { + freeJvmLauncherDesc(result); + result = NULL; + } + free(launcherLibPath); - return launcherLibPath; + return result; } diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.h openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.h --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.h 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.h 2026-10-19 12:10:20.000000000 +0000 @@ -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,7 +30,24 @@ extern "C" { #endif -char* getJvmLauncherLibPath(void); +#define PACKAGE_TYPE_UNKNOWN 0 +#define PACKAGE_TYPE_RPM 1 +#define PACKAGE_TYPE_DEB 2 + +typedef struct { + const char* name; + int type; +} PackageDesc; + +typedef struct { + const char* packageName; + int packageType; + const char* jvmLauncherLibPath; +} JvmLauncherDesc; + +void freeJvmLauncherDesc(JvmLauncherDesc* desc); + +JvmLauncherDesc* getJvmLauncherDesc(void); #ifdef __cplusplus } diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/libapplauncher/Executor.cpp openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Executor.cpp --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/libapplauncher/Executor.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Executor.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -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,49 +23,36 @@ * questions. */ -#include -#include #include "Executor.h" -#include "Log.h" #include "ErrorHandling.h" +#include "ExecCommand.h" -int executeCommandLineAndReadStdout(const std::string& cmd, - CommandOutputConsumer& consumer) { - FILE * stream = popen(cmd.c_str(), "r"); - if (!stream) { - JP_THROW(tstrings::any() << "popen(" << cmd - << ") failed. Error: " << lastCRTError()); +namespace { + +int callbackAdapter(void* callback, char* str) { + JP_TRY; + if (reinterpret_cast(callback)->accept(str)) { + return EXEC_CALLBACK_IGNORE; + } else { + return EXEC_CALLBACK_USE; } + JP_CATCH_ALL; + return EXEC_CALLBACK_ERROR; +} - LOG_TRACE(tstrings::any() << "Reading output of [" << cmd << "] command"); +} // namespace - try { - bool useConsumer = true; - std::string buf; - for (;;) { - const int c = fgetc(stream); - if(c == EOF) { - if (useConsumer && !buf.empty()) { - LOG_TRACE(tstrings::any() << "Next line: [" << buf << "]"); - consumer.accept(buf); - } - break; - } - - if (c == '\n' && useConsumer) { - LOG_TRACE(tstrings::any() << "Next line: [" << buf << "]"); - useConsumer = !consumer.accept(buf); - buf.clear(); - } else { - buf.push_back(static_cast(c)); - } - } - return pclose(stream); - } catch (...) { - if (stream) { - pclose(stream); - } - throw; +int executeCommandLineAndReadStdout(const tstring_array& cmd, + CommandOutputConsumer& consumer) { + + std::vector argv; + tstring_array::const_iterator it = cmd.begin(); + tstring_array::const_iterator end = cmd.end(); + for (; it != end; ++it) { + argv.push_back(it->c_str()); } + argv.push_back(NULL); + + return execCommand(argv.data(), callbackAdapter, &consumer); } diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/libapplauncher/Executor.h openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Executor.h --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/libapplauncher/Executor.h 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Executor.h 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -38,7 +38,7 @@ }; }; -int executeCommandLineAndReadStdout(const std::string& cmd, +int executeCommandLineAndReadStdout(const tstring_array& cmd, CommandOutputConsumer& consumer); #endif // #ifndef EXECUTOR_H diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/libapplauncher/LinuxLauncherLib.cpp openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/LinuxLauncherLib.cpp --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/libapplauncher/LinuxLauncherLib.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/LinuxLauncherLib.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -45,11 +45,16 @@ } Jvm* jvmLauncher; +PackageDesc pkgDesc = {}; void launchApp() { const tstring launcherPath = SysInfo::getProcessModulePath(); - const Package ownerPackage = Package::findOwnerOfFile(launcherPath); + LOG_TRACE(tstrings::any() << "PackageDesc(" + << (pkgDesc.name ? pkgDesc.name : "(null)") + << "|" << pkgDesc.type << ")"); + + const Package ownerPackage = Package(pkgDesc); AppLauncher appLauncher; appLauncher.addJvmLibName(_T("lib/libjli.so")); @@ -100,12 +105,12 @@ tistringstream iss(launchInfo); iss.exceptions(std::ios::failbit | std::ios::badbit); - size_t hash = 0; - iss >> hash; + size_t launchInfoHash = 0; + iss >> launchInfoHash; launchInfo = ""; - if (thisHash != hash) { + if (thisHash != launchInfoHash) { // This launcher execution is the result of execve() call from // within JVM. // This means all JVM arguments are already configured in launcher @@ -133,10 +138,15 @@ extern "C" { -JNIEXPORT JvmlLauncherHandle jvmLauncherCreate(int argc, char *argv[]) { +JNIEXPORT JvmlLauncherHandle jvmLauncherCreate( + const PackageDesc* pkg, + int argc, + char* argv[]) { + SysInfo::argc = argc; SysInfo::argv = argv; jvmLauncher = 0; + pkgDesc = *pkg; app::launch(std::nothrow, launchApp); JvmlLauncherHandle jlh = 0; diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/libapplauncher/Package.cpp openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Package.cpp --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/libapplauncher/Package.cpp 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Package.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -33,67 +33,9 @@ } -namespace { -class FirstLineConsumer : public CommandOutputConsumer { -public: - FirstLineConsumer(): processed(false) { - } - - virtual bool accept(const std::string& line) { - if (!processed) { - value = line; - processed = true; - } - return processed; - }; - - std::string getValue() const { - if (!processed) { - JP_THROW("No output captured"); - } - return value; - } - -private: - bool processed; - std::string value; -}; - - -std::string findOwnerOfFile(const std::nothrow_t&, const std::string& cmdline, - const std::string& path) { - try { - FirstLineConsumer consumer; - int exitCode = executeCommandLineAndReadStdout( - cmdline + " \'" + path + "\' 2>/dev/null", consumer); - if (exitCode == 0) { - return consumer.getValue(); - } - } catch (...) { - } - return ""; -} - -} // namespace - -Package Package::findOwnerOfFile(const std::string& path) { - Package result; - result.theName = ::findOwnerOfFile(std::nothrow, - "rpm --queryformat '%{NAME}' -qf", path); - if (!result.theName.empty()) { - result.type = RPM; - } else { - tstring_array components = tstrings::split(::findOwnerOfFile( - std::nothrow, "dpkg -S", path), ":"); - if (!components.empty()) { - result.theName = components.front(); - if (!result.theName.empty()) { - result.type = DEB; - } - } - } - - return result; +Package::Package(const PackageDesc& desc): + type(static_cast(desc.type)), + theName(desc.name ? desc.name : "") { } @@ -119,7 +61,7 @@ return !appDir.empty() && !runtimeDir.empty(); }; - void apply(AppLauncher& launcher) { + void apply(AppLauncher& launcher) const { launcher.setDefaultRuntimePath(runtimeDir); launcher.setAppDir(appDir); } @@ -136,10 +78,10 @@ int exitCode = -1; if (type == RPM) { exitCode = executeCommandLineAndReadStdout( - "rpm -ql \'" + theName + "\'", consumer); + { "rpm", "-ql", theName }, consumer); } else if (type == DEB) { exitCode = executeCommandLineAndReadStdout( - "dpkg -L \'" + theName + "\'", consumer); + { "dpkg", "-L", theName }, consumer); } if (exitCode == 0) { diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/libapplauncher/Package.h openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Package.h --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/linux/native/libapplauncher/Package.h 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/linux/native/libapplauncher/Package.h 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -28,6 +28,7 @@ #include "tstrings.h" +#include "LinuxPackage.h" class AppLauncher; @@ -37,16 +38,20 @@ public: Package(); - std::string name() const { + explicit Package(const PackageDesc& desc); + + const std::string& name() const { return theName; } void initAppLauncher(AppLauncher& appLauncher) const; - static Package findOwnerOfFile(const std::string& path); - private: - enum Type { Unknown, RPM, DEB }; + enum Type { + Unknown = PACKAGE_TYPE_UNKNOWN, + RPM = PACKAGE_TYPE_RPM, + DEB = PACKAGE_TYPE_DEB + }; Type type; std::string theName; diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/share/native/applauncher/JvmLauncher.h openjdk-25-25.0.5+8/src/jdk.jpackage/share/native/applauncher/JvmLauncher.h --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/share/native/applauncher/JvmLauncher.h 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/share/native/applauncher/JvmLauncher.h 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -86,11 +86,11 @@ JvmlLauncherHandle h, int* size); int jvmLauncherStartJvm(JvmlLauncherData* jvmArgs, void* JLI_Launch); -void jvmLauncherLog(const char* format, ...); +void jvmLauncherLog(const char* file, int line, const char* format, ...); -#define JP_LOG_ERRMSG(msg) do { jvmLauncherLog((msg)); } while (0) +#define JP_LOG_ERRMSG(msg) do { jvmLauncherLog(__FILE__, __LINE__, (msg)); } while (0) #define JP_LOG_ERRNO JP_LOG_ERRMSG(strerror(errno)) -#define JP_LOG_TRACE jvmLauncherLog +#define JP_LOG_TRACE(format, ...) jvmLauncherLog(__FILE__, __LINE__, format, ##__VA_ARGS__) #ifdef __cplusplus diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jpackage/share/native/applauncher/JvmLauncherLib.c openjdk-25-25.0.5+8/src/jdk.jpackage/share/native/applauncher/JvmLauncherLib.c --- openjdk-25-25.0.4.1+1/src/jdk.jpackage/share/native/applauncher/JvmLauncherLib.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jpackage/share/native/applauncher/JvmLauncherLib.c 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -98,6 +98,27 @@ } +static const char* filename(const char* path) { + const char* slash = strrchr(path, '/'); +#ifdef _WIN32 + const char* backslash = strrchr(path, '\\'); +#else + const char* backslash = NULL; +#endif + const char* sep; + + if (slash == NULL) { + sep = backslash; + } else if (backslash == NULL) { + sep = slash; + } else { + sep = slash > backslash ? slash : backslash; + } + + return sep ? sep + 1 : path; +} + + int jvmLauncherStartJvm(JvmlLauncherData* jvmArgs, void* JLI_Launch) { int i; int exitCode; @@ -135,7 +156,7 @@ } -void jvmLauncherLog(const char* format, ...) { +void jvmLauncherLog(const char* file, int line, const char* format, ...) { const char *withLog = getenv("JPACKAGE_DEBUG"); if (!withLog || strcmp(withLog, "true")) { return; @@ -151,6 +172,7 @@ #ifdef LINUX fprintf(stderr, "[%d]: ", getpid()); #endif + fprintf(stderr, "%s:%d: ", filename(file), line); vfprintf(stderr, format, args); fprintf(stderr, "\n"); #if defined(__GNUC__) && __GNUC__ >= 5 diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java --- openjdk-25-25.0.4.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Consumer; import com.sun.jdi.BooleanValue; import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.Field; @@ -48,8 +47,12 @@ import com.sun.jdi.VMDisconnectedException; import com.sun.jdi.VirtualMachine; import java.io.PrintStream; +import java.security.SecureRandom; import java.time.Duration; +import java.util.Arrays; +import java.util.Base64; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import jdk.jshell.JShellConsole; import jdk.jshell.execution.JdiDefaultExecutionControl.JdiStarter.TargetDescription; import jdk.jshell.spi.ExecutionControl; @@ -103,6 +106,7 @@ * @throws IOException if there are errors in set-up */ static ExecutionControl create(ExecutionEnv env, Map parameters, String remoteAgent, int timeout, JdiStarter starter) throws IOException { + Process processToStop = null; try (final ServerSocket listener = new ServerSocket(0, 1, InetAddress.getLoopbackAddress())) { // timeout on I/O-socket listener.setSoTimeout(timeout); @@ -146,15 +150,30 @@ }; // Set-up the JDI connection - TargetDescription target = starter.start(augmentedEnv, parameters, port); + TargetDescription target = starter.start(augmentedEnv, parameters, -1); VirtualMachine vm = target.vm(); - Process process = target.process(); + Process process = processToStop = target.process(); + byte[] secret; + + OutputStream stdout = process.getOutputStream(); + + //send the port number: + stdout.write(("" + port + "\n").getBytes()); + stdout.flush(); + + //generate a secret that will help us validate the correct remote is attached: + secret = new byte[64]; + new SecureRandom().nextBytes(secret); + stdout.write((Base64.getEncoder().encodeToString(secret) + "\n").getBytes()); + stdout.flush(); + + CompletableFuture agentStopped = new CompletableFuture<>(); - List> deathListeners = new ArrayList<>(); Util.detectJdiExitEvent(vm, s -> { - for (Consumer h : deathListeners) { - h.accept(s); - } + agentStopped.complete(s); + }); + process.onExit().thenRun(() -> { + agentStopped.complete("Remote process died."); }); // Set-up the commands/reslts on the socket. Piggy-back snippet @@ -162,6 +181,19 @@ Socket socket = listener.accept(); // out before in -- match remote creation so we don't hang OutputStream out = socket.getOutputStream(); + InputStream in = socket.getInputStream(); + + socket.setSoTimeout(timeout); + + //verify the secret: + byte[] receivedSecret = in.readNBytes(secret.length); + + if (!Arrays.equals(secret, receivedSecret)) { + throw new IOException("Incorrect secret received."); + } + + socket.setSoTimeout(0); + Map outputs = new HashMap<>(); outputs.put("out", env.userOut()); outputs.put("err", env.userErr()); @@ -176,10 +208,17 @@ outputs.put("consoleInput", consoleOutput); input.put("consoleOutput", consoleOutput.sinkInput); } - return remoteInputOutput(socket.getInputStream(), out, outputs, input, + ExecutionControl result = remoteInputOutput(in, out, outputs, input, (objIn, objOut) -> new JdiDefaultExecutionControl(env, - objOut, objIn, vm, process, remoteAgent, deathListeners)); - } + objOut, objIn, vm, process, remoteAgent, + agentStopped)); + processToStop = null; + return result; + } finally { + if (processToStop != null) { + processToStop.destroy(); + } +} } /** @@ -191,7 +230,7 @@ private JdiDefaultExecutionControl(ExecutionEnv env, ObjectOutput cmdout, ObjectInput cmdin, VirtualMachine vm, Process process, String remoteAgent, - List> deathListeners) { + CompletableFuture agentStopped) { super(cmdout, cmdin); this.vm = vm; this.process = process; @@ -199,8 +238,10 @@ // We have now succeeded in establishing the connection. // If there is an exit now it propagates all the way up // and the VM should be disposed of. - deathListeners.add(s -> env.closeDown()); - deathListeners.add(s -> disposeVM()); + agentStopped.thenAccept(s -> { + env.closeDown(); + disposeVM(); + }); } /** @@ -356,7 +397,7 @@ * * @param env the execution context * @param parameters additional execution parameters - * @param port the port to which the remote process should connect + * @param port the value is always {@code -1} * @return a description of the started external process * @throws RuntimeException if the process cannot be started * @throws Error if the process cannot be started diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java --- openjdk-25-25.0.4.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -216,6 +216,7 @@ ProcessBuilder pb = new ProcessBuilder(args); pb.redirectError(crashErrorFile); pb.redirectOutput(crashOutputFile); + pb.redirectInput(ProcessBuilder.Redirect.PIPE); process = pb.start(); setupVM.processStarted(process); diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java --- openjdk-25-25.0.4.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java 2026-10-19 12:10:20.000000000 +0000 @@ -24,6 +24,7 @@ */ package jdk.jshell.execution; +import java.io.ByteArrayInputStream; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.reflect.Field; @@ -34,6 +35,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassHierarchyResolver; import java.lang.classfile.ClassTransform; import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; @@ -85,9 +87,7 @@ @Override public void load(ClassBytecodes[] cbcs) throws ClassInstallException, NotImplementedException, EngineTerminationException { - super.load(Stream.of(cbcs) - .map(cbc -> new ClassBytecodes(cbc.name(), instrument(cbc.bytecodes()))) - .toArray(ClassBytecodes[]::new)); + super.load(instrument(cbcs)); } private static final String CANCEL_CLASS = "REPL.$Cancel$"; @@ -95,8 +95,26 @@ private static final String STOP_CHECK = "stopCheck"; private static final ClassDesc CD_ThreadDeath = ClassDesc.of("java.lang.ThreadDeath"); - private static byte[] instrument(byte[] classFile) { - var cc = ClassFile.of(); + private static ClassBytecodes[] instrument(ClassBytecodes[] cbcs) { + var cc = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of( + ClassHierarchyResolver.defaultResolver().orElse( + ClassHierarchyResolver.ofResourceParsing(cd -> { + String cName = cd.descriptorString(); + cName = cName.substring(1, cName.length() - 1).replace('/', '.'); + for (ClassBytecodes cbc : cbcs) { + if (cName.equals(cbc.name())) { + return new ByteArrayInputStream(cbc.bytecodes()); + } + } + return null; + })))); + + return Stream.of(cbcs) + .map(cbc -> new ClassBytecodes(cbc.name(), instrument(cc, cbc.bytecodes()))) + .toArray(ClassBytecodes[]::new); + } + + private static byte[] instrument(ClassFile cc, byte[] classFile) { return cc.transformClass(cc.parse(classFile), ClassTransform.transformingMethodBodies( CodeTransform.ofStateful(StopCheckWeaver::new))); diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java --- openjdk-25-25.0.4.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, 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,11 +24,15 @@ */ package jdk.jshell.execution; +import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; +import java.io.Reader; import java.lang.reflect.Method; import java.net.Socket; +import java.util.Base64; import java.util.HashMap; import java.util.Map; @@ -45,6 +49,12 @@ * {@link DirectExecutionControl} which adds stop support controlled by * an external process. Designed to work with {@link JdiDefaultExecutionControl}. * + *

    The initial handshake with {@link JdiDefaultExecutionControl} is as follows: + * the first command line argument is {@code -1}. The port number to which the + * agent should connect is passed on the first line on stdin. On the second line + * of stdin, an Base64-encoded byte array is sent, which should be sent to + * the socket immediately after the connection is established. + * * @author Jan Lahoda * @author Robert Field * @since 9 @@ -61,9 +71,24 @@ */ public static void main(String[] args) throws Exception { String loopBack = null; - Socket socket = new Socket(loopBack, Integer.parseInt(args[0])); + int commandLinePort = Integer.parseInt(args[0]); + int port; + byte[] secret; + if (commandLinePort == (-1)) { + Reader r = new InputStreamReader(System.in); + port = Integer.parseInt(readLine(r)); + secret = Base64.getDecoder().decode(readLine(r)); + } else { + port = commandLinePort; + secret = null; + } + Socket socket = new Socket(loopBack, port); InputStream inStream = socket.getInputStream(); OutputStream outStream = socket.getOutputStream(); + if (secret != null) { + outStream.write(secret); + outStream.flush(); + } Map> outputs = new HashMap<>(); outputs.put("out", st -> System.setOut(new PrintStream(st, true, System.out.charset()))); outputs.put("err", st -> System.setErr(new PrintStream(st, true, System.err.charset()))); @@ -74,6 +99,17 @@ forwardExecutionControlAndIO(new RemoteExecutionControl(), inStream, outStream, outputs, input); } + private static String readLine(Reader r) throws IOException { + StringBuilder line = new StringBuilder(); + int read; + + while ((read = r.read()) != (-1) && read != '\n') { + line.append((char)read); + } + + return line.toString(); + } + // These three variables are used by the main JShell process in interrupting // the running process. Access is via JDI, so the reference is not visible // to code inspection. diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java --- openjdk-25-25.0.4.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java 2026-10-19 12:10:20.000000000 +0000 @@ -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,6 +27,8 @@ import java.io.EOFException; import java.io.IOException; import java.io.ObjectInput; +import java.io.ObjectInputFilter; +import java.io.ObjectInputStream; import java.io.ObjectOutput; import jdk.jshell.JShellException; import jdk.jshell.spi.ExecutionControl; @@ -45,16 +47,23 @@ private final ObjectOutput out; private final ObjectInput in; + private final ObjectInputFilterImpl filter = new ObjectInputFilterImpl(); /** * Creates an instance. * * @param out the output for commands - * @param in the input for command responses + * @param in the input for command responses; must be an {@link ObjectInputStream} + * @throws IllegalArgumentException if {@code in} is not an {@linkplain ObjectInputStream} */ public StreamingExecutionControl(ObjectOutput out, ObjectInput in) { this.out = out; this.in = in; + if (in instanceof ObjectInputStream ois) { + ois.setObjectInputFilter(filter); + } else { + throw new IllegalArgumentException("The 'in' parameter must be an ObjectInputStream."); + } } @Override @@ -162,27 +171,16 @@ } /** - * @throws ExecutionControl.UserException {@inheritDoc} - * @throws ExecutionControl.ResolutionException {@inheritDoc} - * @throws ExecutionControl.StoppedException {@inheritDoc} - * @throws ExecutionControl.EngineTerminationException {@inheritDoc} - * @throws ExecutionControl.NotImplementedException {@inheritDoc} + * {@inheritDoc} + * + * @apiNote This method always throws {@link NotImplementedException}. + * + * @throws ExecutionControl.NotImplementedException always thrown. */ @Override public Object extensionCommand(String command, Object arg) - throws RunException, EngineTerminationException, InternalException { - try { - writeCommand(command); - out.writeObject(arg); - out.flush(); - // Retrieve and report results from the remote agent. - readAndReportExecutionResult(); - Object result = in.readObject(); - return result; - } catch (IOException | ClassNotFoundException ex) { - throw new EngineTerminationException("Exception transmitting remote extensionCommand: " - + command + " -- " + ex); - } + throws NotImplementedException { + throw new NotImplementedException("extensionCommand not implemented."); } /** @@ -379,4 +377,21 @@ StackTraceElement[] elems = (StackTraceElement[]) in.readObject(); return new ResolutionException(id, elems); } + + private static final class ObjectInputFilterImpl implements ObjectInputFilter { + + @Override + public ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo filterInfo) { + if (filterInfo.serialClass() instanceof Class clazz) { + while (clazz.isArray()) { + clazz = clazz.componentType(); + } + return clazz == StackTraceElement.class || + clazz == boolean.class ? Status.ALLOWED + : Status.REJECTED; + } + + return Status.ALLOWED; + } + } } diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java openjdk-25-25.0.5+8/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java --- openjdk-25-25.0.4.1+1/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, 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 @@ -149,10 +149,9 @@ name.append("/").append(rminame); try { - remoteHost = new RemoteHostImpl(rmiPort); ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(rmiFilterPattern); - RemoteHost stub = (RemoteHost) UnicastRemoteObject.exportObject( - remoteHost, rmiPort, filter); + remoteHost = new RemoteHostImpl(rmiPort, filter); + RemoteHost stub = (RemoteHost) UnicastRemoteObject.exportObject(remoteHost, rmiPort, filter); bind(name.toString(), stub); System.out.println("jstatd started (bound to " + name.toString() + ")"); System.out.flush(); diff -Nru openjdk-25-25.0.4.1+1/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java openjdk-25-25.0.5+8/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java --- openjdk-25-25.0.4.1+1/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -26,6 +26,7 @@ package sun.tools.jstatd; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.nio.*; import java.io.*; import java.net.*; @@ -52,13 +53,20 @@ private Set activeVms; private static RemoteVm rvm; private final int rmiPort; + private final ObjectInputFilter filter; + private final Map exportedVMs = new ConcurrentHashMap<>(); public RemoteHostImpl() throws MonitorException { this(0); } public RemoteHostImpl(int rmiPort) throws MonitorException { + this(rmiPort, null); + } + + public RemoteHostImpl(int rmiPort, ObjectInputFilter filter) throws MonitorException { this.rmiPort = rmiPort; + this.filter = filter; try { monitoredHost = MonitoredHost.getMonitoredHost("localhost"); } catch (URISyntaxException e) { } @@ -78,7 +86,8 @@ VmIdentifier vmid = new VmIdentifier(vmidStr); MonitoredVm mvm = monitoredHost.getMonitoredVm(vmid); rvm = new RemoteVmImpl((BufferedMonitoredVm)mvm); - stub = (RemoteVm) UnicastRemoteObject.exportObject(rvm, rmiPort); + stub = (RemoteVm) UnicastRemoteObject.exportObject(rvm, rmiPort, filter); + exportedVMs.put(stub, (RemoteVmImpl) rvm); } catch (URISyntaxException e) { throw new RuntimeException("Malformed VmIdentifier URI: " @@ -88,7 +97,11 @@ } public void detachVm(RemoteVm rvm) throws RemoteException { - rvm.detach(); + // Do not invoke on caller-supplied Object. + RemoteVm v = exportedVMs.remove(rvm); + if (v != null) { + v.detach(); + } } public int[] activeVms() throws MonitorException { diff -Nru openjdk-25-25.0.4.1+1/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json openjdk-25-25.0.5+8/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json --- openjdk-25-25.0.4.1+1/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json 2026-10-19 12:10:20.000000000 +0000 @@ -81,7 +81,7 @@ "owner": { "type": "string", "description": "The thread identifier of the owner when the parkBlocker is an AbstractOwnableSynchronizer." - } + }, "required": [ "object" ] diff -Nru openjdk-25-25.0.4.1+1/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java openjdk-25-25.0.5+8/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java --- openjdk-25-25.0.4.1+1/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,23 @@ package com.sun.security.auth.module; -import javax.security.auth.*; -import javax.security.auth.callback.*; -import javax.security.auth.login.*; -import javax.security.auth.spi.*; -import javax.naming.*; -import javax.naming.directory.*; +import javax.naming.InitialContext; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.BasicAttributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.SearchResult; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.FailedLoginException; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; import java.util.Map; import java.util.LinkedList; @@ -200,9 +211,8 @@ private static final String CRYPT = "{crypt}"; private static final String USER_PWD = "userPassword"; - private static final String USER_UID = "uidNumber"; - private static final String USER_GID = "gidNumber"; - private static final String GROUP_ID = "gidNumber"; + private static final String UID_NUMBER = "uidNumber"; + private static final String GID_NUMBER = "gidNumber"; private static final String NAME = "javax.security.auth.login.name"; private static final String PWD = "javax.security.auth.login.password"; @@ -381,7 +391,7 @@ */ public boolean commit() throws LoginException { - if (succeeded == false) { + if (!succeeded) { return false; } else { if (subject.isReadOnly()) { @@ -389,11 +399,11 @@ throw new LoginException ("Subject is Readonly"); } // add Principals to the Subject - if (!subject.getPrincipals().contains(userPrincipal)) + if (userPrincipal != null && !subject.getPrincipals().contains(userPrincipal)) subject.getPrincipals().add(userPrincipal); - if (!subject.getPrincipals().contains(UIDPrincipal)) + if (UIDPrincipal != null && !subject.getPrincipals().contains(UIDPrincipal)) subject.getPrincipals().add(UIDPrincipal); - if (!subject.getPrincipals().contains(GIDPrincipal)) + if (GIDPrincipal != null && !subject.getPrincipals().contains(GIDPrincipal)) subject.getPrincipals().add(GIDPrincipal); for (int i = 0; i < supplementaryGroups.size(); i++) { if (!subject.getPrincipals().contains @@ -436,9 +446,9 @@ System.out.println("\t\t[JndiLoginModule]: " + "aborted authentication failed"); - if (succeeded == false) { + if (!succeeded) { return false; - } else if (succeeded == true && commitSucceeded == false) { + } else if (!commitSucceeded) { // Clean out state succeeded = false; @@ -510,34 +520,25 @@ * @param getPasswdFromSharedState boolean that tells this method whether * to retrieve the password from the sharedState. */ - private void attemptAuthentication(boolean getPasswdFromSharedState) - throws LoginException { - + private void attemptAuthentication(boolean getPasswdFromSharedState) throws LoginException { String encryptedPassword = null; - // first get the username and password getUsernamePassword(getPasswdFromSharedState); - + if (username == null) { + throw new FailedLoginException("No username provided"); + } try { - // get the user's passwd entry from the user provider URL InitialContext iCtx = new InitialContext(); ctx = (DirContext)iCtx.lookup(userProvider); - - /* - SearchControls controls = new SearchControls - (SearchControls.ONELEVEL_SCOPE, - 0, - 5000, - new String[] { USER_PWD }, - false, - false); - */ - - SearchControls controls = new SearchControls(); - NamingEnumeration ne = ctx.search("", - "(uid=" + username + ")", - controls); + // Search for the user with the given "uid" and obtain all their attributes. + // Then verify the user's password attribute matches with the one set on + // this LoginModule + NamingEnumeration ne = ctx.search("", new BasicAttributes("uid", username)); + // Create an exception instance beforehand, to use it in the case of a failed login due + // to a missing user or due to an incorrect credential. It's OK for it to go unused + // in the case of a successful authentication. + final FailedLoginException failedLogin = new FailedLoginException("Login failed"); if (ne.hasMore()) { SearchResult result = ne.next(); Attributes attributes = result.getAttributes(); @@ -559,14 +560,17 @@ // authentication for LDAP is recommended only for secure // channels. For nonsecure channels, SSL is recommended. + final boolean passwordMatches; Attribute pwd = attributes.get(USER_PWD); - String encryptedPwd = new String((byte[])pwd.get(), UTF_8); - encryptedPassword = encryptedPwd.substring(CRYPT.length()); - - // check the password - if (verifyPassword - (encryptedPassword, new String(password)) == true) { - + if (pwd == null) { + passwordMatches = false; + } else { + String encryptedPwd = new String((byte[]) pwd.get(), UTF_8); + encryptedPassword = encryptedPwd.substring(CRYPT.length()); + // check the password + passwordMatches = verifyPassword(encryptedPassword, new String(password)); + } + if (passwordMatches) { // authentication succeeded if (debug) System.out.println("\t\t[JndiLoginModule] " + @@ -577,7 +581,7 @@ if (debug) System.out.println("\t\t[JndiLoginModule] " + "attemptAuthentication() failed"); - throw new FailedLoginException("Login incorrect"); + throw failedLogin; } // save input as shared state only if @@ -592,27 +596,36 @@ // create the user principal userPrincipal = new UnixPrincipal(username); - // get the UID - Attribute uid = attributes.get(USER_UID); - String uidNumber = (String)uid.get(); - UIDPrincipal = new UnixNumericUserPrincipal(uidNumber); - if (debug && uidNumber != null) { - System.out.println("\t\t[JndiLoginModule] " + - "user: '" + username + "' has UID: " + + // get the uidNumber + Attribute uid = attributes.get(UID_NUMBER); + if (uid == null) { + UIDPrincipal = null; + } else { + String uidNumber = (String) uid.get(); + UIDPrincipal = uidNumber == null + ? null + : new UnixNumericUserPrincipal(uidNumber); + if (debug && UIDPrincipal != null) { + System.out.println("\t\t[JndiLoginModule] " + + "user: '" + username + "' has uidNumber: " + uidNumber); + } } - // get the GID - Attribute gid = attributes.get(USER_GID); - String gidNumber = (String)gid.get(); - GIDPrincipal = new UnixNumericGroupPrincipal - (gidNumber, true); - if (debug && gidNumber != null) { - System.out.println("\t\t[JndiLoginModule] " + - "user: '" + username + "' has GID: " + + Attribute gid = attributes.get(GID_NUMBER); + if (gid == null) { + GIDPrincipal = null; + } else { + String gidNumber = (String) gid.get(); + GIDPrincipal = gidNumber == null + ? null + : new UnixNumericGroupPrincipal(gidNumber, true); + if (debug && GIDPrincipal != null) { + System.out.println("\t\t[JndiLoginModule] " + + "user: '" + username + "' has gidNumber: " + gidNumber); + } } - // get the supplementary groups from the group provider URL ctx = (DirContext)iCtx.lookup(groupProvider); ne = ctx.search("", new BasicAttributes("memberUid", username)); @@ -621,13 +634,19 @@ result = ne.next(); attributes = result.getAttributes(); - gid = attributes.get(GROUP_ID); - String suppGid = (String)gid.get(); - if (!gidNumber.equals(suppGid)) { + gid = attributes.get(GID_NUMBER); + if (gid == null) { + continue; + } + String suppGid = (String) gid.get(); + if (suppGid == null) { + continue; + } + if (GIDPrincipal == null || !GIDPrincipal.getName().equals(suppGid)) { UnixNumericGroupPrincipal suppPrincipal = new UnixNumericGroupPrincipal(suppGid, false); supplementaryGroups.add(suppPrincipal); - if (debug && suppGid != null) { + if (debug) { System.out.println("\t\t[JndiLoginModule] " + "user: '" + username + "' has Supplementary Group: " + @@ -641,17 +660,15 @@ if (debug) { System.out.println("\t\t[JndiLoginModule]: User not found"); } - throw new FailedLoginException("User not found"); + throw failedLogin; } } catch (NamingException ne) { - // bad username if (debug) { - System.out.println("\t\t[JndiLoginModule]: User not found"); + System.out.println("\t\t[JndiLoginModule]: exception when finding user"); ne.printStackTrace(); } - throw new FailedLoginException("User not found"); + throw new FailedLoginException("Login failed"); } - // authentication succeeded } diff -Nru openjdk-25-25.0.4.1+1/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java openjdk-25-25.0.5+8/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java --- openjdk-25-25.0.4.1+1/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -105,6 +105,9 @@ private static final String COMPRESSION_METHOD_DEFLATED = "DEFLATED"; // Value specified for compressionMethod property to not compress Zip entries private static final String COMPRESSION_METHOD_STORED = "STORED"; + // CEN size is limited to the maximum array size in the JDK + // See ArraysSupport.SOFT_MAX_ARRAY_LENGTH; + private static final int MAX_CEN_SIZE = Integer.MAX_VALUE - 8; private final ZipFileSystemProvider provider; private final Path zfpath; @@ -1233,7 +1236,7 @@ private volatile boolean isOpen = true; private final SeekableByteChannel ch; // channel to the zipfile - final byte[] cen; // CEN & ENDHDR + final byte[] cen; // CEN private END end; private long locpos; // position of first LOC header (usually 0) @@ -1353,7 +1356,7 @@ // to use the end64 values end.cenlen = cenlen64; end.cenoff = cenoff64; - end.centot = (int)centot64; // assume total < 2g + end.centot = centot64; end.endpos = end64pos; return end; } @@ -1575,25 +1578,36 @@ buildNodeTree(); return null; // only END header present } - if (end.cenlen > end.endpos) - throw new ZipException("invalid END header (bad central directory size)"); + // Validate END header + if (end.cenlen > end.endpos) { + zerror("invalid END header (bad central directory size)"); + } long cenpos = end.endpos - end.cenlen; // position of CEN table - // Get position of first local file (LOC) header, taking into - // account that there may be a stub prefixed to the zip file. + // account that there may be a stub prefixed to the ZIP file. locpos = cenpos - end.cenoff; - if (locpos < 0) - throw new ZipException("invalid END header (bad central directory offset)"); - - // read in the CEN and END - byte[] cen = new byte[(int)(end.cenlen + ENDHDR)]; - if (readNBytesAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) { - throw new ZipException("read CEN tables failed"); + if (locpos < 0) { + zerror("invalid END header (bad central directory offset)"); + } + if (end.cenlen > MAX_CEN_SIZE) { + zerror("invalid END header (central directory size too large)"); + } + if (end.centot < 0 || end.centot > end.cenlen / CENHDR) { + zerror("invalid END header (total entries count too large)"); + } + // Validation ensures these are <= Integer.MAX_VALUE + int cenlen = Math.toIntExact(end.cenlen); + int centot = Math.toIntExact(end.centot); + + // read in the CEN + byte[] cen = new byte[cenlen]; + if (readNBytesAt(cen, 0, cen.length, cenpos) != cenlen) { + zerror("read CEN tables failed"); } // Iterate through the entries in the central directory - inodes = LinkedHashMap.newLinkedHashMap(end.centot + 1); + inodes = LinkedHashMap.newLinkedHashMap(centot + 1); int pos = 0; - int limit = cen.length - ENDHDR; + int limit = cen.length; while (pos < limit) { if (!cenSigAt(cen, pos)) throw new ZipException("invalid CEN header (bad signature)"); @@ -1641,7 +1655,7 @@ // skip ext and comment pos += (CENHDR + nlen + elen + clen); } - if (pos + ENDHDR != cen.length) { + if (pos != cen.length) { throw new ZipException("invalid CEN header (bad header size)"); } buildNodeTree(); @@ -1671,7 +1685,7 @@ } // CEN Offset where this Extra field ends int extraEndOffset = startingOffset + extraFieldLen; - if (extraEndOffset > cen.length - ENDHDR) { + if (extraEndOffset > cen.length) { zerror("Invalid CEN header (extra data field size too long)"); } int currentOffset = startingOffset; @@ -2666,7 +2680,7 @@ // int disknum; // int sdisknum; // int endsub; - int centot; // 4 bytes + long centot; // 4 bytes long cenlen; // 4 bytes long cenoff; // 4 bytes // int comlen; // comment length @@ -2689,7 +2703,7 @@ xoff = ZIP64_MINVAL; hasZip64 = true; } - int count = centot; + int count = Math.toIntExact(centot); if (count >= ZIP64_MINVAL32) { count = ZIP64_MINVAL32; hasZip64 = true; diff -Nru openjdk-25-25.0.4.1+1/test/docs/TEST.ROOT openjdk-25-25.0.5+8/test/docs/TEST.ROOT --- openjdk-25-25.0.4.1+1/test/docs/TEST.ROOT 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/docs/TEST.ROOT 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -38,7 +38,7 @@ groups=TEST.groups # Minimum jtreg version -requiredVersion=8+2 +requiredVersion=8.2.1+1 # Use new module options useNewOptions=true diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/TEST.ROOT openjdk-25-25.0.5+8/test/hotspot/jtreg/TEST.ROOT --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/TEST.ROOT 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/TEST.ROOT 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -104,7 +104,7 @@ jdk.static # Minimum jtreg version -requiredVersion=8+2 +requiredVersion=8.2.1+1 # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../../ notation to reach them diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/TEST.groups openjdk-25-25.0.5+8/test/hotspot/jtreg/TEST.groups --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/TEST.groups 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/TEST.groups 2026-10-19 12:10:20.000000000 +0000 @@ -320,7 +320,8 @@ gc/shenandoah/compiler/ \ gc/shenandoah/mxbeans/ \ gc/shenandoah/TestSmallHeap.java \ - gc/shenandoah/oom/ + gc/shenandoah/oom/ \ + gtest/ShenandoahGtests.java tier2_gc_shenandoah = \ runtime/MemberName/MemberNameLeak.java \ diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/arraycopy/TestDeadCloneMem.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/arraycopy/TestDeadCloneMem.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/arraycopy/TestDeadCloneMem.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/arraycopy/TestDeadCloneMem.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * 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 JDK-8387015 + * @summary C2: crash with "named projection 2 not found" from ArrayCopyNode::finish_transform() for clone + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:CompileOnly=${test.main.class}::test1 + * -XX:CompileCommand=dontinline,${test.main.class}::notInlined -XX:+StressIGVN + * -XX:StressSeed=1324432947 ${test.main.class} + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:CompileOnly=${test.main.class}::test1 + * -XX:CompileCommand=dontinline,${test.main.class}::notInlined -XX:+StressIGVN + * ${test.main.class} + */ + +package compiler.arraycopy; + +public class TestDeadCloneMem { + private static int field; + + public static void main(String[] args) { + int[] array = new int[10]; + array.clone(); + Object o = new Object(); + test1(42, false); + } + + private static int test1(int flag, boolean flag2) { + int len; + if (flag != 42) { + if (flag2) { + field = 42; + } + int[] array2; + if (flag != 42) { + len = -1; + array2 = new int[4]; + } else { + len = 42; + array2 = new int[100]; + } + int[] array = new int[len]; + int length = array.length; + int i = 0; + do { + synchronized (new Object()) {} + notInlined(); + array2.clone(); + i++; + } while (i < 10); + return length; + } + return 0; + } + + private static void notInlined() { + + } +} diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java 2026-10-19 12:10:20.000000000 +0000 @@ -84,8 +84,13 @@ } @Test - @IR(counts = { IRNode.LOOP, "1" }) - @IR(failOn = { IRNode.COUNTED_LOOP}) + // This is a negative test: the range check cannot be currently optimized + // because the index expression scale * i + offset contains short scaling + // (see PhaseIdealLoop::is_scaled_iv) and is thus not a candidate for long + // range check transformations. The two rules below verify that range check + // optimization does NOT take place. + @IR(failOn = { IRNode.LOOP}) + @IR(counts = { IRNode.COUNTED_LOOP, "1"}) public static void testStridePosScalePosInIntLoop2(int start, int stop, long length, long offset) { final int scale = 2; final int stride = 1; @@ -135,8 +140,13 @@ } @Test - @IR(counts = { IRNode.LOOP, "1" }) - @IR(failOn = { IRNode.COUNTED_LOOP}) + // This is a negative test: the range check cannot be currently optimized + // because the index expression scale * i + offset contains short scaling + // (see PhaseIdealLoop::is_scaled_iv) and is thus not a candidate for long + // range check transformations. The two rules below verify that range check + // optimization does NOT take place. + @IR(failOn = { IRNode.LOOP}) + @IR(counts = { IRNode.COUNTED_LOOP, "1"}) public static void testStrideNegScaleNegInIntLoop2(int start, int stop, long length, long offset) { final int scale = -2; final int stride = 1; @@ -184,8 +194,13 @@ } @Test - @IR(counts = { IRNode.LOOP, "1" }) - @IR(failOn = { IRNode.COUNTED_LOOP}) + // This is a negative test: the range check cannot be currently optimized + // because the index expression scale * i + offset contains short scaling + // (see PhaseIdealLoop::is_scaled_iv) and is thus not a candidate for long + // range check transformations. The two rules below verify that range check + // optimization does NOT take place. + @IR(failOn = { IRNode.LOOP}) + @IR(counts = { IRNode.COUNTED_LOOP, "1"}) public static void testStrideNegScalePosInIntLoop2(int start, int stop, long length, long offset) { final int scale = 2; final int stride = 1; @@ -232,8 +247,13 @@ } @Test - @IR(counts = { IRNode.LOOP, "1"}) - @IR(failOn = { IRNode.COUNTED_LOOP}) + // This is a negative test: the range check cannot be currently optimized + // because the index expression scale * i + offset contains short scaling + // (see PhaseIdealLoop::is_scaled_iv) and is thus not a candidate for long + // range check transformations. The two rules below verify that range check + // optimization does NOT take place. + @IR(failOn = { IRNode.LOOP}) + @IR(counts = { IRNode.COUNTED_LOOP, "1"}) public static void testStridePosScaleNegInIntLoop2(int start, int stop, long length, long offset) { final int scale = -2; final int stride = 1; diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java 2026-10-19 12:10:20.000000000 +0000 @@ -64,7 +64,7 @@ @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) public static void testByteLong1(byte[] dest, long[] src) { for (int i = 0; i < src.length; i++) { - long j = Objects.checkIndex(i * 8, (long)(src.length * 8)); + long j = Objects.checkIndex(i * 8L, (long)(src.length * 8)); UNSAFE.putLongUnaligned(dest, baseOffset + j, src[i]); } } @@ -75,6 +75,26 @@ testByteLong1(byteArray, longArray); } + // This is a negative version of the test above where C2 currently fails to + // perform range check elimination, which inhibits vectorization. + // The reason is that the i * 8 index expression is not accepted as a valid + // index for long range check transformations, see + // PhaseIdealLoop::is_scaled_iv_plus_offset. + @Test + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + public static void testNegativeByteLong1(byte[] dest, long[] src) { + for (int i = 0; i < src.length; i++) { + long j = Objects.checkIndex(i * 8, (long)(src.length * 8)); + UNSAFE.putLongUnaligned(dest, baseOffset + j, src[i]); + } + } + + @Run(test = "testNegativeByteLong1") + public static void testNegativeByteLong1_runner() { + baseOffset = UNSAFE.ARRAY_BYTE_BASE_OFFSET; + testNegativeByteLong1(byteArray, longArray); + } + @Test @IR(counts = { IRNode.LOAD_VECTOR_B, ">=1", IRNode.STORE_VECTOR, ">=1" }) public static void testLoopNest1(byte[] dest, byte[] src, diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** +* @test +* @bug 8364305 +* @summary Test scalar float/double to integral cast +* @requires vm.compiler2.enabled +* @library /test/lib / +* @run main/othervm/native compiler.floatingpoint.ScalarFPtoIntCastTest +*/ + +package compiler.floatingpoint; + +import compiler.lib.ir_framework.*; +import compiler.lib.generators.Generator; +import static compiler.lib.generators.Generators.G; +import compiler.lib.verify.Verify; + +public class ScalarFPtoIntCastTest { + private static final int COUNT = 16; + + private float[] float_arr; + private double[] double_arr; + private long[] long_float_arr; + private long[] long_double_arr; + private int[] int_float_arr; + private int[] int_double_arr; + private short[] short_float_arr; + private short[] short_double_arr; + private byte[] byte_float_arr; + private byte[] byte_double_arr; + + private static final Generator genF = G.floats(); + private static final Generator genD = G.doubles(); + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.start(); + } + + public ScalarFPtoIntCastTest() { + long_float_arr = new long[COUNT]; + long_double_arr = new long[COUNT]; + int_float_arr = new int[COUNT]; + int_double_arr = new int[COUNT]; + short_float_arr = new short[COUNT]; + short_double_arr = new short[COUNT]; + byte_float_arr = new byte[COUNT]; + byte_double_arr = new byte[COUNT]; + float_arr = new float[COUNT]; + double_arr = new double[COUNT]; + + G.fill(genF, float_arr); + G.fill(genD, double_arr); + for (int i = 0; i < COUNT; i++) { + long_float_arr[i] = (long) float_arr[i]; + long_double_arr[i] = (long) double_arr[i]; + int_float_arr[i] = (int) float_arr[i]; + int_double_arr[i] = (int) double_arr[i]; + short_float_arr[i] = (short) float_arr[i]; + short_double_arr[i] = (short) double_arr[i]; + byte_float_arr[i] = (byte) float_arr[i]; + byte_double_arr[i] = (byte) double_arr[i]; + } + } + + @Test + @IR(counts = {IRNode.CONV_F2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2int() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + int computed = (int) float_val; + int expected = int_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_F2L, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2L, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2L_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2long() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + long computed = (long) float_val; + long expected = long_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_F2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2short() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + short computed = (short) float_val; + short expected = short_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_F2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2byte() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + byte computed = (byte) float_val; + byte expected = byte_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2int() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + int computed = (int) double_val; + int expected = int_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2L, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2L, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2L_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2long() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + long computed = (long) double_val; + long expected = long_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2short() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + short computed = (short) double_val; + short expected = short_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2byte() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + byte computed = (byte) double_val; + byte expected = byte_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java 2026-10-19 12:10:20.000000000 +0000 @@ -110,7 +110,6 @@ } @Test // needs to be run in (fast) debug mode - @Warmup(10000) @IR(counts = {IRNode.UDIV_L, ">= 1"}) // At least one UDivL node is generated if intrinsic is used public void testDivideUnsigned() { for (int i = 0; i < BUFFER_SIZE; i++) { @@ -124,7 +123,6 @@ } @Test // needs to be run in (fast) debug mode - @Warmup(10000) @IR(counts = {IRNode.UMOD_L, ">= 1"}) // At least one UModL node is generated if intrinsic is used public void testRemainderUnsigned() { for (int i = 0; i < BUFFER_SIZE; i++) { @@ -139,7 +137,6 @@ @Test // needs to be run in (fast) debug mode - @Warmup(10000) @IR(applyIfPlatform = {"x64", "true"}, counts = {IRNode.UDIV_MOD_L, ">= 1"}) // At least one UDivModL node is generated if intrinsic is used public void testDivModUnsigned() { diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/intrinsics/TestReferenceGet.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/TestReferenceGet.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/intrinsics/TestReferenceGet.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/TestReferenceGet.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,175 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8382815 + * @run main/othervm -XX:CompileCommand=dontinline,${test.main.class}::test_* ${test.main.class} + */ + +package compiler.intrinsics; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.PhantomReference; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; + +public class TestReferenceGet { + private static final void fail(String msg) throws Exception { + throw new RuntimeException(msg); + } + + private static final void test0(Reference ref, + Object expectedValue, + Object unexpectedValue, + String kind) throws Exception { + if ((expectedValue != null) && ref.get() == null) { + fail(kind + " refers to null"); + } + if (ref.get() != expectedValue) { + fail(kind + " doesn't refer to expected value"); + } + if (ref.get() == unexpectedValue) { + fail(kind + " refers to unexpected value"); + } + } + + private static final void test_phantom0(PhantomReference ref, + String kind) throws Exception { + if (ref.get() != null) { + fail(kind + " does not refer to null"); + } + } + + // Entry points to the test, important to push down type information to + // individual test methods. + + private static final void test_phantom(PhantomReference ref) throws Exception { + test_phantom0(ref, "phantom"); + } + + private static final void test_phantom_shadow(ShadowPhantomReference ref) throws Exception { + test_phantom0(ref, "phantom shadow"); + } + + private static final void test_weak(WeakReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "weak"); + } + + private static final void test_weak_shadow(ShadowWeakReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "weak shadow"); + } + + private static final void test_soft(SoftReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "soft"); + } + + private static final void test_soft_shadow(ShadowSoftReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "soft shadow"); + } + + static Object unexpected = new Object(); + + static Object obj0 = new Object(); + static Object obj1 = new Object(); + static Object obj2 = new Object(); + static Object obj3 = new Object(); + static Object obj4 = new Object(); + static Object obj5 = new Object(); + + public static void main(String[] args) throws Exception { + var queue = new ReferenceQueue(); + + // It is important to do all test methods in the loop, so that we + // exercise all paths in intrinsics. + for (int i = 0; i < 100000; i++) { + System.out.println("Create"); + var pref = new PhantomReference(obj0, queue); + var wref = new WeakReference(obj1); + var sref = new SoftReference(obj2); + var psref = new ShadowPhantomReference<>(obj3, queue); + var wsref = new ShadowWeakReference<>(obj4); + var ssref = new ShadowSoftReference<>(obj5); + + System.out.println("After creation"); + test_phantom(pref); + test_weak(wref, obj1, unexpected); + test_soft(sref, obj2, unexpected); + test_phantom_shadow(psref); + test_weak_shadow(wsref, obj4, unexpected); + test_soft_shadow(ssref, obj5, unexpected); + + System.out.println("Cleaning references"); + pref.clear(); + wref.clear(); + sref.clear(); + psref.clear(); + wsref.clear(); + ssref.clear(); + + System.out.println("Testing after cleaning"); + test_phantom(pref); + test_weak(wref, null, unexpected); + test_soft(sref, null, unexpected); + test_phantom_shadow(psref); + test_weak_shadow(wsref, null, unexpected); + test_soft_shadow(ssref, null, unexpected); + } + } + + // References that have their own "shadow" referent. Check that intrinsics + // hit the right referent. + + static class ShadowSoftReference extends SoftReference { + T referent; + public ShadowSoftReference(T ref) { + super(ref); + referent = ref; + } + } + + static class ShadowWeakReference extends WeakReference { + T referent; + public ShadowWeakReference(T ref) { + super(ref); + referent = ref; + } + } + + static class ShadowPhantomReference extends PhantomReference { + T referent; + public ShadowPhantomReference(T ref, ReferenceQueue q) { + super(ref, q); + referent = ref; + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/intrinsics/TestReferenceRefersTo.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/TestReferenceRefersTo.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/intrinsics/TestReferenceRefersTo.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/TestReferenceRefersTo.java 2026-10-19 12:10:20.000000000 +0000 @@ -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,10 +23,13 @@ /* * @test - * @bug 8256377 + * @bug 8256377 8382815 * @summary Based on test/jdk/java/lang/ref/ReferenceRefersTo.java. + * @run main/othervm -XX:CompileCommand=dontinline,${test.main.class}::test_* ${test.main.class} */ +package compiler.intrinsics; + import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.PhantomReference; @@ -39,7 +42,7 @@ } // Test java.lang.ref.Reference::refersTo0 intrinsic. - private static final void test(Reference ref, + private static final void test0(Reference ref, Object expectedValue, Object unexpectedValue, String kind) throws Exception { @@ -55,10 +58,10 @@ } // Test java.lang.ref.PhantomReference::refersTo0 intrinsic. - private static final void test_phantom(PhantomReference ref, + private static final void test_phantom0(PhantomReference ref, Object expectedValue, - Object unexpectedValue) throws Exception { - String kind = "phantom"; + Object unexpectedValue, + String kind) throws Exception { if ((expectedValue != null) && ref.refersTo(null)) { fail(kind + " refers to null"); } @@ -68,53 +71,120 @@ if (ref.refersTo(unexpectedValue)) { fail(kind + " refers to unexpected value"); } + } + + // Entry points to the test, important to push down type information to + // individual test methods. + + private static final void test_phantom(PhantomReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test_phantom0(ref, expectedValue, unexpectedValue, "phantom"); + } + private static final void test_phantom_shadow(ShadowPhantomReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test_phantom0(ref, expectedValue, unexpectedValue, "phantom shadow"); } private static final void test_weak(WeakReference ref, Object expectedValue, Object unexpectedValue) throws Exception { - test(ref, expectedValue, unexpectedValue, "weak"); + test0(ref, expectedValue, unexpectedValue, "weak"); + } + + private static final void test_weak_shadow(ShadowWeakReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "weak shadow"); } private static final void test_soft(SoftReference ref, Object expectedValue, Object unexpectedValue) throws Exception { - test(ref, expectedValue, unexpectedValue, "soft"); + test0(ref, expectedValue, unexpectedValue, "soft"); } + private static final void test_soft_shadow(ShadowSoftReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "soft shadow"); + } + + static Object unexpected = new Object(); + + static Object obj0 = new Object(); + static Object obj1 = new Object(); + static Object obj2 = new Object(); + static Object obj3 = new Object(); + static Object obj4 = new Object(); + static Object obj5 = new Object(); + public static void main(String[] args) throws Exception { var queue = new ReferenceQueue(); - var obj0 = new Object(); - var obj1 = new Object(); - var obj2 = new Object(); - var obj3 = new Object(); - - var pref = new PhantomReference(obj0, queue); - var wref = new WeakReference(obj1); - var sref = new SoftReference(obj2); - - System.out.println("Warmup"); - for (int i = 0; i < 10000; i++) { - test_phantom(pref, obj0, obj3); - test_weak(wref, obj1, obj3); - test_soft(sref, obj2, obj3); - } - - System.out.println("Testing starts"); - test_phantom(pref, obj0, obj3); - test_weak(wref, obj1, obj3); - test_soft(sref, obj2, obj3); - - System.out.println("Cleaning references"); - pref.clear(); - wref.clear(); - sref.clear(); - - System.out.println("Testing after cleaning"); - test_phantom(pref, null, obj3); - test_weak(wref, null, obj3); - test_soft(sref, null, obj3); + // It is important to do all test methods in the loop, so that we + // exercise all paths in intrinsics. + for (int i = 0; i < 100000; i++) { + System.out.println("Create"); + var pref = new PhantomReference(obj0, queue); + var wref = new WeakReference(obj1); + var sref = new SoftReference(obj2); + var psref = new ShadowPhantomReference<>(obj3, queue); + var wsref = new ShadowWeakReference<>(obj4); + var ssref = new ShadowSoftReference<>(obj5); + + System.out.println("After creation"); + test_phantom(pref, obj0, unexpected); + test_weak(wref, obj1, unexpected); + test_soft(sref, obj2, unexpected); + test_phantom_shadow(psref, obj3, unexpected); + test_weak_shadow(wsref, obj4, unexpected); + test_soft_shadow(ssref, obj5, unexpected); + + System.out.println("Cleaning references"); + pref.clear(); + wref.clear(); + sref.clear(); + psref.clear(); + wsref.clear(); + ssref.clear(); + + System.out.println("Testing after cleaning"); + test_phantom(pref, null, unexpected); + test_weak(wref, null, unexpected); + test_soft(sref, null, unexpected); + test_phantom_shadow(psref, null, unexpected); + test_weak_shadow(wsref, null, unexpected); + test_soft_shadow(ssref, null, unexpected); + } + } + + // References that have their own "shadow" referent. Check that intrinsics + // hit the right referent. + + static class ShadowSoftReference extends SoftReference { + T referent; + public ShadowSoftReference(T ref) { + super(ref); + referent = ref; + } + } + + static class ShadowWeakReference extends WeakReference { + T referent; + public ShadowWeakReference(T ref) { + super(ref); + referent = ref; + } + } + + static class ShadowPhantomReference extends PhantomReference { + T referent; + public ShadowPhantomReference(T ref, ReferenceQueue q) { + super(ref, q); + referent = ref; + } } } diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2026, IBM and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package compiler.intrinsics.math; + +import jdk.test.lib.Asserts; + +import compiler.lib.ir_framework.*; +import compiler.lib.generators.*; +import static compiler.lib.generators.Generators.*; + +import java.util.Random; + +/* + * @test + * @bug 8378713 + * @key randomness + * @summary Math.pow(base, exp) should constant propagate + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class PowDNodeTests { + public static final Generator UNIFORMS = G.uniformDoubles(); // [0, 1) + + public static final double B = UNIFORMS.next() * 1000.0d; + public static final double E = UNIFORMS.next() * 1000.0d + 3.0d; // e >= 3 to avoid strength reduction code + + public static void main(String[] args) { + TestFramework.run(); + + testCorrectness(); + } + + // Test 1: pow(2.0, 10.0) -> 1024.0 + @Test + @IR(failOn = {IRNode.POW_D}) + public static double constantLiteralFolding() { + return Math.pow(2.0, 10.0); // should fold to 1024.0 + } + + // Test 2: pow(final B, final E) -> B^E + @Test + @IR(failOn = {IRNode.POW_D}) + public static double constantStaticFolding() { + return Math.pow(B, E); // should fold to B^E + } + + // Test 3: pow(b, 0.0) -> 1.0 + @Test + @IR(failOn = {IRNode.POW_D}) + @Arguments(values = {Argument.RANDOM_EACH}) + public static double expZero(double b) { + return Math.pow(b, 0.0); + } + + // Test 4: pow(b, 1.0) -> b (identity) + @Test + @IR(failOn = {IRNode.POW_D}) + @Arguments(values = {Argument.RANDOM_EACH}) + public static double expOne(double b) { + return Math.pow(b, 1.0); + } + + // Test 5: pow(b, NaN) -> NaN + @Test + @IR(failOn = {IRNode.POW_D}) + @Arguments(values = {Argument.RANDOM_EACH}) + public static double expNaN(double b) { + return Math.pow(b, Double.NaN); + } + + // Test 6: pow(b, 2.0) -> b * b + // More tests in TestPow2Opt.java + @Test + @IR(failOn = {IRNode.POW_D}) + @IR(counts = {IRNode.MUL_D, "1"}) + @Arguments(values = {Argument.RANDOM_EACH}) + public static double expTwo(double b) { + return Math.pow(b, 2.0); + } + + // Test 7: pow(b, 0.5) -> b <= 0.0 ? pow(b, 0.5) : sqrt(b) + // More tests in TestPow0Dot5Opt.java + @Test + @IR(counts = {IRNode.IF, "1"}) + @IR(counts = {IRNode.SQRT_D, "1"}) + @IR(counts = {".*CallLeaf.*pow.*", "1"}, phase = CompilePhase.BEFORE_MATCHING) + @Arguments(values = {Argument.RANDOM_EACH}) + public static double expDot5(double b) { + return Math.pow(b, 0.5); // expand to: if (b > 0) { sqrt(b) } else { call(b) } + } + + // Test 8: non-constant exponent stays as call + @Test + @IR(counts = {IRNode.POW_D, "1"}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + public static double nonConstant(double b, double e) { + return Math.pow(b, e); + } + + // Test 9: late constant discovery on base (after loop opts) + @Test + @IR(counts = {IRNode.POW_D, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(failOn = {IRNode.POW_D}) + public static double lateBaseConstant() { + double base = 0; + for (int i = 0; i < 4; i++) { + if ((i % 2) == 0) { + base = B; + } + } + // After loop opts, base == B (constant), so pow(B, E) folds + return Math.pow(base, E); + } + + // Test 10: late constant discovery on exp (after loop opts) + @Test + @IR(counts = {IRNode.POW_D, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(failOn = {IRNode.POW_D}) + public static double lateExpConstant() { + double exp = 0; + for (int i = 0; i < 4; i++) { + if ((i % 2) == 0) { + exp = E; + } + } + // After loop opts, exp == E (constant), so pow(B, E) folds + return Math.pow(B, exp); + } + + // Test 11: late constant discoveries on both base and exp (after loop opts) + @Test + @IR(counts = {IRNode.POW_D, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(failOn = {IRNode.POW_D}) + public static double lateBothConstant() { + double base = 0, exp = 0; + for (int i = 0; i < 4; i++) { + if ((i % 2) == 0) { + base = B; + exp = E; + } + } + // After loop opts, base = B, exp == E, so pow(B, E) folds + return Math.pow(base, exp); + } + + private static void assertEQWithinOneUlp(double expected, double observed) { + if (Double.isNaN(expected) && Double.isNaN(observed)) return; + + // Math.pow() requires result must be within 1 ulp of the respective magnitude + double ulp = Math.max(Math.ulp(expected), Math.ulp(observed)); + if (Math.abs(expected - observed) > ulp) { + throw new AssertionError(String.format( + "expect = %x, observed = %x, ulp = %x", + Double.doubleToRawLongBits(expected), Double.doubleToRawLongBits(observed), Double.doubleToRawLongBits(ulp) + )); + } + } + + private static void testCorrectness() { + // No need to warm up for intrinsics + Asserts.assertEQ(1024.0d, constantLiteralFolding()); + + double BE = StrictMath.pow(B, E); + assertEQWithinOneUlp(BE, constantStaticFolding()); + assertEQWithinOneUlp(BE, lateBaseConstant()); + assertEQWithinOneUlp(BE, lateExpConstant()); + assertEQWithinOneUlp(BE, lateBothConstant()); + + Generator anyBits = G.anyBitsDouble(); + Generator largeDoubles = G.uniformDoubles(Long.MAX_VALUE, Double.MAX_VALUE); + Generator doubles = G.doubles(); + double[] values = { + Double.MIN_VALUE, Double.MIN_NORMAL, -42.0d, -1.0d, -0.0d, +0.0d, 0.5d, 1.0d, 2.0d, 123d, Double.MAX_VALUE, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NaN, + UNIFORMS.next(), UNIFORMS.next(), + largeDoubles.next(), -largeDoubles.next(), // some sufficiently large magnitudes + anyBits.next(), anyBits.next(), // any bits with potentially more NaN representation + doubles.next(), doubles.next() // a healthy sprinkle of whatever else is possible + }; + + for (double b : values) { + // Strength reduced, so we know the bits matches exactly + Asserts.assertEQ(1.0d, expZero(b)); + Asserts.assertEQ(b, expOne(b)); + Asserts.assertEQ(b * b, expTwo(b)); + + assertEQWithinOneUlp(Double.NaN, expNaN(b)); + + // Runtime calls, so make sure the result is within 1 ulp + assertEQWithinOneUlp(StrictMath.pow(b, 0.5d), expDot5(b)); + + for (double e : values) { + assertEQWithinOneUlp(StrictMath.pow(b, e), nonConstant(b, e)); + } + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java 2026-10-19 12:10:20.000000000 +0000 @@ -471,6 +471,12 @@ superWordNodes(AND_REDUCTION_V, "AndReductionV"); } + public static final String ANY_LOOP = PREFIX + "ANY_LOOP" + POSTFIX; + static { + String regex = START + "(Counted|LongCounted|OuterStripMined)?Loop\\b" + MID + END; + fromBeforeCountedLoops(ANY_LOOP, regex); + } + public static final String CALL = PREFIX + "CALL" + POSTFIX; static { beforeMatchingNameRegex(CALL, "Call.*Java"); @@ -610,11 +616,31 @@ beforeMatchingNameRegex(CONV, "Conv"); } + public static final String CONV_D2I = PREFIX + "CONV_D2I" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_D2I, "ConvD2I"); + } + + public static final String CONV_D2L = PREFIX + "CONV_D2L" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_D2L, "ConvD2L"); + } + public static final String CONV_F2HF = PREFIX + "CONV_F2HF" + POSTFIX; static { beforeMatchingNameRegex(CONV_F2HF, "ConvF2HF"); } + public static final String CONV_F2I = PREFIX + "CONV_F2I" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_F2I, "ConvF2I"); + } + + public static final String CONV_F2L = PREFIX + "CONV_F2L" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_F2L, "ConvF2L"); + } + public static final String CONV_I2L = PREFIX + "CONV_I2L" + POSTFIX; static { beforeMatchingNameRegex(CONV_I2L, "ConvI2L"); @@ -1858,6 +1884,11 @@ beforeMatchingNameRegex(SQRT_HF, "SqrtHF"); } + public static final String SQRT_D = PREFIX + "SQRT_D" + POSTFIX; + static { + beforeMatchingNameRegex(SQRT_D, "SqrtD"); + } + public static final String SQRT_F = PREFIX + "SQRT_F" + POSTFIX; static { beforeMatchingNameRegex(SQRT_F, "SqrtF"); @@ -2254,6 +2285,11 @@ vectorNode(VECTOR_MASK_CMP_D, "VectorMaskCmp", TYPE_DOUBLE); } + public static final String VECTOR_MASK_CMP = PREFIX + "VECTOR_MASK_CMP" + POSTFIX; + static { + beforeMatchingNameRegex(VECTOR_MASK_CMP, "VectorMaskCmp"); + } + public static final String VECTOR_CAST_B2S = VECTOR_PREFIX + "VECTOR_CAST_B2S" + POSTFIX; static { vectorNode(VECTOR_CAST_B2S, "VectorCastB2X", TYPE_SHORT); @@ -2629,6 +2665,66 @@ machOnlyNameRegex(VSTOREMASK_TRUECOUNT, "vstoremask_truecount_neon"); } + public static final String X86_SCONV_D2I = PREFIX + "X86_SCONV_D2I" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2I, "convD2I_reg_reg"); + } + + public static final String X86_SCONV_D2L = PREFIX + "X86_SCONV_D2L" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2L, "convD2L_reg_reg"); + } + + public static final String X86_SCONV_F2I = PREFIX + "X86_SCONV_F2I" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2I, "convF2I_reg_reg"); + } + + public static final String X86_SCONV_F2L = PREFIX + "X86_SCONV_F2L" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2L, "convF2L_reg_reg"); + } + + public static final String X86_SCONV_D2I_AVX10 = PREFIX + "X86_SCONV2_D2I_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2I_AVX10, "convD2I_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_SCONV_D2L_AVX10 = PREFIX + "X86_SCONV_D2L_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2L_AVX10, "convD2L_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_SCONV_F2I_AVX10 = PREFIX + "X86_SCONV_F2I_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2I_AVX10, "convF2I_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_SCONV_F2L_AVX10 = PREFIX + "X86_SCONV_F2L_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2L_AVX10, "convF2L_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_VCAST_F2X = PREFIX + "X86_VCAST_F2X" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_F2X, "castFtoX_reg_(av|eve)x"); + } + + public static final String X86_VCAST_D2X = PREFIX + "X86_VCAST_D2X" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_D2X, "castDtoX_reg_(av|eve)x"); + } + + public static final String X86_VCAST_F2X_AVX10 = PREFIX + "X86_VCAST_F2X_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_F2X_AVX10, "castFtoX_(reg|mem)_avx10"); + } + + public static final String X86_VCAST_D2X_AVX10 = PREFIX + "X86_VCAST_D2X_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_D2X_AVX10, "castDtoX_(reg|mem)_avx10"); + } + public static final String XOR = PREFIX + "XOR" + POSTFIX; static { beforeMatchingNameRegex(XOR, "Xor(I|L)"); @@ -2664,6 +2760,11 @@ vectorNode(XOR_VL, "XorV", TYPE_LONG); } + public static final String XOR_V = PREFIX + "XOR_V" + POSTFIX; + static { + beforeMatchingNameRegex(XOR_V, "XorV"); + } + public static final String XOR_V_MASK = PREFIX + "XOR_V_MASK" + POSTFIX; static { beforeMatchingNameRegex(XOR_V_MASK, "XorVMask"); @@ -2825,6 +2926,12 @@ macroNodes(MOD_D, regex); } + public static final String POW_D = PREFIX + "POW_D" + POSTFIX; + static { + String regex = START + "PowD" + MID + END; + macroNodes(POW_D, regex); + } + public static final String BLACKHOLE = PREFIX + "BLACKHOLE" + POSTFIX; static { fromBeforeRemoveUselessToFinalCode(BLACKHOLE, "Blackhole"); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java 2026-10-19 12:10:20.000000000 +0000 @@ -104,6 +104,7 @@ "avx512f", "avx512_fp16", "avx512_vnni", + "avx10_2", // AArch64 "sha3", "asimd", diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/rangechecks/TestFoldedIfsWrongReexec.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/rangechecks/TestFoldedIfsWrongReexec.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/rangechecks/TestFoldedIfsWrongReexec.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/rangechecks/TestFoldedIfsWrongReexec.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,299 @@ +/* + * 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 8376400 + * @summary C2: folding ifs may cause incorrect execution when trap is taken + * + * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation + * -XX:+UnlockDiagnosticVMOptions -XX:-OptimizeUnstableIf ${test.main.class} + * @run main ${test.main.class} + * + */ + +package compiler.rangechecks; + +public class TestFoldedIfsWrongReexec { + private static int taken1; + private static int taken2; + private static int taken3; + private static int taken4; + private static int taken5; + private static int taken6; + private static int taken7; + private static int MIN_VALUE = Integer.MIN_VALUE; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test1(12); + if (taken1 != 0) { + throw new RuntimeException("branch shouldn't have been taken"); + } + test1Helper1(16, 0); + test2(12); + if (taken2 != 0) { + throw new RuntimeException("branch shouldn't have been taken"); + } + test2Helper1(16, 0); + test3(12); + if (taken3 != 0) { + throw new RuntimeException("branch shouldn't have been taken"); + } + test3Helper1(16, 0); + test4(12, 1, 2); + if (taken4 != 0) { + throw new RuntimeException("branch shouldn't have been taken"); + } + test4Helper1(16, 0, 1, 2); + test5(12); + if (taken5 != 0) { + throw new RuntimeException("branch shouldn't have been taken"); + } + test5Helper1(16, 0); + test6(12, 1, 2); + if (taken6 != 0) { + throw new RuntimeException("branch shouldn't have been taken"); + } + test6Helper1(16, 0, 1, 2); + test7(12); + if (taken7 != 0) { + throw new RuntimeException("branch shouldn't have been taken"); + } + test7Helper1(16, 0); + test7Helper2(o1); + test7Helper2(a); + test7Helper2(b); + } + test1(0); + if (taken1 == 0) { + throw new RuntimeException("branch should have been taken"); + } + test2(0); + if (taken2 == 0) { + throw new RuntimeException("branch should have been taken"); + } + test3(0); + if (taken3 == 0) { + throw new RuntimeException("branch should have been taken"); + } + test4(0, 1, 2); + if (taken4 == 0) { + throw new RuntimeException("branch should have been taken"); + } + test5(0); + if (taken5 == 0) { + throw new RuntimeException("branch should have been taken"); + } + test6(0, 1, 2); + if (taken6 == 0) { + throw new RuntimeException("branch should have been taken"); + } + test7(0); + if (taken7 == 0) { + throw new RuntimeException("branch should have been taken"); + } + } + + private static void test1(int i) { + if (test1Helper1(i, 16) == 0) { + throw new RuntimeException("never taken"); + } + if (i + MIN_VALUE < 8 + Integer.MIN_VALUE) { + taken1++; + } + for (int j = 0; j < 10; j++) { + for (int k = 0; k < 10; k++) { + + } + } + } + + private static int test1Helper1(int i, int j) { + if (i + MIN_VALUE >= j + Integer.MIN_VALUE) { + for (int k = 0; k < 100; k++) { + } + return 0; + } + return 1; + } + + private static void test2(int i) { + if (test2Helper1(i, 16) == 42) { + throw new RuntimeException("never taken"); + } + if (i + MIN_VALUE < 8 + Integer.MIN_VALUE) { + taken2++; + } + for (int j = 0; j < 10; j++) { + for (int k = 0; k < 10; k++) { + + } + } + } + + private static int test2Helper1(int i, int j) { + if (i + MIN_VALUE >= j + Integer.MIN_VALUE) { + for (int k = 0; k < 100; k++) { + } + return 42; + } + return 0x42; + } + + private static void test3(int i) { + if (test3Helper1(i, 16) == 42L) { + throw new RuntimeException("never taken"); + } + if (i + MIN_VALUE < 8 + Integer.MIN_VALUE) { + taken3++; + } + for (int j = 0; j < 10; j++) { + for (int k = 0; k < 10; k++) { + + } + } + } + + private static long test3Helper1(int i, int j) { + if (i + MIN_VALUE >= j + Integer.MIN_VALUE) { + for (int k = 0; k < 100; k++) { + } + return 42L; + } + return 0x42L; + } + + private static void test4(int i, int x, int y) { + if (x == y) { + throw new RuntimeException("never taken"); + } + if (test4Helper1(i, 16, x, y) == y) { + throw new RuntimeException("never taken"); + } + if (i + MIN_VALUE < 8 + Integer.MIN_VALUE) { + taken4++; + } + for (int j = 0; j < 10; j++) { + for (int k = 0; k < 10; k++) { + + } + } + } + + private static int test4Helper1(int i, int j, int x, int y) { + if (i + MIN_VALUE >= j + Integer.MIN_VALUE) { + for (int k = 0; k < 100; k++) { + } + return y; + } + return x; + } + + static final Object o1 = new Object(); + static final Object o2 = new Object(); + + private static void test5(int i) { + if (test5Helper1(i, 16) == o1) { + throw new RuntimeException("never taken"); + } + if (i + MIN_VALUE < 8 + Integer.MIN_VALUE) { + taken5++; + } + for (int j = 0; j < 10; j++) { + for (int k = 0; k < 10; k++) { + + } + } + } + + private static Object test5Helper1(int i, int j) { + if (i + MIN_VALUE >= j + Integer.MIN_VALUE) { + for (int k = 0; k < 100; k++) { + } + return o1; + } + return o2; + } + + private static void test6(int i, int x, int y) { + if (x < y) { + if (test6Helper1(i, 16, x, y) < y) { + throw new RuntimeException("never taken"); + } + if (i + MIN_VALUE < 8 + Integer.MIN_VALUE) { + taken6++; + } + } + for (int j = 0; j < 10; j++) { + for (int k = 0; k < 10; k++) { + + } + } + } + + private static int test6Helper1(int i, int j, int x, int y) { + if (i + MIN_VALUE >= j + Integer.MIN_VALUE) { + for (int k = 0; k < 100; k++) { + } + return x; + } + return y; + } + + static final Object a = new A(); + static final Object b = new B(); + + private static void test7(int i) { + if (test7Helper2(test7Helper1(i, 16))) { + throw new RuntimeException("never taken"); + } + if (i + MIN_VALUE < 8 + Integer.MIN_VALUE) { + taken7++; + } + for (int j = 0; j < 10; j++) { + for (int k = 0; k < 10; k++) { + + } + } + } + + private static Object test7Helper1(int i, int j) { + if (i + MIN_VALUE >= j + Integer.MIN_VALUE) { + for (int k = 0; k < 100; k++) { + } + return a; + } + return b; + } + + private static boolean test7Helper2(Object o) { + return o instanceof A; + } + + private static class A { + } + + private static class B { + } +} diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/rangechecks/TestIndexMatching.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/rangechecks/TestIndexMatching.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/rangechecks/TestIndexMatching.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/rangechecks/TestIndexMatching.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,833 @@ +/* + * 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.rangechecks; + +import compiler.lib.ir_framework.*; +import java.util.Objects; + +/** + * @test + * @bug 8382378 + * @summary Tests that valid index expressions in range checks are matched for + * range check optimizations, and that invalid expressions are + * rejected. These tests should be kept updated with the grammar-based + * specification provided as a comment on + * PhaseIdealLoop::is_scaled_iv_plus_offset(). + * @library /test/lib / + * @run driver ${test.main.class} + */ + +public class TestIndexMatching { + + static int intVar0 = 0; + static int intVar3 = 3; + static int intVar100 = 100; + static int intVar1000 = 1000; + static int intVar10000 = 10000; + + static long longVar0 = 0L; + static long longVar3 = 3L; + static long longVar100 = 100L; + static long longVar1000 = 1000L; + static long longVar10000 = 10000L; + + public static void main(String[] args) { + TestFramework.run(); + } + + // Positive tests: expect the index expressions to be matched and range + // check optimizations to trigger. Use C2-opaque range check limits to + // increase the likelihood that loop elimination is indeed caused by range + // check optimizations and not accidentally by other transformations. + + // Int indices using int induction variables + + // iv + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIV() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv, intVar10000); + } + } + + // AddI(iv, e) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithAddedVarOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv + intVar0, intVar10000); + } + } + + // SubI(iv, e) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithSubtractedVarOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv - intVar0, intVar10000); + } + } + + // SubI(e, iv) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVSubtractedFromVarOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(intVar1000 - iv, intVar10000); + } + } + + // AddI(iv, ConI) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithAddedConstOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv + 7, intVar10000); + } + } + + // AddI((AddI(iv, e)), ConI) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithAddedNestedOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((iv + intVar0) + 7, intVar10000); + } + } + + // MulI(iv, ConI) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithMulScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv * 11, intVar10000); + } + } + + // AddI(MulI(iv, ConI), e) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithMulScalingAndAddedVarOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((iv * 11) + intVar0, intVar10000); + } + } + + // AddI(AddI(MulI(iv, ConI), e), ConI) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithMulScalingAndAddedNestedOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(((iv * 11) + intVar0) + 7, intVar10000); + } + } + + // LShiftI(iv, ConI) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithShiftScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv << 2, intVar10000); + } + } + + // SubI(0, MulI(iv, ConI)) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithNegatedMulScaling() { + for (int iv = -intVar100; iv <= 0; iv++) { + Objects.checkIndex(0 - (iv * 11), intVar10000); + } + } + + // AddI(MulI(iv, ConI), MulI(iv, ConI)) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithAddOfMulsScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((iv * 3) + (iv * 7), intVar10000); + } + } + + // SubI(LShiftI(iv, ConI), MulI(iv, ConI)) + @Test + @IR(failOn = {IRNode.ANY_LOOP}) + static void testIntIndexIntIVWithSubOfShiftAndMulScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((iv << 4) - (iv * 13), intVar10000); + } + } + + // Long indices using long induction variables + + // iv + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexLongIV() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv, longVar10000); + } + } + + // AddL(iv, e) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexLongIVWithAddedVarOffset() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv + longVar0, longVar10000); + } + } + + // SubL(iv, e) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexLongIVWithSubtractedVarOffset() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv - longVar0, longVar10000); + } + } + + // SubL(e, iv) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexLongIVSubtractedFromVarOffset() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(longVar1000 - iv, longVar10000); + } + } + + // AddL(iv, ConL) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.COUNTED_LOOP, "1", IRNode.ANY_LOOP, "2"}) + static void testLongIndexLongIVWithAddedConstOffset() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv + 1L, longVar10000); + } + } + + // AddL((AddL(iv, e)), ConL) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexLongIVWithAddedNestedOffset() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex((iv + longVar0) + 7L, longVar10000); + } + } + + // MulL(iv, ConL) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexLongIVWithMulScaling() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv * 11L, longVar10000); + } + } + + // AddL(MulL(iv, ConL), e) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexLongIVWithMulScalingAndAddedVarOffset() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex((iv * 11L) + longVar0, longVar10000); + } + } + + // AddL(AddL(MulL(iv, ConL), e), ConL) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexLongIVWithMulScalingAndAddedNestedOffset() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(((iv * 11L) + longVar0) + 7L, longVar10000); + } + } + + // LShiftL(iv, ConI) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexLongIVWithShiftScaling() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv << 2, longVar10000); + } + } + + // SubL(0L, MulL(iv, ConL)) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexLongIVWithNegatedMulScaling() { + for (long iv = -longVar100; iv <= 0; iv++) { + Objects.checkIndex(0L - (iv * 11L), longVar10000); + } + } + + // Long indices using int induction variables + + // ConvI2L(iv) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIV() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)iv, longVar10000); + } + } + + // AddL(ConvI2L(iv), e) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithAddedVarOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)iv + longVar0, longVar10000); + } + } + + // AddL(ConvI2L(iv), ConL) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.COUNTED_LOOP, "1", IRNode.ANY_LOOP, "2"}) + static void testLongIndexIntIVWithAddedConstOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)iv + 1L, longVar10000); + } + } + + // MulL(ConvI2L(iv), ConL) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithMulScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)iv * 11L, longVar10000); + } + } + + // AddL(MulL(ConvI2L(iv), ConL), e) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithMulScalingAndAddedVarOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(((long)iv * 11L) + longVar0, longVar10000); + } + } + + // LShiftL(ConvI2L(iv), ConI) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithShiftScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)iv << 2, longVar10000); + } + } + + // SubL(0L, MulL(ConvI2L(iv), ConL)) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithNegatedMulScaling() { + for (int iv = -intVar100; iv <= 0; iv++) { + Objects.checkIndex(0L - ((long)iv * 11L), longVar10000); + } + } + + // ConvI2L(MulI(iv, ConI)) + // Range check optimizations still trigger because the short scaling is + // optimized away during IGVN. + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithShortMulScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)(iv * 1), longVar10000); + } + } + + // ConvI2L(LShiftI(iv, ConI)) + // Range check optimizations still trigger because the short scaling is + // optimized away during IGVN. + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithShortShiftScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)(iv << 0), longVar10000); + } + } + + // ConvI2L(AddI(MulI(iv, ConI), MulI(iv, ConI))) + // Range check optimizations still trigger because the short scaling is + // optimized away during IGVN. + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithShortAddOfMulsScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)((iv * 3) + (iv * -2)), longVar10000); + } + } + + // ConvI2L(SubI(0, MulI(iv, ConI))) + // Range check optimizations still trigger because the short scaling is + // optimized away during IGVN. + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithShortNegatedSubScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)(0 - (iv * -1)), longVar10000); + } + } + + // ConvI2L(SubI(MulI(iv, ConI), MulI(iv, ConI))) + // Range check optimizations still trigger because the short scaling is + // optimized away during IGVN. + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithShortSubOfMulsScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)((iv * 3) - (iv * 2)), longVar10000); + } + } + + // AddL(MulL(ConvI2L(iv), ConL), MulL(ConvI2L(iv), ConL)) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithAddOfMulsScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(((long)iv * 3L) + ((long)iv * 7L), longVar10000); + } + } + + // SubL(LShiftL(ConvI2L(iv), ConI), ConvI2L(iv)) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithSubOfShiftScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(((long)iv << 3) - iv, longVar10000); + } + } + + // ConvI2L(AddI(MulI(iv, ConI), LShiftI(iv, ConI))) + // Range check optimizations still trigger because the short scaling is + // optimized away during IGVN. + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithShortAddOfMulAndShiftScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)((iv * -15) + (iv << 4)), longVar10000); + } + } + + // AddL(AddL(ConvI2L(AddI(MulI(iv, ConI), MulI(iv, ConI))), e), ConL) + // Range check optimizations still trigger because the short scaling is + // optimized away during IGVN. + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + // The following check will fail if JDK-8342692 is backported. To fix it, + // use @IR(failOn = {IRNode.ANY_LOOP}), like the int indices positive tests. + @IR(counts = {IRNode.LOOP, "1", IRNode.ANY_LOOP, "1"}) + static void testLongIndexIntIVWithShortAddOfMulsScalingAndAddedNestedOffset() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(((long)((iv * 3) + (iv * -2)) + longVar0) + 7L, longVar10000); + } + } + + // Negative tests: expect the index expressions to be rejected and the loop + // to not be eliminated. + + // Int indices using int induction variables + + // MulI(iv, LoadI(..)) + @Test + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testIntIndexIntIVWithVarMulScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv * intVar3, 10000); + } + } + + // LShiftI(iv, LoadI(..)) + @Test + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testIntIndexIntIVWithVarShiftScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv << intVar0, 10000); + } + } + + // MulI(AddI(iv, LoadI(..)), ConI) + @Test + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testIntIndexIntIVWithNonTrivialMulScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((iv + intVar0) * 11, 10000); + } + } + + // LShiftI(AddI(iv, LoadI(..)), LoadI(..)) + @Test + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testIntIndexIntIVWithNonTrivialShiftScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((iv + intVar0) << intVar0, 10000); + } + } + + // RShiftI(iv, ConI) + @Test + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testIntIndexIntIVWithUnsupportedRightShift() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv >> 1, 10000); + } + } + + // OrI(iv, ConI) + @Test + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testIntIndexIntIVWithUnsupportedOr() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv | 1024, 10000); + } + } + + // XorI(iv, ConI) + @Test + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testIntIndexIntIVWithUnsupportedXor() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(iv ^ 1024, 10000); + } + } + + // SubI(0, LShiftI(iv, ConI)) where scale(LShiftI(..)) == min_jint + @Test + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testIntIndexIntIVWithNegatedMinJIntShiftScaling() { + for (int iv = 0; iv <= intVar100; iv += 2) { + Objects.checkIndex(0 - (iv << 31), 10000); + } + } + + // Long indices using long induction variables + + // MulL(iv, LoadL(..)) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexLongIVWithVarMulScaling() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv * longVar3, 10000L); + } + } + + // LShiftL(iv, LoadI(..)) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexLongIVWithVarShiftScaling() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv << intVar0, 10000L); + } + } + + // MulL(AddL(iv, LoadL(..)), ConL) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexLongIVWithNonTrivialMulScaling() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex((iv + longVar0) * 11L, 10000L); + } + } + + // LShiftL(AddL(iv, LoadL(..)), LoadI(..)) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexLongIVWithNonTrivialShiftScaling() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex((iv + longVar0) << intVar0, 10000L); + } + } + + // RShiftL(iv, ConI) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexLongIVWithUnsupportedRightShift() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv >> 1, 10000L); + } + } + + // OrL(iv, ConL) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexLongIVWithUnsupportedOr() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv | 1024L, 10000L); + } + } + + // XorL(iv, ConL) + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexLongIVWithUnsupportedXor() { + for (long iv = 0L; iv <= longVar100; iv++) { + Objects.checkIndex(iv ^ 1024L, 10000L); + } + } + + // SubL(0L, LShiftL(iv, ConI)) where scale(LShiftL(..)) == min_jlong + @Test + @IR(failOn = {IRNode.CONV_I2L}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexLongIVWithNegatedMinJLongShiftScaling() { + for (long iv = 0L; iv <= longVar100; iv += 2L) { + Objects.checkIndex(0L - (iv << 63), 10000L); + } + } + + // Long indices using int induction variables + + // ConvI2L(MulI(iv, ConI)) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithNonUnitShortMulScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)(iv * 11), 10000L); + } + } + + // ConvI2L(LShiftI(iv, ConI)) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithNonUnitShortShiftScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)(iv << 2), 10000L); + } + } + + // ConvI2L(SubI(0, MulI(iv, ConI))) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithNonUnitShortNegatedSubScaling() { + for (int iv = -100; iv <= 0; iv++) { + Objects.checkIndex((long)(0 - (iv * 3)), + // Using a variable range check length is + // required here for the index expression not to + // be optimized into something else that matches. + longVar10000); + } + } + + // ConvI2L(SubI(0, LShiftI(iv, ConI))) where scale(LShiftI(..)) == min_jint + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithShortNegatedSubMinJIntShiftScaling() { + for (int iv = 0; iv <= intVar100; iv += 2) { + Objects.checkIndex((long)(0 - (iv << 31)), 10000L); + } + } + + // ConvI2L(MulI(iv, LoadI(..))) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithShortVarMulScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)(iv * intVar3), 10000L); + } + } + + // ConvI2L(LShiftI(iv, LoadI(..))) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithShortVarShiftScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)(iv << intVar3), 10000L); + } + } + + // MulL(AddL(ConvI2L(iv), LoadL(..)), ConL) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithMulOfAddScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex(((long)iv + longVar0) * 11L, 10000L); + } + } + + // RShiftL(ConvI2L(iv), ConI) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithUnsupportedRightShift() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)iv >> 1, 10000L); + } + } + + // ConvI2L(AddI(MulI(iv, ConI), MulI(iv, ConI))) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithNonUnitShortAddOfMulsScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)((iv * 3) + (iv * 5)), 10000L); + } + } + + // ConvI2L(AddI(MulI(iv, ConI), LShiftI(iv, ConI))) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithNonUnitShortAddOfMulAndShiftScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)((iv * -15) + (iv << 5)), 10000L); + } + } + + // ConvI2L(SubI(MulI(iv, ConI), MulI(iv, ConI))) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithNonUnitShortSubOfMulsScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)((iv * 7) - (iv * 2)), 10000L); + } + } + + // ConvI2L(SubI(LShiftI(iv, ConI), LShiftI(iv, ConI))) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithShortSubOfShiftsScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)((iv << 33) - (iv << 0)), longVar10000); + } + } + + // ConvI2L(SubI(LShiftI(iv, ConI), LShiftI(iv, ConI))) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithNonUnitShortSubOfShiftsScaling() { + for (int iv = 0; iv <= intVar100; iv++) { + Objects.checkIndex((long)((iv << 5) - (iv << 1)), 10000L); + } + } + + // ConvI2L(SubI(0, LShiftI(iv, ConI))) + @Test + @IR(counts = {IRNode.CONV_I2L, ">0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.COUNTED_LOOP, ">0"}) + static void testLongIndexIntIVWithNonUnitShortNegatedSubShiftScaling() { + for (int iv = -100; iv <= 0; iv++) { + Objects.checkIndex((long)(0 - (iv << 2)), + // Using a variable range check length is + // required here for the index expression not to + // be optimized into something else that matches. + longVar10000); + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheckWithZeroScaling.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheckWithZeroScaling.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheckWithZeroScaling.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheckWithZeroScaling.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.rangechecks; + +import java.util.Objects; + +/** + * @test + * @bug 8382378 + * @summary Test that C2 can handle long range check indices scaled by zero. + * @run main ${test.main.class} + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * ${test.main.class} + */ + +public class TestLongRangeCheckWithZeroScaling { + + static void testCheckCancellingSubtractionOfScaledIndices() { + for (int i = 0; i < 100; i++) { + long index = ((long)(i << 10)) - (((long)i) << 10); + Objects.checkIndex(index, 100); + } + } + + public static void main(String[] args) { + Objects.checkIndex(0, 1); // Ensure java.util.Objects is loaded. + for (int i = 0; i < 10_000; i++) { + testCheckCancellingSubtractionOfScaledIndices(); + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,8 @@ /** * @test -* @bug 8287835 -* @summary Test float/double to integral cast +* @bug 8287835 8364305 +* @summary Test vector float/double to integral cast * @modules jdk.incubator.vector * @requires vm.compiler2.enabled * @library /test/lib / @@ -87,7 +87,11 @@ @Test @IR(counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE_16, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2int() { var cvec = (IntVector)fvec512.convertShape(VectorOperators.F2I, ispec512, 0); cvec.intoArray(int_arr, 0); @@ -96,7 +100,7 @@ public void checkf2int(int len) { for (int i = 0; i < len; i++) { - int expected = (int)float_arr[i]; + int expected = (int) float_arr[i]; if (int_arr[i] != expected) { throw new RuntimeException("Invalid result: int_arr[" + i + "] = " + int_arr[i] + " != " + expected); } @@ -105,7 +109,11 @@ @Test @IR(counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512dq", "true"}) + applyIfCPUFeatureOr = {"avx512dq", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2long() { var cvec = (LongVector)fvec512.convertShape(VectorOperators.F2L, lspec512, 0); cvec.intoArray(long_arr, 0); @@ -114,7 +122,7 @@ public void checkf2long(int len) { for (int i = 0; i < len; i++) { - long expected = (long)float_arr[i]; + long expected = (long) float_arr[i]; if (long_arr[i] != expected) { throw new RuntimeException("Invalid result: long_arr[" + i + "] = " + long_arr[i] + " != " + expected); } @@ -123,7 +131,11 @@ @Test @IR(counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE_16, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2short() { var cvec = (ShortVector)fvec512.convertShape(VectorOperators.F2S, sspec256, 0); cvec.intoArray(short_arr, 0); @@ -132,7 +144,7 @@ public void checkf2short(int len) { for (int i = 0; i < len; i++) { - short expected = (short)float_arr[i]; + short expected = (short) float_arr[i]; if (short_arr[i] != expected) { throw new RuntimeException("Invalid result: short_arr[" + i + "] = " + short_arr[i] + " != " + expected); } @@ -141,7 +153,11 @@ @Test @IR(counts = {IRNode.VECTOR_CAST_F2B, IRNode.VECTOR_SIZE_16, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2byte() { var cvec = (ByteVector)fvec512.convertShape(VectorOperators.F2B, bspec128, 0); cvec.intoArray(byte_arr, 0); @@ -150,7 +166,7 @@ public void checkf2byte(int len) { for (int i = 0; i < len; i++) { - byte expected = (byte)float_arr[i]; + byte expected = (byte) float_arr[i]; if (byte_arr[i] != expected) { throw new RuntimeException("Invalid result: byte_arr[" + i + "] = " + byte_arr[i] + " != " + expected); } @@ -159,7 +175,11 @@ @Test @IR(counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2int() { var cvec = (IntVector)dvec512.convertShape(VectorOperators.D2I, ispec256, 0); cvec.intoArray(int_arr, 0); @@ -168,7 +188,7 @@ public void checkd2int(int len) { for (int i = 0; i < len; i++) { - int expected = (int)double_arr[i]; + int expected = (int) double_arr[i]; if (int_arr[i] != expected) { throw new RuntimeException("Invalid result: int_arr[" + i + "] = " + int_arr[i] + " != " + expected); } @@ -177,7 +197,11 @@ @Test @IR(counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512dq", "true"}) + applyIfCPUFeatureOr = {"avx512dq", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2long() { var cvec = (LongVector)dvec512.convertShape(VectorOperators.D2L, lspec512, 0); cvec.intoArray(long_arr, 0); @@ -186,7 +210,7 @@ public void checkd2long(int len) { for (int i = 0; i < len; i++) { - long expected = (long)double_arr[i]; + long expected = (long) double_arr[i]; if (long_arr[i] != expected) { throw new RuntimeException("Invalid result: long_arr[" + i + "] = " + long_arr[i] + " != " + expected); } @@ -195,7 +219,11 @@ @Test @IR(counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2short() { var cvec = (ShortVector)dvec512.convertShape(VectorOperators.D2S, sspec128, 0); cvec.intoArray(short_arr, 0); @@ -204,7 +232,7 @@ public void checkd2short(int len) { for (int i = 0; i < len; i++) { - short expected = (short)double_arr[i]; + short expected = (short) double_arr[i]; if (short_arr[i] != expected) { throw new RuntimeException("Invalid result: short_arr[" + i + "] = " + short_arr[i] + " != " + expected); } @@ -213,7 +241,11 @@ @Test @IR(counts = {IRNode.VECTOR_CAST_D2B, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2byte() { var cvec = (ByteVector)dvec512.convertShape(VectorOperators.D2B, bspec64, 0); cvec.intoArray(byte_arr, 0); @@ -222,7 +254,7 @@ public void checkd2byte(int len) { for (int i = 0; i < len; i++) { - byte expected = (byte)double_arr[i]; + byte expected = (byte) double_arr[i]; if (byte_arr[i] != expected) { throw new RuntimeException("Invalid result: byte_arr[" + i + "] = " + byte_arr[i] + " != " + expected); } diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,1299 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.vectorapi; + +import compiler.lib.generators.*; +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8354242 + * @key randomness + * @library /test/lib / + * @summary test combining vector not operation with compare + * @modules jdk.incubator.vector + * + * @run driver compiler.vectorapi.VectorMaskCompareNotTest + */ + +public class VectorMaskCompareNotTest { + private static int LENGTH = 128; + + private static final VectorSpecies B_SPECIES = VectorSpecies.ofLargestShape(byte.class); + private static final VectorSpecies S_SPECIES = VectorSpecies.ofLargestShape(short.class); + private static final VectorSpecies I_SPECIES = VectorSpecies.ofLargestShape(int.class); + private static final VectorSpecies L_SPECIES = VectorSpecies.ofLargestShape(long.class); + private static final VectorSpecies F_SPECIES = VectorSpecies.ofLargestShape(float.class); + private static final VectorSpecies D_SPECIES = VectorSpecies.ofLargestShape(double.class); + + // Vector species for vector mask cast operation between int and long types, + // they must have the same number of elements. + // For other types, use a vector species of the specified width. + private static final VectorSpecies L_SPECIES_FOR_CAST = VectorSpecies.ofLargestShape(long.class); + private static final VectorSpecies I_SPECIES_FOR_CAST = VectorSpecies.of(int.class, VectorShape.forBitSize(L_SPECIES_FOR_CAST.vectorBitSize() / 2)); + + private static final Generators RD = Generators.G; + + private static byte[] ba; + private static byte[] bb; + private static short[] sa; + private static short[] sb; + private static int[] ia; + private static int[] ib; + private static int[] ic; + private static long[] la; + private static long[] lb; + private static float[] fa; + private static float[] fb; + private static float[] fnan; + private static float[] fpinf; + private static float[] fninf; + private static double[] da; + private static double[] db; + private static double[] dnan; + private static double[] dpinf; + private static double[] dninf; + private static boolean[] mr; + + static { + ba = new byte[LENGTH]; + bb = new byte[LENGTH]; + sa = new short[LENGTH]; + sb = new short[LENGTH]; + ia = new int[LENGTH]; + ib = new int[LENGTH]; + ic = new int[LENGTH]; + la = new long[LENGTH]; + lb = new long[LENGTH]; + fa = new float[LENGTH]; + fb = new float[LENGTH]; + fnan = new float[LENGTH]; + fpinf = new float[LENGTH]; + fninf = new float[LENGTH]; + da = new double[LENGTH]; + db = new double[LENGTH]; + dnan = new double[LENGTH]; + dpinf = new double[LENGTH]; + dninf = new double[LENGTH]; + mr = new boolean[LENGTH]; + + Generator iGen = RD.ints(); + Generator lGen = RD.longs(); + // Use uniform generators for floating point numbers not to generate NaN values. + Generator fGen = RD.uniformFloats(Float.MIN_VALUE, Float.MAX_VALUE); + Generator dGen = RD.uniformDoubles(Double.MIN_VALUE, Double.MAX_VALUE); + 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(); + ia[i] = iGen.next(); + ib[i] = iGen.next(); + la[i] = lGen.next(); + lb[i] = lGen.next(); + fa[i] = fGen.next(); + fb[i] = fGen.next(); + fnan[i] = Float.NaN; + fpinf[i] = Float.POSITIVE_INFINITY; + fninf[i] = Float.NEGATIVE_INFINITY; + da[i] = dGen.next(); + db[i] = dGen.next(); + dnan[i] = Double.NaN; + dpinf[i] = Double.POSITIVE_INFINITY; + dninf[i] = Double.NEGATIVE_INFINITY; + } + } + + public static int compareUnsigned(Number a, Number b) { + if (a instanceof Byte) { + return Integer.compareUnsigned(Byte.toUnsignedInt(a.byteValue()), Byte.toUnsignedInt(b.byteValue())); + } else if (a instanceof Short) { + return Integer.compareUnsigned(Short.toUnsignedInt(a.shortValue()), Short.toUnsignedInt(b.shortValue())); + } else if (a instanceof Integer) { + return Integer.compareUnsigned(a.intValue(), b.intValue()); + } else if (a instanceof Long) { + return Long.compareUnsigned(a.longValue(), b.longValue()); + } else { + throw new IllegalArgumentException("Unsupported type for unsigned comparison: " + a.getClass() + ", " + b.getClass()); + } + } + + public static > void compareResults(T a, T b, boolean r, VectorOperators.Comparison op) { + if (op == VectorOperators.EQ) { + // For floating point numbers, a is not NaN, b may be NaN. If b is NaN, + // a.compareTo(b) will return 1, 1 != 0 is true, r is expected to be true. + Asserts.assertEquals(a.compareTo(b) != 0, r); + } else if (op == VectorOperators.NE) { + // For floating point numbers, a is not NaN, b may be NaN. If b is NaN, + // a.compareTo(b) will return 1, 1 == 0 is false, r is expected to be false. + Asserts.assertEquals(a.compareTo(b) == 0, r); + } else if (op == VectorOperators.LE) { + Asserts.assertEquals(a.compareTo(b) > 0, r); + } else if (op == VectorOperators.GE) { + Asserts.assertEquals(a.compareTo(b) < 0, r); + } else if (op == VectorOperators.LT) { + Asserts.assertEquals(a.compareTo(b) >= 0, r); + } else if (op == VectorOperators.GT) { + Asserts.assertEquals(a.compareTo(b) <= 0, r); + } else if (op == VectorOperators.ULE) { + Asserts.assertEquals(compareUnsigned(a, b) > 0, r); + } else if (op == VectorOperators.UGE) { + Asserts.assertEquals(compareUnsigned(a, b) < 0, r); + } else if (op == VectorOperators.ULT) { + Asserts.assertEquals(compareUnsigned(a, b) >= 0, r); + } else if (op == VectorOperators.UGT) { + Asserts.assertEquals(compareUnsigned(a, b) <= 0, r); + } else { + throw new IllegalArgumentException("Unknown comparison operator: " + op); + } + } + + @DontInline + public static void verifyResultsByte(VectorSpecies vs, VectorOperators.Comparison op) { + for (int i = 0; i < vs.length(); i++) { + compareResults(ba[i], bb[i], mr[i], op); + } + } + + @DontInline + public static void verifyResultsShort(VectorSpecies vs, VectorOperators.Comparison op) { + for (int i = 0; i < vs.length(); i++) { + compareResults(sa[i], sb[i], mr[i], op); + } + } + + @DontInline + public static void verifyResultsInt(VectorSpecies vs, VectorOperators.Comparison op) { + for (int i = 0; i < vs.length(); i++) { + compareResults(ia[i], ib[i], mr[i], op); + } + } + + @DontInline + public static void verifyResultsLong(VectorSpecies vs, VectorOperators.Comparison op) { + for (int i = 0; i < vs.length(); i++) { + compareResults(la[i], lb[i], mr[i], op); + } + } + + @DontInline + public static void verifyResultsFloat(VectorSpecies vs, VectorOperators.Comparison op, float[] a, float[] b) { + for (int i = 0; i < vs.length(); i++) { + compareResults(a[i], b[i], mr[i], op); + } + } + + @DontInline + public static void verifyResultsDouble(VectorSpecies vs, VectorOperators.Comparison op, double[] a, double[] b) { + for (int i = 0; i < vs.length(); i++) { + compareResults(a[i], b[i], mr[i], op); + } + } + + interface VectorMaskOperator { + public VectorMask apply(VectorMask m); + } + + @ForceInline + public static void testCompareMaskNotByte(VectorSpecies vs, VectorOperators.Comparison op, VectorMaskOperator func) { + ByteVector av = ByteVector.fromArray(vs, ba, 0); + ByteVector bv = ByteVector.fromArray(vs, bb, 0); + VectorMask m = av.compare(op, bv); + func.apply(m).intoArray(mr, 0); + } + + @ForceInline + public static void testCompareMaskNotShort(VectorSpecies vs, VectorOperators.Comparison op, VectorMaskOperator func) { + ShortVector av = ShortVector.fromArray(vs, sa, 0); + ShortVector bv = ShortVector.fromArray(vs, sb, 0); + VectorMask m = av.compare(op, bv); + func.apply(m).intoArray(mr, 0); + } + + @ForceInline + public static void testCompareMaskNotInt(VectorSpecies vs, VectorOperators.Comparison op, VectorMaskOperator func) { + IntVector av = IntVector.fromArray(vs, ia, 0); + IntVector bv = IntVector.fromArray(vs, ib, 0); + VectorMask m = av.compare(op, bv); + func.apply(m).intoArray(mr, 0); + } + + @ForceInline + public static void testCompareMaskNotLong(VectorSpecies vs, VectorOperators.Comparison op, VectorMaskOperator func) { + LongVector av = LongVector.fromArray(vs, la, 0); + LongVector bv = LongVector.fromArray(vs, lb, 0); + VectorMask m = av.compare(op, bv); + func.apply(m).intoArray(mr, 0); + } + + @ForceInline + public static void testCompareMaskNotFloat(VectorSpecies vs, VectorOperators.Comparison op, float[] a, float[] b, VectorMaskOperator func) { + FloatVector av = FloatVector.fromArray(vs, a, 0); + FloatVector bv = FloatVector.fromArray(vs, b, 0); + VectorMask m = av.compare(op, bv); + func.apply(m).intoArray(mr, 0); + } + + @ForceInline + public static void testCompareMaskNotDouble(VectorSpecies vs, VectorOperators.Comparison op, double[] a, double[] b, VectorMaskOperator func) { + DoubleVector av = DoubleVector.fromArray(vs, a, 0); + DoubleVector bv = DoubleVector.fromArray(vs, b, 0); + VectorMask m = av.compare(op, bv); + func.apply(m).intoArray(mr, 0); + } + + // Byte tests + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareEQMaskNotByte() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); + verifyResultsByte(B_SPECIES, VectorOperators.EQ); + testCompareMaskNotByte(B_SPECIES, VectorOperators.EQ, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.EQ); + + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.EQ, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.EQ); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareNEMaskNotByte() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); + verifyResultsByte(B_SPECIES, VectorOperators.NE); + testCompareMaskNotByte(B_SPECIES, VectorOperators.NE, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.NE); + + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.NE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareLTMaskNotByte() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); + verifyResultsByte(B_SPECIES, VectorOperators.LT); + testCompareMaskNotByte(B_SPECIES, VectorOperators.LT, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.LT); + + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.LT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.LT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareGTMaskNotByte() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); + verifyResultsByte(B_SPECIES, VectorOperators.GT); + testCompareMaskNotByte(B_SPECIES, VectorOperators.GT, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.GT); + + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.GT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.GT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareLEMaskNotByte() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); + verifyResultsByte(B_SPECIES, VectorOperators.LE); + testCompareMaskNotByte(B_SPECIES, VectorOperators.LE, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.LE); + + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.LE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.LE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareGEMaskNotByte() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); + verifyResultsByte(B_SPECIES, VectorOperators.GE); + testCompareMaskNotByte(B_SPECIES, VectorOperators.GE, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.GE); + + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.GE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.GE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareULTMaskNotByte() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); + verifyResultsByte(B_SPECIES, VectorOperators.ULT); + testCompareMaskNotByte(B_SPECIES, VectorOperators.ULT, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.ULT); + + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.ULT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.ULT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareUGTMaskNotByte() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); + verifyResultsByte(B_SPECIES, VectorOperators.UGT); + testCompareMaskNotByte(B_SPECIES, VectorOperators.UGT, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.UGT); + + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.UGT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.UGT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareULEMaskNotByte() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); + verifyResultsByte(B_SPECIES, VectorOperators.ULE); + testCompareMaskNotByte(B_SPECIES, VectorOperators.ULE, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.ULE); + + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.ULE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.ULE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareUGEMaskNotByte() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); + verifyResultsByte(B_SPECIES, VectorOperators.UGE); + testCompareMaskNotByte(B_SPECIES, VectorOperators.UGE, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.UGE); + + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.UGE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.UGE); + } + + // Short tests + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareEQMaskNotShort() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); + verifyResultsShort(S_SPECIES, VectorOperators.EQ); + testCompareMaskNotShort(S_SPECIES, VectorOperators.EQ, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.EQ); + + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.EQ, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.EQ); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.EQ, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.EQ); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareNEMaskNotShort() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); + verifyResultsShort(S_SPECIES, VectorOperators.NE); + testCompareMaskNotShort(S_SPECIES, VectorOperators.NE, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.NE); + + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.NE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.NE); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.NE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareLTMaskNotShort() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); + verifyResultsShort(S_SPECIES, VectorOperators.LT); + testCompareMaskNotShort(S_SPECIES, VectorOperators.LT, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.LT); + + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.LT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.LT); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.LT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.LT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareGTMaskNotShort() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); + verifyResultsShort(S_SPECIES, VectorOperators.GT); + testCompareMaskNotShort(S_SPECIES, VectorOperators.GT, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.GT); + + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.GT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.GT); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.GT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.GT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareLEMaskNotShort() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); + verifyResultsShort(S_SPECIES, VectorOperators.LE); + testCompareMaskNotShort(S_SPECIES, VectorOperators.LE, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.LE); + + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.LE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.LE); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.LE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.LE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareGEMaskNotShort() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); + verifyResultsShort(S_SPECIES, VectorOperators.GE); + testCompareMaskNotShort(S_SPECIES, VectorOperators.GE, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.GE); + + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.GE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.GE); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.GE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.GE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareULTMaskNotShort() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); + verifyResultsShort(S_SPECIES, VectorOperators.ULT); + testCompareMaskNotShort(S_SPECIES, VectorOperators.ULT, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.ULT); + + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.ULT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.ULT); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.ULT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.ULT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareUGTMaskNotShort() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); + verifyResultsShort(S_SPECIES, VectorOperators.UGT); + testCompareMaskNotShort(S_SPECIES, VectorOperators.UGT, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.UGT); + + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.UGT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.UGT); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.UGT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.UGT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareULEMaskNotShort() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); + verifyResultsShort(S_SPECIES, VectorOperators.ULE); + testCompareMaskNotShort(S_SPECIES, VectorOperators.ULE, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.ULE); + + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.ULE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.ULE); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.ULE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.ULE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareUGEMaskNotShort() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); + verifyResultsShort(S_SPECIES, VectorOperators.UGE); + testCompareMaskNotShort(S_SPECIES, VectorOperators.UGE, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.UGE); + + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.UGE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.UGE); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.UGE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.UGE); + } + + // Int tests + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareEQMaskNotInt() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); + verifyResultsInt(I_SPECIES, VectorOperators.EQ); + testCompareMaskNotInt(I_SPECIES, VectorOperators.EQ, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.EQ); + + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.EQ, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.EQ); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.EQ, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.EQ); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareNEMaskNotInt() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); + verifyResultsInt(I_SPECIES, VectorOperators.NE); + testCompareMaskNotInt(I_SPECIES, VectorOperators.NE, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.NE); + + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.NE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.NE); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.NE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareLTMaskNotInt() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); + verifyResultsInt(I_SPECIES, VectorOperators.LT); + testCompareMaskNotInt(I_SPECIES, VectorOperators.LT, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.LT); + + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.LT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.LT); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.LT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.LT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareGTMaskNotInt() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); + verifyResultsInt(I_SPECIES, VectorOperators.GT); + testCompareMaskNotInt(I_SPECIES, VectorOperators.GT, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.GT); + + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.GT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.GT); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.GT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.GT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareLEMaskNotInt() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); + verifyResultsInt(I_SPECIES, VectorOperators.LE); + testCompareMaskNotInt(I_SPECIES, VectorOperators.LE, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.LE); + + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.LE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.LE); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.LE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.LE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareGEMaskNotInt() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); + verifyResultsInt(I_SPECIES, VectorOperators.GE); + testCompareMaskNotInt(I_SPECIES, VectorOperators.GE, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.GE); + + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.GE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.GE); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.GE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.GE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareULTMaskNotInt() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); + verifyResultsInt(I_SPECIES, VectorOperators.ULT); + testCompareMaskNotInt(I_SPECIES, VectorOperators.ULT, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.ULT); + + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.ULT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.ULT); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.ULT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.ULT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareUGTMaskNotInt() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); + verifyResultsInt(I_SPECIES, VectorOperators.UGT); + testCompareMaskNotInt(I_SPECIES, VectorOperators.UGT, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.UGT); + + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.UGT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.UGT); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.UGT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.UGT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareULEMaskNotInt() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); + verifyResultsInt(I_SPECIES, VectorOperators.ULE); + testCompareMaskNotInt(I_SPECIES, VectorOperators.ULE, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.ULE); + + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.ULE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.ULE); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.ULE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.ULE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 2", + IRNode.VECTOR_MASK_CMP, "= 4" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareUGEMaskNotInt() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); + verifyResultsInt(I_SPECIES, VectorOperators.UGE); + testCompareMaskNotInt(I_SPECIES, VectorOperators.UGE, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.UGE); + + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.UGE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.UGE); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.UGE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.UGE); + } + + // Long tests + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareEQMaskNotLong() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); + verifyResultsLong(L_SPECIES, VectorOperators.EQ); + testCompareMaskNotLong(L_SPECIES, VectorOperators.EQ, (m) -> { return L_SPECIES.maskAll(true).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.EQ); + + testCompareMaskNotLong(L_SPECIES_FOR_CAST, VectorOperators.EQ, (m) -> { return m.cast(I_SPECIES_FOR_CAST).not(); }); + verifyResultsLong(L_SPECIES_FOR_CAST, VectorOperators.EQ); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareNEMaskNotLong() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); + verifyResultsLong(L_SPECIES, VectorOperators.NE); + testCompareMaskNotLong(L_SPECIES, VectorOperators.NE, (m) -> { return L_SPECIES.maskAll(true).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.NE); + + testCompareMaskNotLong(L_SPECIES_FOR_CAST, VectorOperators.NE, (m) -> { return m.cast(I_SPECIES_FOR_CAST).not(); }); + verifyResultsLong(L_SPECIES_FOR_CAST, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareLTMaskNotLong() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); + verifyResultsLong(L_SPECIES, VectorOperators.LT); + testCompareMaskNotLong(L_SPECIES, VectorOperators.LT, (m) -> { return L_SPECIES.maskAll(true).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.LT); + + testCompareMaskNotLong(L_SPECIES_FOR_CAST, VectorOperators.LT, (m) -> { return m.cast(I_SPECIES_FOR_CAST).not(); }); + verifyResultsLong(L_SPECIES_FOR_CAST, VectorOperators.LT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareGTMaskNotLong() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); + verifyResultsLong(L_SPECIES, VectorOperators.GT); + testCompareMaskNotLong(L_SPECIES, VectorOperators.GT, (m) -> { return L_SPECIES.maskAll(true).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.GT); + + testCompareMaskNotLong(L_SPECIES_FOR_CAST, VectorOperators.GT, (m) -> { return m.cast(I_SPECIES_FOR_CAST).not(); }); + verifyResultsLong(L_SPECIES_FOR_CAST, VectorOperators.GT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareLEMaskNotLong() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); + verifyResultsLong(L_SPECIES, VectorOperators.LE); + testCompareMaskNotLong(L_SPECIES, VectorOperators.LE, (m) -> { return L_SPECIES.maskAll(true).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.LE); + + testCompareMaskNotLong(L_SPECIES_FOR_CAST, VectorOperators.LE, (m) -> { return m.cast(I_SPECIES_FOR_CAST).not(); }); + verifyResultsLong(L_SPECIES_FOR_CAST, VectorOperators.LE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareGEMaskNotLong() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); + verifyResultsLong(L_SPECIES, VectorOperators.GE); + testCompareMaskNotLong(L_SPECIES, VectorOperators.GE, (m) -> { return L_SPECIES.maskAll(true).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.GE); + + testCompareMaskNotLong(L_SPECIES_FOR_CAST, VectorOperators.GE, (m) -> { return m.cast(I_SPECIES_FOR_CAST).not(); }); + verifyResultsLong(L_SPECIES_FOR_CAST, VectorOperators.GE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareULTMaskNotLong() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); + verifyResultsLong(L_SPECIES, VectorOperators.ULT); + testCompareMaskNotLong(L_SPECIES, VectorOperators.ULT, (m) -> { return L_SPECIES.maskAll(true).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.ULT); + + testCompareMaskNotLong(L_SPECIES_FOR_CAST, VectorOperators.ULT, (m) -> { return m.cast(I_SPECIES_FOR_CAST).not(); }); + verifyResultsLong(L_SPECIES_FOR_CAST, VectorOperators.ULT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareUGTMaskNotLong() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); + verifyResultsLong(L_SPECIES, VectorOperators.UGT); + testCompareMaskNotLong(L_SPECIES, VectorOperators.UGT, (m) -> { return L_SPECIES.maskAll(true).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.UGT); + + testCompareMaskNotLong(L_SPECIES_FOR_CAST, VectorOperators.UGT, (m) -> { return m.cast(I_SPECIES_FOR_CAST).not(); }); + verifyResultsLong(L_SPECIES_FOR_CAST, VectorOperators.UGT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareULEMaskNotLong() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); + verifyResultsLong(L_SPECIES, VectorOperators.ULE); + testCompareMaskNotLong(L_SPECIES, VectorOperators.ULE, (m) -> { return L_SPECIES.maskAll(true).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.ULE); + + testCompareMaskNotLong(L_SPECIES_FOR_CAST, VectorOperators.ULE, (m) -> { return m.cast(I_SPECIES_FOR_CAST).not(); }); + verifyResultsLong(L_SPECIES_FOR_CAST, VectorOperators.ULE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CAST, "= 1", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareUGEMaskNotLong() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); + verifyResultsLong(L_SPECIES, VectorOperators.UGE); + testCompareMaskNotLong(L_SPECIES, VectorOperators.UGE, (m) -> { return L_SPECIES.maskAll(true).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.UGE); + + testCompareMaskNotLong(L_SPECIES_FOR_CAST, VectorOperators.UGE, (m) -> { return m.cast(I_SPECIES_FOR_CAST).not(); }); + verifyResultsLong(L_SPECIES_FOR_CAST, VectorOperators.UGE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareEQMaskNotFloat() { + testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fb, (m) -> { return m.not(); }); + verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fb); + testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fb, (m) -> { return F_SPECIES.maskAll(true).xor(m); }); + verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fb); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareNEMaskNotFloat() { + testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fb, (m) -> { return m.not(); }); + verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fb); + testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fb, (m) -> { return F_SPECIES.maskAll(true).xor(m); }); + verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fb); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareEQMaskNotFloatNaN() { + testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fnan, (m) -> { return m.not(); }); + verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fnan); + testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fnan, (m) -> { return F_SPECIES.maskAll(true).xor(m); }); + verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fnan); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareNEMaskNotFloatNaN() { + testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fnan, (m) -> { return m.not(); }); + verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fnan); + testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fnan, (m) -> { return F_SPECIES.maskAll(true).xor(m); }); + verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fnan); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareEQMaskNotFloatPositiveInfinity() { + testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fpinf, (m) -> { return m.not(); }); + verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fpinf); + testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fpinf, (m) -> { return F_SPECIES.maskAll(true).xor(m); }); + verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fpinf); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareNEMaskNotFloatPositiveInfinity() { + testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fpinf, (m) -> { return m.not(); }); + verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fpinf); + testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fpinf, (m) -> { return F_SPECIES.maskAll(true).xor(m); }); + verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fpinf); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareEQMaskNotFloatNegativeInfinity() { + testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fninf, (m) -> { return m.not(); }); + verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fninf); + testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fninf, (m) -> { return F_SPECIES.maskAll(true).xor(m); }); + verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fninf); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + public static void testCompareNEMaskNotFloatNegativeInfinity() { + testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fninf, (m) -> { return m.not(); }); + verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fninf); + testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fninf, (m) -> { return F_SPECIES.maskAll(true).xor(m); }); + verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fninf); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareEQMaskNotDouble() { + testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, db, (m) -> { return m.not(); }); + verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, db); + testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, db, (m) -> { return D_SPECIES.maskAll(true).xor(m); }); + verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, db); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareNEMaskNotDouble() { + testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, db, (m) -> { return m.not(); }); + verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, db); + testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, db, (m) -> { return D_SPECIES.maskAll(true).xor(m); }); + verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, db); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareEQMaskNotDoubleNaN() { + testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dnan, (m) -> { return m.not(); }); + verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dnan); + testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dnan, (m) -> { return D_SPECIES.maskAll(true).xor(m); }); + verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dnan); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareNEMaskNotDoubleNaN() { + testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dnan, (m) -> { return m.not(); }); + verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dnan); + testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dnan, (m) -> { return D_SPECIES.maskAll(true).xor(m); }); + verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dnan); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareEQMaskNotDoublePositiveInfinity() { + testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dpinf, (m) -> { return m.not(); }); + verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dpinf); + testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dpinf, (m) -> { return D_SPECIES.maskAll(true).xor(m); }); + verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dpinf); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareNEMaskNotDoublePositiveInfinity() { + testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dpinf, (m) -> { return m.not(); }); + verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dpinf); + testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dpinf, (m) -> { return D_SPECIES.maskAll(true).xor(m); }); + verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dpinf); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareEQMaskNotDoubleNegativeInfinity() { + testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dninf, (m) -> { return m.not(); }); + verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dninf); + testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dninf, (m) -> { return D_SPECIES.maskAll(true).xor(m); }); + verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dninf); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + public static void testCompareNEMaskNotDoubleNegativeInfinity() { + testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dninf, (m) -> { return m.not(); }); + verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dninf); + testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dninf, (m) -> { return D_SPECIES.maskAll(true).xor(m); }); + verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dninf); + } + + // negative tests + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + @IR(counts = { IRNode.XOR_V, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "avx2", "true" }) + public static void testCompareMaskNotByteNegative() { + testCompareMaskNotByte(B_SPECIES, VectorOperators.EQ, (m) -> { + // The vector mask is used multiple times. + ic[0] = m.trueCount(); + return m.not(); + }); + verifyResultsByte(B_SPECIES, VectorOperators.EQ); + + // One of the operands of XOR is not all ones vector. + testCompareMaskNotByte(B_SPECIES, VectorOperators.EQ, (m) -> { return B_SPECIES.maskAll(false).xor(m); }); + verifyResultsByte(B_SPECIES, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + @IR(counts = { IRNode.XOR_V, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "avx2", "true" }) + public static void testCompareMaskNotShortNegative() { + testCompareMaskNotShort(S_SPECIES, VectorOperators.EQ, (m) -> { + // The vector mask is used multiple times. + ic[0] = m.trueCount(); + return m.not(); + }); + verifyResultsShort(S_SPECIES, VectorOperators.EQ); + + // One of the operands of XOR is not all ones vector. + testCompareMaskNotShort(S_SPECIES, VectorOperators.EQ, (m) -> { return S_SPECIES.maskAll(false).xor(m); }); + verifyResultsShort(S_SPECIES, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + @IR(counts = { IRNode.XOR_V, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "avx2", "true" }) + public static void testCompareMaskNotIntNegative() { + testCompareMaskNotInt(I_SPECIES, VectorOperators.EQ, (m) -> { + // The vector mask is used multiple times. + ic[0] = m.trueCount(); + return m.not(); + }); + verifyResultsInt(I_SPECIES, VectorOperators.EQ); + + // One of the operands of XOR is not all ones vector. + testCompareMaskNotInt(I_SPECIES, VectorOperators.EQ, (m) -> { return I_SPECIES.maskAll(false).xor(m); }); + verifyResultsInt(I_SPECIES, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + @IR(counts = { IRNode.XOR_V, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V, "= 2", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "avx2", "true" }) + public static void testCompareMaskNotLongNegative() { + testCompareMaskNotLong(L_SPECIES, VectorOperators.EQ, (m) -> { + // The vector mask is used multiple times. + ic[0] = m.trueCount(); + return m.not(); + }); + verifyResultsLong(L_SPECIES, VectorOperators.EQ); + + // One of the operands of XOR is not all ones vector. + testCompareMaskNotLong(L_SPECIES, VectorOperators.EQ, (m) -> { return L_SPECIES.maskAll(false).xor(m); }); + verifyResultsLong(L_SPECIES, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 3", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + @IR(counts = { IRNode.XOR_V, "= 3", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V, "= 3", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureAnd = { "avx2", "true" }) + public static void testCompareMaskNotFloatNegative() { + testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fb, (m) -> { + // The vector mask is used multiple times. + ic[0] = m.trueCount(); + return m.not(); + }); + verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fb); + + // One of the operands of XOR is not all ones vector. + testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fb, (m) -> { return F_SPECIES.maskAll(false).xor(m); }); + verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fb); + + // Float vectors use the LT comparison. + testCompareMaskNotFloat(F_SPECIES, VectorOperators.LT, fa, fb, (m) -> { return m.not(); }); + verifyResultsFloat(F_SPECIES, VectorOperators.LT, fa, fb); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 3", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + @IR(counts = { IRNode.XOR_V, "= 3", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V, "= 3", + IRNode.VECTOR_MASK_CMP, "= 3" }, + applyIfCPUFeatureAnd = { "avx2", "true" }) + public static void testCompareMaskNotDoubleNegative() { + testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, db, (m) -> { + // The vector mask is used multiple times. + ic[0] = m.trueCount(); + return m.not(); + }); + verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, db); + + // One of the operands of XOR is not all ones vector. + testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, db, (m) -> { return D_SPECIES.maskAll(false).xor(m); }); + verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, db); + + // Double vectors use the LT comparison. + testCompareMaskNotDouble(D_SPECIES, VectorOperators.LT, da, db, (m) -> { return m.not(); }); + verifyResultsDouble(D_SPECIES, VectorOperators.LT, da, db); + } + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(5000) + .addFlags("--add-modules=jdk.incubator.vector") + .start(); + } +} diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -291,8 +291,12 @@ // ---------------- Convert F/D to I/L ---------------- @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", ">0"}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public int[] convertFloatToInt() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -302,8 +306,12 @@ } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", ">0"}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public long[] convertFloatToLong() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -313,8 +321,12 @@ } @Test - @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", ">0"}) + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public int[] convertDoubleToInt() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -324,8 +336,12 @@ } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", ">0"}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public long[] convertDoubleToLong() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -336,9 +352,15 @@ // ---------------- Convert F/D to Subword-I ---------------- @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, - counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", ">0"}) + applyIfCPUFeature = {"avx10_2", "true"}) public short[] convertFloatToShort() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -355,9 +377,15 @@ } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"}, applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, - counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", ">0"}) + counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeature = {"avx10_2", "true"}) public char[] convertFloatToChar() { char[] res = new char[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -376,7 +404,16 @@ @Test @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=32"}, - counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", ">0"}) + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"}) + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"}, + applyIf = {"MaxVectorSize", ">=16"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIf = {"MaxVectorSize", ">=16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIf = {"MaxVectorSize", ">=16"}, + applyIfCPUFeature = {"avx10_2", "true"}) public short[] convertDoubleToShort() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -387,8 +424,17 @@ @Test @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"}, - applyIf = {"MaxVectorSize", ">=32"}, - counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", ">0"}) + applyIf = {"MaxVectorSize", ">= 32"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"}) + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"}, + applyIf = {"MaxVectorSize", ">= 16"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIf = {"MaxVectorSize", ">=16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIf = {"MaxVectorSize", ">=16"}, + applyIfCPUFeature = {"avx10_2", "true"}) public char[] convertDoubleToChar() { char[] res = new char[SIZE]; for (int i = 0; i < SIZE; i++) { diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/DockerBasicTest.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/DockerBasicTest.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/DockerBasicTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/DockerBasicTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build HelloDocker @@ -45,10 +46,7 @@ private static final String imageNameAndTag = Common.imageName("basic"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageNameAndTag); try { diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/ShareTmpDir.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/ShareTmpDir.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/ShareTmpDir.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/ShareTmpDir.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build WaitForFlagFile * @run driver ShareTmpDir */ @@ -50,10 +51,7 @@ private static final String imageName = Common.imageName("sharetmpdir"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,9 +48,8 @@ private static final int availableCPUs = Runtime.getRuntime().availableProcessors(); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); DockerTestUtils.buildJdkContainerImage(imageName); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestCPUSets.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestCPUSets.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestCPUSets.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestCPUSets.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ * @requires (os.arch != "s390x") * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build AttemptOOM jdk.test.whitebox.WhiteBox PrintContainerInfo @@ -52,11 +53,8 @@ private static final String imageName = Common.imageName("cpusets"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestContainerInfo.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestContainerInfo.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestContainerInfo.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestContainerInfo.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build CheckContainerized jdk.test.whitebox.WhiteBox PrintContainerInfo @@ -49,10 +50,7 @@ private static final String imageName = Common.imageName("container-info"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestJFREvents.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJFREvents.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestJFREvents.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJFREvents.java 2026-10-19 12:10:20.000000000 +0000 @@ -34,6 +34,7 @@ * @modules java.base/jdk.internal.platform * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build JfrReporter @@ -59,9 +60,7 @@ public static void main(String[] args) throws Exception { System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); // If cgroups is not configured, report success. Metrics metrics = Metrics.systemMetrics(); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build JfrNetwork @@ -48,10 +49,7 @@ public static void main(String[] args) throws Exception { System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build EventProducer @@ -73,9 +74,7 @@ static final AtomicReference ipAddr = new AtomicReference(); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - throw new SkippedException("Docker is not supported on this host"); - } + DockerTestUtils.checkCanTestDocker(); if (DockerTestUtils.isPodman() & !Platform.isRoot()) { throw new SkippedException("test cannot be run under rootless podman configuration"); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestJcmd.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJcmd.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestJcmd.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJcmd.java 2026-10-19 12:10:20.000000000 +0000 @@ -29,6 +29,7 @@ * @requires container.support * @requires vm.flagless * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @library /test/lib @@ -62,7 +63,7 @@ public static void main(String[] args) throws Exception { - DockerTestUtils.canTestDocker(); + DockerTestUtils.checkCanTestDocker(); // podman versions below 3.3.1 hava a bug where cross-container testing with correct // permissions fails. See JDK-8273216 diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ * @requires vm.flagless * @requires !vm.asan * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @library /test/lib @@ -95,10 +96,7 @@ private static final String NET_BIND_SERVICE = "--cap-add=NET_BIND_SERVICE"; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(IMAGE_NAME); try { diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. - * 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. * @@ -32,6 +32,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build jdk.test.whitebox.WhiteBox LimitUpdateChecker * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox * @run driver TestLimitsUpdating @@ -48,16 +49,18 @@ import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; import jdk.test.lib.process.OutputAnalyzer; +import jtreg.SkippedException; public class TestLimitsUpdating { + private static final int CPU_PERIOD = 100_000; + private static final int INITIAL_CPU_COUNT = 1; + private static final int UPDATED_CPU_COUNT = 2; private static final String TARGET_CONTAINER = "limitsUpdatingHS_" + Runtime.getRuntime().version().major(); private static final String imageName = Common.imageName("limitsUpdating"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); @@ -69,6 +72,10 @@ } private static void testLimitUpdates() throws Exception { + if (Runtime.getRuntime().availableProcessors() < UPDATED_CPU_COUNT) { + throw new SkippedException("Need at least " + UPDATED_CPU_COUNT + + " available CPUs to test CPU limit updates"); + } File sharedtmpdir = new File("test-sharedtmp"); File flag = new File(sharedtmpdir, "limitsUpdated"); // shared with LimitUpdateChecker File started = new File(sharedtmpdir, "started"); // shared with LimitUpdateChecker @@ -78,8 +85,8 @@ DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "LimitUpdateChecker"); opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/"); opts.addDockerOpts("--volume", sharedtmpdir.getAbsolutePath() + ":/tmp"); - opts.addDockerOpts("--cpu-period", "100000"); - opts.addDockerOpts("--cpu-quota", "200000"); + opts.addDockerOpts("--cpu-period", Integer.toString(CPU_PERIOD)); + opts.addDockerOpts("--cpu-quota", Integer.toString(INITIAL_CPU_COUNT * CPU_PERIOD)); opts.addDockerOpts("--memory", "500m"); opts.addDockerOpts("--memory-swap", "500m"); opts.addDockerOpts("--name", TARGET_CONTAINER); @@ -104,7 +111,7 @@ Thread.sleep(100); } - final List containerCommand = getContainerUpdate(300_000, 100_000, "300m"); + final List containerCommand = getContainerUpdate(UPDATED_CPU_COUNT * CPU_PERIOD, CPU_PERIOD, "300m"); // Run the update command so as to increase resources once the container signaled it has started. Thread t2 = new Thread() { public void run() { @@ -127,8 +134,8 @@ // Do assertions based on the output in target container OutputAnalyzer targetOut = out[0]; - targetOut.shouldContain("active_processor_count: 2"); // initial value - targetOut.shouldContain("active_processor_count: 3"); // updated value + targetOut.shouldContain("active_processor_count: 1"); // initial value + targetOut.shouldContain("active_processor_count: 2"); // updated value targetOut.shouldContain("memory_limit_in_bytes: 512000 k"); // initial value targetOut.shouldContain("memory_and_swap_limit_in_bytes: 512000 k"); // initial value targetOut.shouldContain("memory_limit_in_bytes: 307200 k"); // updated value diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java 2026-10-19 12:10:20.000000000 +0000 @@ -59,10 +59,7 @@ } public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java 2026-10-19 12:10:20.000000000 +0000 @@ -55,10 +55,7 @@ System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (C) 2022, Tencent. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,10 +52,8 @@ return; } if ("cgroupv1".equals(metrics.getProvider())) { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java 2026-10-19 12:10:20.000000000 +0000 @@ -52,10 +52,7 @@ System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestMisc.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMisc.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestMisc.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestMisc.java 2026-10-19 12:10:20.000000000 +0000 @@ -46,14 +46,10 @@ public class TestMisc { - private static final Metrics metrics = Metrics.systemMetrics(); private static final String imageName = Common.imageName("misc"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); @@ -102,14 +98,8 @@ // Test the mapping function on cgroups v2. Should also pass on cgroups v1 as it's // a direct mapping there. private static void testPrintContainerInfoCPUShares() throws Exception { - // Test won't work on cgv1 rootless podman since resource limits don't - // work there. - if ("cgroupv1".equals(metrics.getProvider()) && - DockerTestUtils.isPodman() && - DockerTestUtils.isRootless()) { - throw new SkippedException("Resource limits required for testPrintContainerInfoCPUShares(). " + - "This is cgv1 with podman in rootless mode. Test skipped."); - } + // Test won't work on cgv1 rootless since resource limits don't work there. + DockerTestUtils.checkCanUseResourceLimits(); // Anything less than 1024 should return the back-mapped cpu-shares value without // rounding to next multiple of 1024 (on cg v2). Only ensure that we get // 'cpu_shares: ' over 'cpu_shares: no shares'. diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestPids.java openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestPids.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/containers/docker/TestPids.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/containers/docker/TestPids.java 2026-10-19 12:10:20.000000000 +0000 @@ -31,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * @build jdk.test.whitebox.WhiteBox PrintContainerInfo * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox @@ -54,10 +55,8 @@ static final String warning_kernel_no_pids_support = "WARNING: Your kernel does not support pids limit capabilities"; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/gc/TestNativeReferenceGet.java openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/TestNativeReferenceGet.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/gc/TestNativeReferenceGet.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/TestNativeReferenceGet.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package gc; + +/** + * @test + * @bug 8352565 + * @summary Determine whether the native method implementation of + * Reference.get() works as expected. Disable the intrinsic implementation to + * force use of the native method. + * @library /test/lib + * @modules java.base/java.lang.ref:open + * @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:DisableIntrinsic=_Reference_get0 + * gc.TestNativeReferenceGet + */ + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import jdk.test.whitebox.WhiteBox; + +public final class TestNativeReferenceGet { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + private static void gcUntilOld(Object o) { + while (!WB.isObjectInOldGen(o)) { + WB.fullGC(); + } + } + + private static final class TestObject { + public final int value; + + public TestObject(int value) { + this.value = value; + } + } + + private static final ReferenceQueue queue = + new ReferenceQueue(); + + private static final class Ref extends WeakReference { + public Ref(TestObject obj) { + super(obj, queue); + } + } + + private static final int NUM_REFS = 100; + + private static List references = null; + private static List referents = null; + + // Create all the objects used by the test, and ensure they are all in the + // old generation. + private static void setup() { + references = new ArrayList(NUM_REFS); + referents = new ArrayList(NUM_REFS); + + for (int i = 0; i < NUM_REFS; ++i) { + TestObject obj = new TestObject(i); + referents.add(obj); + references.add(new Ref(obj)); + } + + gcUntilOld(references); + gcUntilOld(referents); + for (int i = 0; i < NUM_REFS; ++i) { + gcUntilOld(references.get(i)); + gcUntilOld(referents.get(i)); + } + } + + // Discard all the strong references. + private static void dropReferents() { + // Not using List.clear() because it doesn't document null'ing elements. + for (int i = 0; i < NUM_REFS; ++i) { + referents.set(i, null); + } + } + + // Create new strong references from the weak references, by using the + // native method implementation of Reference.get() and recording the value + // in references. + private static void strengthenReferents() { + for (int i = 0; i < NUM_REFS; ++i) { + referents.set(i, references.get(i).get()); + } + } + + private static void check() { + // None of the references should have been cleared and enqueued, + // because we have strong references to all the referents. + try { + while (WB.waitForReferenceProcessing()) {} + } catch (InterruptedException e) { + throw new RuntimeException("Test interrupted"); + } + if (queue.poll() != null) { + throw new RuntimeException("Reference enqueued"); + } + + // Check details of expected state. + for (int i = 0; i < NUM_REFS; ++i) { + Ref reference = (Ref) references.get(i); + TestObject referent = reference.get(); + if (referent == null) { + throw new RuntimeException("Referent not strengthened"); + } else if (referent != referents.get(i)) { + throw new RuntimeException( + "Reference referent differs from saved referent: " + i); + } else if (referent.value != i) { + throw new RuntimeException( + "Referent " + i + " value: " + referent.value); + } + } + } + + private static void testConcurrent() { + System.out.println("Testing concurrent GC"); + try { + WB.concurrentGCAcquireControl(); + dropReferents(); + WB.concurrentGCRunTo(WB.BEFORE_MARKING_COMPLETED); + strengthenReferents(); + WB.concurrentGCRunToIdle(); + check(); + } finally { + WB.concurrentGCReleaseControl(); + } + } + + private static void testNonconcurrent() { + System.out.println("Testing nonconcurrent GC"); + // A GC between clearing and strengthening will result in test failure. + // We try to make that unlikely via this immediately preceeding GC. + WB.fullGC(); + dropReferents(); + strengthenReferents(); + WB.fullGC(); + check(); + } + + public static final void main(String[] args) { + setup(); + if (WB.supportsConcurrentGCBreakpoints()) { + testConcurrent(); + } else { + testNonconcurrent(); + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -44,6 +44,7 @@ import java.util.Arrays; import java.util.stream.Stream; +import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -62,8 +63,11 @@ String[] selectedArgs = args[0].equals("G1") ? g1Args : parallelArgs; + final String[] vm64bitArgs = { + "-XX:-UseCompactObjectHeaders" // Object sizes are calculated such that the heap is tight. + }; + final String[] commonArgs = { - "-XX:-UseCompactObjectHeaders", // Object sizes are calculated such that the heap is tight. "-XX:ParallelGCThreads=1", // Make GCs take longer. "-XX:+UseGCOverheadLimit", "-Xlog:gc=debug", @@ -72,7 +76,9 @@ Allocating.class.getName() }; - String[] vmArgs = Stream.concat(Arrays.stream(selectedArgs), Arrays.stream(commonArgs)).toArray(String[]::new); + String[] vmArgs = Stream.of(selectedArgs, Platform.is64bit() ? vm64bitArgs : new String[0], commonArgs) + .flatMap(Arrays::stream) + .toArray(String[]::new); OutputAnalyzer output = ProcessTools.executeLimitedTestJava(vmArgs); output.shouldNotHaveExitValue(0); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 2026-10-19 12:10:20.000000000 +0000 @@ -46,6 +46,7 @@ import java.util.List; public class CompressedClassSpaceSizeInJmapHeap { + // Note that on some platforms it may require root privileges to run this test. public static void main(String[] args) throws Exception { SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. @@ -67,8 +68,15 @@ File err = new File("CompressedClassSpaceSizeInJmapHeap.stderr.txt"); pb.redirectError(err); - run(pb); - + // If we attempt to attach to LingeredApp before it has initialized, the heap dump request will fail, so we allow 3 tries + int allowedTries = 3; + int exitValue; + do { + exitValue = run(pb); + } while ((exitValue != 0) && (allowedTries-- > 0)); + if (exitValue != 0) { + throw new Exception("jmap -heap exited with error code: " + exitValue); + } OutputAnalyzer output = new OutputAnalyzer(read(out)); output.shouldContain("CompressedClassSpaceSize = 50331648 (48.0MB)"); out.delete(); @@ -76,12 +84,9 @@ LingeredApp.stopApp(theApp); } - private static void run(ProcessBuilder pb) throws Exception { + private static int run(ProcessBuilder pb) throws Exception { OutputAnalyzer output = ProcessTools.executeProcess(pb); - int exitValue = output.getExitValue(); - if (exitValue != 0) { - throw new Exception("jmap -heap exited with error code: " + exitValue); - } + return output.getExitValue(); } private static String read(File f) throws Exception { diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java 2026-10-19 12:10:20.000000000 +0000 @@ -24,7 +24,9 @@ /* * @test id=default + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -50,7 +52,9 @@ /* * @test id=default-verify + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -80,8 +84,81 @@ */ /* + * @test id=passive + * @key randomness + * @summary Test clone barriers work correctly + * @library /test/lib + * @requires vm.gc.Shenandoah + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:TieredStopAtLevel=4 + * TestClone + */ + +/* + * @test id=passive-verify + * @key randomness + * @summary Test clone barriers work correctly + * @library /test/lib + * @requires vm.gc.Shenandoah + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:+ShenandoahVerify + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:+ShenandoahVerify + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:+ShenandoahVerify + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=4 + * TestClone + */ + +/* * @test id=aggressive + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -106,8 +183,43 @@ */ /* + * @test id=aggressive-verify + * @key randomness + * @summary Test clone barriers work correctly + * @library /test/lib + * @requires vm.gc.Shenandoah + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:+ShenandoahVerify + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:+ShenandoahVerify + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:+ShenandoahVerify + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=4 + * TestClone + */ + +/* * @test id=no-coops + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * @requires vm.bits == "64" * @@ -139,7 +251,9 @@ /* * @test id=no-coops-verify + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * @requires vm.bits == "64" * @@ -176,7 +290,9 @@ /* * @test id=no-coops-aggressive + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * @requires vm.bits == "64" * @@ -208,7 +324,9 @@ /* * @test id=generational + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -234,7 +352,9 @@ /* * @test id=generational-small-card-size + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -260,129 +380,272 @@ /* * @test id=generational-verify + * @key randomness + * @summary Test clone barriers work correctly + * @library /test/lib + * @requires vm.gc.Shenandoah + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:+ShenandoahVerify + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:+ShenandoahVerify + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:+ShenandoahVerify + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=4 + * TestClone + */ + +/* + * @test id=generational-no-coops + * @key randomness + * @summary Test clone barriers work correctly + * @library /test/lib + * @requires vm.gc.Shenandoah + * @requires vm.bits == "64" + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:TieredStopAtLevel=4 + * TestClone + */ +/* + * @test id=generational-no-coops-verify + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah + * @requires vm.bits == "64" * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * -XX:+ShenandoahVerify * TestClone * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * -XX:+ShenandoahVerify * -Xint * TestClone * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * -XX:+ShenandoahVerify * -XX:-TieredCompilation * TestClone * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * -XX:+ShenandoahVerify * -XX:TieredStopAtLevel=1 * TestClone * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * -XX:+ShenandoahVerify * -XX:TieredStopAtLevel=4 * TestClone */ - /* - * @test id=generational-no-coops - * @summary Test clone barriers work correctly - * @requires vm.gc.Shenandoah - * @requires vm.bits == "64" - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -Xint - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:-TieredCompilation - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:TieredStopAtLevel=1 - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:TieredStopAtLevel=4 - * TestClone - */ - - /* - * @test id=generational-no-coops-verify - * @summary Test clone barriers work correctly - * @requires vm.gc.Shenandoah - * @requires vm.bits == "64" - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:+ShenandoahVerify - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:+ShenandoahVerify - * -Xint - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:+ShenandoahVerify - * -XX:-TieredCompilation - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:+ShenandoahVerify - * -XX:TieredStopAtLevel=1 - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:+ShenandoahVerify - * -XX:TieredStopAtLevel=4 - * TestClone - */ +import java.util.Random; + +import jdk.test.lib.Utils; public class TestClone { + private static final int ENTRIES = 1_000; + private static final int ITERS = 50_000; + private static final int ARRAY_MAX_SIZE = 128; + private static final Random RAND = Utils.getRandomInstance(); + private static final SmallObject[] SMALL = new SmallObject[ENTRIES]; + private static final LargeObject[] LARGE = new LargeObject[ENTRIES]; + private static final Ref[][] ARRAY = new Ref[ENTRIES][]; + public static void main(String[] args) throws Exception { - for (int i = 0; i < 10000; i++) { - Object[] src = new Object[i]; - for (int c = 0; c < src.length; c++) { - src[c] = new Object(); - } - testWith(src); + // Seed + for (int i = 0; i < ENTRIES; i++) { + SMALL[i] = new SmallObject(i); + LARGE[i] = new LargeObject(i); + ARRAY[i] = newArray(i); + } + + // Random clone and verify + for (int i = 0; i < ITERS; i++) { + cloneAndVerify(); + } + + // Verify everything + for (int i = 0; i < ENTRIES; i++) { + verify(SMALL[i], i); + verify(LARGE[i], i); + verify(ARRAY[i], i); + } + } + + static void cloneAndVerify() { + int r = RAND.nextInt(ENTRIES); + SMALL[r] = SMALL[r].clone(); + LARGE[r] = LARGE[r].clone(); + ARRAY[r] = ARRAY[r].clone(); + + // Verify will trigger LRB. + // We don't want LRB to heal refs in the clone source or target, + // so we verify a different random location. + r = RAND.nextInt(ENTRIES); + verify(SMALL[r], r); + verify(LARGE[r], r); + verify(ARRAY[r], r); + } + + static Ref[] newArray(int id) { + int size = id % ARRAY_MAX_SIZE; + Ref[] arr = new Ref[size]; + for (int i = 0; i < size; i++) { + arr[i] = new Ref(elementValue(id, i)); } + return arr; + } + + static void verify(SmallObject src, int id) { + assertEquals(elementValue(id, 0), src.x1.x); + assertEquals(elementValue(id, 1), src.x2.x); + assertEquals(elementValue(id, 2), src.x3.x); + assertEquals(elementValue(id, 3), src.x4.x); } - static void testWith(Object[] src) { - Object[] dst = src.clone(); + static void verify(LargeObject src, int id) { + assertEquals(elementValue(id, 0), src.x01.x); + assertEquals(elementValue(id, 1), src.x02.x); + assertEquals(elementValue(id, 2), src.x03.x); + assertEquals(elementValue(id, 3), src.x04.x); + assertEquals(elementValue(id, 4), src.x05.x); + assertEquals(elementValue(id, 5), src.x06.x); + assertEquals(elementValue(id, 6), src.x07.x); + assertEquals(elementValue(id, 7), src.x08.x); + assertEquals(elementValue(id, 8), src.x09.x); + assertEquals(elementValue(id, 9), src.x10.x); + assertEquals(elementValue(id, 10), src.x11.x); + assertEquals(elementValue(id, 11), src.x12.x); + assertEquals(elementValue(id, 12), src.x13.x); + assertEquals(elementValue(id, 13), src.x14.x); + assertEquals(elementValue(id, 14), src.x15.x); + assertEquals(elementValue(id, 15), src.x16.x); + } + + static void assertEquals(int expected, int actual) { + if (actual != expected) { + throw new IllegalStateException("Mismatch: expected=" + expected + ", actual=" + actual); + } + } + + static void verify(Ref[] src, int id) { + int expectedLen = id % ARRAY_MAX_SIZE; int srcLen = src.length; - int dstLen = dst.length; - if (srcLen != dstLen) { - throw new IllegalStateException("Lengths do not match: " + srcLen + " vs " + dstLen); - } - for (int c = 0; c < src.length; c++) { - Object s = src[c]; - Object d = dst[c]; - if (s != d) { - throw new IllegalStateException("Elements do not match at " + c + ": " + s + " vs " + d); + if (srcLen != expectedLen) { + throw new IllegalStateException("Lengths do not match: " + srcLen + " vs " + expectedLen); + } + for (int i = 0; i < src.length; i++) { + int expectedVal = elementValue(id, i); + int val = src[i].x; + if (val != expectedVal) { + throw new IllegalStateException("Elements do not match at " + i + ": " + val + " vs " + expectedVal + ", len = " + srcLen); } } } + + static int elementValue(int id, int offset) { + // Globally unique (per type). + return ENTRIES * id + offset; + } + + static class Ref { + int x; + + Ref(int x) { + this.x = x; + } + } + + abstract static class DefaultClone implements Cloneable { + @Override + @SuppressWarnings("unchecked") + public T clone() { + try { + return (T) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(e); + } + } + } + + static class SmallObject extends DefaultClone { + Ref x1, x2, x3, x4; + + SmallObject(int x) { + x1 = new Ref(elementValue(x, 0)); + x2 = new Ref(elementValue(x, 1)); + x3 = new Ref(elementValue(x, 2)); + x4 = new Ref(elementValue(x, 3)); + } + } + + static class LargeObject extends DefaultClone { + Ref x01, x02, x03, x04, x05, x06, x07, x08; + Ref x09, x10, x11, x12, x13, x14, x15, x16; + + LargeObject(int x) { + x01 = new Ref(elementValue(x, 0)); + x02 = new Ref(elementValue(x, 1)); + x03 = new Ref(elementValue(x, 2)); + x04 = new Ref(elementValue(x, 3)); + x05 = new Ref(elementValue(x, 4)); + x06 = new Ref(elementValue(x, 5)); + x07 = new Ref(elementValue(x, 6)); + x08 = new Ref(elementValue(x, 7)); + x09 = new Ref(elementValue(x, 8)); + x10 = new Ref(elementValue(x, 9)); + x11 = new Ref(elementValue(x, 10)); + x12 = new Ref(elementValue(x, 11)); + x13 = new Ref(elementValue(x, 12)); + x14 = new Ref(elementValue(x, 13)); + x15 = new Ref(elementValue(x, 14)); + x16 = new Ref(elementValue(x, 15)); + } + } } diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/gtest/ShenandoahGtests.java openjdk-25-25.0.5+8/test/hotspot/jtreg/gtest/ShenandoahGtests.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/gtest/ShenandoahGtests.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/gtest/ShenandoahGtests.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * 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 + * @summary Run Shenandoah gtests + * @library /test/lib + * @requires vm.gc.Shenandoah + * @requires vm.debug + * @run main/native GTestWrapper --gtest_filter=Shenandoah* + */ diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -64,7 +64,7 @@ assertTrue(Files.exists(hsErrPath)); Pattern[] positivePatterns = { - Pattern.compile(".*Internal Error \\(0x2a\\).*") + Pattern.compile(".*Internal Error \\(0xdeadbeef\\).*") }; HsErrFileUtils.checkHsErrFileContent(hsErrFile, positivePatterns, null, true /* check end marker */, false /* verbose */); } diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/ErrorHandling/libNativeException.c openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/ErrorHandling/libNativeException.c --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/ErrorHandling/libNativeException.c 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/ErrorHandling/libNativeException.c 2026-10-19 12:10:20.000000000 +0000 @@ -25,7 +25,10 @@ #include -const DWORD EX_CODE = 42; +// Use an exception code that causes the Windows FAILED() macro to return true. +// Windows AArch64 uses vectored exception handling and therefore runs error +// reporting only for failed exception codes. +const DWORD EX_CODE = 0xdeadbeef; JNIEXPORT void JNICALL Java_UncaughtNativeExceptionTest_00024Crasher_throwException(JNIEnv* env, jclass cls) { RaiseException(EX_CODE, EXCEPTION_NONCONTINUABLE, 0, NULL); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java 2026-10-19 12:10:20.000000000 +0000 @@ -63,10 +63,9 @@ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); private static final Path MODS_DIR = Paths.get(TEST_CLASSES, "mods"); - // Windows has source information only in full pdbs, not in stripped pdbs - private static boolean expectSourceInformation = Platform.isLinux() || Platform.isWindows(); - - static WhiteBox wb = WhiteBox.getWhiteBox(); + // In some configurations on Windows, we could have stripped pdbs which do not have source information. + private static boolean expectSourceInformation = (Platform.isLinux() || Platform.isWindows()) && + WhiteBox.getWhiteBox().shipsFullDebugInfo(); /* The stack trace we look for by default. Note that :: has been replaced by .* to make sure it matches even if the symbol is not unmangled. @@ -145,12 +144,8 @@ throw new RuntimeException("Expected stack trace missing from output"); } - if (wb.hasExternalSymbolsStripped()) { - expectSourceInformation = false; - } - - System.out.println("Looking for source information:"); if (expectSourceInformation) { + System.out.println("Looking for source information:"); if (!stackTraceMatches(".*moduleEntry.cpp.*", output)) { output.reportDiagnosticSummary(); throw new RuntimeException("Expected source information missing from output"); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheConsistency.java openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheConsistency.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheConsistency.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheConsistency.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * 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 + * @key randomness + * @summary AOTCacheConsistency This test checks that there is a CRC validation of the AOT Cache regions. + * @bug 8382166 + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib + * @build jdk.test.whitebox.WhiteBox AOTCacheConsistency + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar HelloApp + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AOTCacheConsistency + */ + +import jdk.test.lib.cds.CDSArchiveUtils; +import jdk.test.lib.cds.SimpleCDSAppTester; +import jdk.test.lib.process.OutputAnalyzer; +import java.io.File; + +public class AOTCacheConsistency { + public static void main(String args[]) throws Exception { + // Train and run the app + SimpleCDSAppTester tester = SimpleCDSAppTester.of("AOTCacheConsistency") + .classpath("app.jar") + .appCommandLine("HelloApp") + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("HelloWorld"); + }) + .runAOTWorkflow(); + + String aotCache = tester.aotCacheFile(); + + String[] regions = CDSArchiveUtils.getRegions(); + String orig = aotCache + ".orig"; + CDSArchiveUtils.copyArchiveFile(new File(aotCache), orig); // save original copy + + // Modify each of the region individually. The production should fail to run + // with these args; + String extraVMArgs[] = {"-XX:+VerifySharedSpaces", "-XX:AOTMode=on"}; + tester.setCheckExitValue(false); + + for (int i = 0; i < regions.length; i++) { + File f = CDSArchiveUtils.copyArchiveFile(new File(orig), aotCache); + System.out.println("\n=======\nTesting region " + i + " = " + regions[i]); + if (CDSArchiveUtils.modifyRegionContent(i, f)) { + tester.setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("Checksum verification failed."); + }); + tester.rerunProduction(extraVMArgs); + } + } + } +} + +class HelloApp { + public static void main(String[] args) { + System.out.println("HelloWorld"); + } +} \ No newline at end of file diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ChangedJarFile.java openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ChangedJarFile.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ChangedJarFile.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ChangedJarFile.java 2026-10-19 12:10:20.000000000 +0000 @@ -59,7 +59,7 @@ tester.productionRun(new String[] {"-XX:AOTMode=auto", "-Xlog:aot"}, new String[] {"jarHasChanged"}); out.shouldMatch("This file is not the one used while building the " + - "AOT cache: '.*app.jar', timestamp has changed, size has changed"); + "AOT cache: '.*app.jar',.* size has changed"); } static class Tester extends CDSAppTester { diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -128,6 +128,7 @@ case RunMode.ASSEMBLY: { List args = getVMArgsForHeapConfig(zeroBaseInAsmPhase, zeroShiftInAsmPhase); args.addAll(List.of("-XX:+UnlockDiagnosticVMOptions", + "-XX:+AOTAdapterCaching", "-Xlog:aot=info", "-Xlog:aot+codecache+init=debug", "-Xlog:aot+codecache+exit=debug")); @@ -136,6 +137,7 @@ case RunMode.PRODUCTION: { List args = getVMArgsForHeapConfig(zeroBaseInProdPhase, zeroShiftInProdPhase); args.addAll(List.of("-XX:+UnlockDiagnosticVMOptions", + "-XX:+AOTAdapterCaching", "-Xlog:aot=info", // we need this to parse CompressedOops settings "-Xlog:aot+codecache+init=debug", "-Xlog:aot+codecache+exit=debug")); diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /** + * @test + * @bug 8375125 + * @summary Trigger StringTable::clean_dead_entries or SymbolTable::clean_dead_entries + * with -XX:TrimNativeHeapInterval enabled,should not violate lock ordering. + * @requires vm.debug + * @requires vm.gc != "Epsilon" + * @library /test/lib + * @modules java.compiler + * @run main/othervm -Xms128m -Xmx128m + * -XX:TrimNativeHeapInterval=300000 + * TestTrimNativeHeapIntervalTablesCleanup string + * @run main/othervm -Xms128m -Xmx128m + * -XX:TrimNativeHeapInterval=300000 + * TestTrimNativeHeapIntervalTablesCleanup symbol + */ + +import java.util.LinkedList; +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +public class TestTrimNativeHeapIntervalTablesCleanup { + + public static void main(String[] args) throws Exception{ + if (args.length != 1) { + throw new IllegalArgumentException("Expected 1 argument: string|symbol"); + } + switch (args[0]) { + case "string": + testStringTableCleanup(); + break; + case "symbol": + testSymbolTableCleanup(); + break; + default: + throw new IllegalArgumentException("Unknown mode: " + args[0]); + } + System.out.println("passed: " + args[0]); + } + + static void testStringTableCleanup() throws Exception{ + final int rounds = 30; + final int maxSize = 200_000; + final int pruneEvery = 50_000; + final int pruneCount = 25_000; + long stringNum = 0; + + for (int round = 0; round < rounds; round++) { + LinkedList list = new LinkedList<>(); + for (int i = 0; i < maxSize; i++, stringNum++) { + if (i != 0 && (i % pruneEvery) == 0) { + int toRemove = Math.min(pruneCount, list.size()); + list.subList(0, toRemove).clear(); + } + list.push(Long.toString(stringNum).intern()); + } + System.gc(); + Thread.sleep(1000); + } + } + + static void testSymbolTableCleanup() throws Exception { + final int rounds = 10; + final int classesPerRound = 100; + + for (int r = 0; r < rounds; r++) { + for (int i = 0; i < classesPerRound; i++) { + String cn = "C" + r + "_" + i; + byte[] bytes = InMemoryJavaCompiler.compile( + cn, + "public class " + cn + " { int m" + i + "() { return " + i + "; } }" + ); + new ClassLoader(null) { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (!name.equals(cn)) throw new ClassNotFoundException(name); + return defineClass(name, bytes, 0, bytes.length); + } + }.loadClass(cn).getDeclaredConstructor().newInstance(); + } + System.gc(); + Thread.sleep(1000); + } + } +} \ No newline at end of file diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/serviceability/dcmd/thread/PrintTest.java openjdk-25-25.0.5+8/test/hotspot/jtreg/serviceability/dcmd/thread/PrintTest.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/serviceability/dcmd/thread/PrintTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/serviceability/dcmd/thread/PrintTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,6 +168,9 @@ output.shouldNotMatch(jucLockPattern1); output.shouldNotMatch(jucLockPattern2); } + + /* Check for presence of version string */ + output.shouldContain("JDK version:"); } @Test diff -Nru openjdk-25-25.0.4.1+1/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java openjdk-25-25.0.5+8/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java --- openjdk-25-25.0.4.1+1/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -605,6 +605,9 @@ {"windows-x64", "com.sun.jdi.CommandLineLaunch", "dt_socket"}, {"windows-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"}, + {"windows-aarch64", "com.sun.jdi.CommandLineLaunch", "dt_socket"}, + {"windows-aarch64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"}, + {"macosx-amd64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"macosx-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, diff -Nru openjdk-25-25.0.4.1+1/test/jaxp/TEST.ROOT openjdk-25-25.0.5+8/test/jaxp/TEST.ROOT --- openjdk-25-25.0.4.1+1/test/jaxp/TEST.ROOT 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jaxp/TEST.ROOT 2026-10-19 12:10:20.000000000 +0000 @@ -23,7 +23,7 @@ groups=TEST.groups # Minimum jtreg version -requiredVersion=8+2 +requiredVersion=8.2.1+1 # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../ notation to reach them diff -Nru openjdk-25-25.0.4.1+1/test/jdk/ProblemList.txt openjdk-25-25.0.5+8/test/jdk/ProblemList.txt --- openjdk-25-25.0.4.1+1/test/jdk/ProblemList.txt 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/ProblemList.txt 2026-10-19 12:10:20.000000000 +0000 @@ -248,7 +248,6 @@ sun/awt/shell/ShellFolderMemoryLeak.java 8197794 windows-all sun/java2d/DirectX/OverriddenInsetsTest/OverriddenInsetsTest.java 8196102 generic-all sun/java2d/DirectX/RenderingToCachedGraphicsTest/RenderingToCachedGraphicsTest.java 8196180 windows-all,macosx-all -sun/java2d/OpenGL/MultiWindowFillTest.java 8378506 macosx-all sun/java2d/OpenGL/OpaqueDest.java#id1 8367574 macosx-all sun/java2d/OpenGL/ScaleParamsOOB.java#id0 8377908 linux-all sun/java2d/SunGraphics2D/EmptyClipRenderingTest.java 8144029 macosx-all,linux-all @@ -640,19 +639,9 @@ ############################################################################ # jdk_sound -javax/sound/sampled/DirectAudio/bug6372428.java 8055097 generic-all -javax/sound/sampled/Clip/bug5070081.java 8055097 generic-all -javax/sound/sampled/DataLine/LongFramePosition.java 8055097 generic-all javax/sound/sampled/Clip/Drain/ClipDrain.java 7062792 generic-all -javax/sound/sampled/Mixers/DisabledAssertionCrash.java 7067310 generic-all - -javax/sound/midi/Sequencer/Recording.java 8167580,8265485 linux-all,macosx-aarch64 -javax/sound/midi/Sequencer/Looping.java 8136897 generic-all -javax/sound/sampled/Clip/ClipIsRunningAfterStop.java 8307574 linux-x64 -javax/sound/sampled/Clip/ClipFlushCrash.java 8308395 linux-x64 - ############################################################################ # jdk_imageio diff -Nru openjdk-25-25.0.4.1+1/test/jdk/TEST.ROOT openjdk-25-25.0.5+8/test/jdk/TEST.ROOT --- openjdk-25-25.0.4.1+1/test/jdk/TEST.ROOT 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/TEST.ROOT 2026-10-19 12:10:20.000000000 +0000 @@ -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 file identifies the root of the test-suite hierarchy. @@ -59,7 +59,7 @@ java/rmi/Naming java/util/prefs sun/management/jmxremote \ sun/tools/jstatd sun/security/mscapi java/util/Arrays/largeMemory \ java/util/BitSet/stream javax/rmi java/net/httpclient/websocket \ -com/sun/net/httpserver/simpleserver sun/tools/jhsdb +com/sun/net/httpserver/simpleserver sun/tools/jhsdb javax/sound # Group definitions groups=TEST.groups @@ -121,7 +121,7 @@ jdk.static # Minimum jtreg version -requiredVersion=8+2 +requiredVersion=8.2.1+1 # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../ notation to reach them diff -Nru openjdk-25-25.0.4.1+1/test/jdk/TEST.groups openjdk-25-25.0.5+8/test/jdk/TEST.groups --- openjdk-25-25.0.4.1+1/test/jdk/TEST.groups 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/TEST.groups 2026-10-19 12:10:20.000000000 +0000 @@ -109,8 +109,7 @@ / \ -:tier1 \ -:tier2 \ - -:tier3 \ - :jdk_foreign_stress + -:tier3 ############################################################################### # @@ -393,11 +392,7 @@ jdk_foreign = \ java/foreign \ jdk/internal/reflect/CallerSensitive/CheckCSMs.java \ - -java/foreign/TestMatrix.java \ - -java/foreign/TestUpcallStress.java - -jdk_foreign_stress = \ - java/foreign/TestUpcallStress.java + -java/foreign/TestMatrix.java jdk_vector = \ jdk/incubator/vector diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java openjdk-25-25.0.5+8/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8014618 + * @bug 8014618 8368694 * @summary Need to strip leading zeros in TlsPremasterSecret of DHKeyAgreement * @author Pasi Eronen */ @@ -88,6 +88,26 @@ throw new Exception("First byte is not zero as expected"); } + // generate generic shared secret + aliceKeyAgree.init(alicePrivKey); + aliceKeyAgree.doPhase(bobPubKey, true); + byte[] genericSecret = + aliceKeyAgree.generateSecret("Generic").getEncoded(); + System.out.println("generic secret:\n" + HEX_FORMATTER.formatHex(genericSecret)); + + // verify that leading zero is present + if (genericSecret.length != 256) { + throw new Exception("Unexpected generic secret length"); + } + if (genericSecret[0] != 0) { + throw new Exception("First byte is not zero as expected"); + } + for (int i = 0; i < genericSecret.length; i++) { + if (genericSecret[i] != sharedSecret[i]) { + throw new Exception("Shared secrets differ"); + } + } + // now, test TLS premaster secret aliceKeyAgree.init(alicePrivKey); aliceKeyAgree.doPhase(bobPubKey, true); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java openjdk-25-25.0.5+8/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,7 @@ import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -238,6 +239,7 @@ void testBlockedThread(ThreadFactory factory, boolean pinned) throws Exception { var lock = new Object(); + String lockAsString = Objects.toIdentityString(lock); var started = new CountDownLatch(1); Thread thread = factory.newThread(() -> { @@ -258,9 +260,7 @@ thread.start(); started.await(); await(thread, Thread.State.BLOCKED); - long tid = thread.threadId(); - String lockAsString = Objects.toIdentityString(lock); // thread dump in plain text should include thread List lines = dumpThreadsToPlainText(); @@ -308,6 +308,7 @@ void testWaitingThread(ThreadFactory factory, boolean pinned) throws Exception { var lock = new Object(); + String lockAsString = Objects.toIdentityString(lock); var started = new CountDownLatch(1); Thread thread = factory.newThread(() -> { @@ -331,9 +332,7 @@ thread.start(); started.await(); await(thread, Thread.State.WAITING); - long tid = thread.threadId(); - String lockAsString = Objects.toIdentityString(lock); // thread dump in plain text should include thread List lines = dumpThreadsToPlainText(); @@ -417,7 +416,6 @@ thread.start(); started.await(); await(thread, Thread.State.WAITING); - long tid = thread.threadId(); // thread dump in plain text should include thread @@ -460,7 +458,7 @@ } /** - * Test thread dump with a thread owning a monitor. + * Test thread dump with a thread owning monitors. */ @ParameterizedTest @MethodSource("threadFactories") @@ -475,19 +473,26 @@ } void testThreadOwnsMonitor(ThreadFactory factory, boolean pinned) throws Exception { - var lock = new Object(); - var started = new CountDownLatch(1); + var lock1 = new Object(); + var lock2 = new Object(); + var lock3 = new Object(); + String lock1AsString = Objects.toIdentityString(lock1); + String lock2AsString = Objects.toIdentityString(lock2); + String lock3AsString = Objects.toIdentityString(lock3); + var started = new CountDownLatch(1); Thread thread = factory.newThread(() -> { - synchronized (lock) { - if (pinned) { - VThreadPinner.runPinned(() -> { + synchronized (lock1) { + synchronized (lock2) { + if (pinned) { + VThreadPinner.runPinned(() -> { + started.countDown(); + lockAndRun(lock3, LockSupport::park); + }); + } else { started.countDown(); - LockSupport.park(); - }); - } else { - started.countDown(); - LockSupport.park(); + lockAndRun(lock3, LockSupport::park); + } } } }); @@ -497,16 +502,16 @@ thread.start(); started.await(); await(thread, Thread.State.WAITING); - long tid = thread.threadId(); - String lockAsString = Objects.toIdentityString(lock); // thread dump in plain text should include thread List lines = dumpThreadsToPlainText(); ThreadFields fields = findThread(tid, lines); assertNotNull(fields, "thread not found"); assertEquals("WAITING", fields.state()); - assertTrue(contains(lines, "- locked <" + lockAsString)); + assertTrue(contains(lines, "- locked <" + lock1AsString)); + assertTrue(contains(lines, "- locked <" + lock2AsString)); + assertTrue(contains(lines, "- locked <" + lock3AsString)); // thread dump in JSON format should include thread in root container ThreadDump threadDump = dumpThreadsToJson(); @@ -516,18 +521,47 @@ assertNotNull(ti, "thread not found"); assertEquals(ti.isVirtual(), thread.isVirtual()); - // the lock should be in the ownedMonitors array - Set ownedMonitors = ti.ownedMonitors().values() + // depth -> list of locks + Map> ownedMonitors = ti.ownedMonitors(); + + // lock -> list of depths + Map> monitorDepths = ownedMonitors.entrySet() .stream() - .flatMap(List::stream) - .collect(Collectors.toSet()); - assertTrue(ownedMonitors.contains(lockAsString), lockAsString + " not found"); + .flatMap(e -> e.getValue() + .stream() + .map(monitor -> Map.entry(monitor, e.getKey()))) + .collect(Collectors.groupingBy( + Map.Entry::getKey, + Collectors.mapping(Map.Entry::getValue, Collectors.toList()) + )); + + // each lock should be owned + List lock1Depths = monitorDepths.getOrDefault(lock1AsString, List.of()); + List lock2Depths = monitorDepths.getOrDefault(lock2AsString, List.of()); + List lock3Depths = monitorDepths.getOrDefault(lock3AsString, List.of()); + assertEquals(1, lock1Depths.size()); + assertEquals(1, lock2Depths.size()); + assertEquals(1, lock3Depths.size()); + + // lock1 and lock2 owned at the same depth, lock3 is the innermost + int depth1 = lock1Depths.get(0); + int depth2 = lock2Depths.get(0); + int depth3 = lock3Depths.get(0); + assertEquals(depth1, depth2); + assertTrue(depth3 < depth1); + } finally { LockSupport.unpark(thread); thread.join(); } } + private void lockAndRun(Object lock, Runnable action) { + synchronized (lock) { + action.run(); + } + } + /** * Test mounted virtual thread. */ diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8373677 + * @summary Tests for verifying that a non-SSL server can detect + * when a client attempts to use SSL. + * @library /test/lib + * @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.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLException; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static org.junit.jupiter.api.Assertions.*; + +public class ClearTextServerSSL { + + static final InetAddress LOOPBACK_ADDR = InetAddress.getLoopbackAddress(); + static final boolean ENABLE_LOGGING = true; + static final Logger logger = Logger.getLogger("com.sun.net.httpserver"); + static final long RSPBODY_EMPTY = -1l; + + static final String CTXT_PATH = "/ClearTextServerSSL"; + + @BeforeAll + public static void setup() { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + logger.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + logger.addHandler(ch); + } + } + + @Test + public void test() throws Exception { + var sslContext = new SimpleSSLContext().get(); + var handler = new TestHandler(); + var server = HttpServer.create(new InetSocketAddress(LOOPBACK_ADDR, 0), 0); + server.createContext(path(""), handler); + server.start(); + try (var client = HttpClient.newBuilder() + .sslContext(sslContext) + .proxy(NO_PROXY) + .build()) { + var request = HttpRequest.newBuilder() + .uri(uri("http", server, path("/clear"))) + .build(); + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + var sslRequest = HttpRequest.newBuilder() + .uri(uri("https", server, path("/ssl"))) + .build(); + Assertions.assertThrows(SSLException.class, () -> { + client.send(sslRequest, HttpResponse.BodyHandlers.ofString()); + }); + try (var socket = new Socket()) { + socket.connect(server.getAddress()); + byte[] badRequest = { + 22, 'B', 'A', 'D', ' ', + '/', ' ' , + 'H', 'T', 'T', 'P', '/', '1', '.', '1' }; + socket.getOutputStream().write(badRequest); + socket.getOutputStream().flush(); + var reader = new InputStreamReader(socket.getInputStream()); + var line = reader.readAllLines(); + Assertions.assertEquals("HTTP/1.1 400 Bad Request", line.get(0)); + System.out.println("Got expected response:"); + line.stream().map(l -> "\t" + l).forEach(System.out::println); + } + + } finally { + server.stop(0); + } + } + + // --- infra --- + + static String path(String path) { + assert CTXT_PATH.startsWith("/"); + assert !CTXT_PATH.endsWith("/"); + if (path.startsWith("/")) { + return CTXT_PATH + path; + } else { + return CTXT_PATH + "/" + path; + } + } + + static URI uri(String scheme, HttpServer server, String path) throws URISyntaxException { + return URIBuilder.newBuilder() + .scheme(scheme) + .loopback() + .port(server.getAddress().getPort()) + .path(path) + .build(); + } + + /** + * A test handler that reads any request bytes and sends + * an empty 200 response + */ + static class TestHandler implements HttpHandler { + @java.lang.Override + public void handle(HttpExchange exchange) throws IOException { + try (var reqBody = exchange.getRequestBody()) { + reqBody.readAllBytes(); + exchange.sendResponseHeaders(200, RSPBODY_EMPTY); + } catch (Throwable t) { + t.printStackTrace(); + exchange.sendResponseHeaders(500, RSPBODY_EMPTY); + } + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/Test10.java openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test10.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/Test10.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test10.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,11 @@ * @test * @bug 7005016 * @summary pit jdk7 b121 sqe test jhttp/HttpServer150013 failing - * @run main/othervm -Dsun.net.httpserver.clockTick=1000 -Dsun.net.httpserver.idleInterval=3 Test10 * @run main/othervm -Dsun.net.httpserver.clockTick=1000 -Dsun.net.httpserver.idleInterval=3 - * -Djava.net.preferIPv6Addresses Test10 + * -Dsun.net.httpserver.disableHostValidation=true Test10 + * @run main/othervm -Dsun.net.httpserver.clockTick=1000 -Dsun.net.httpserver.idleInterval=3 + * -Djava.net.preferIPv6Addresses + * -Dsun.net.httpserver.disableHostValidation=true Test10 */ import com.sun.net.httpserver.*; @@ -41,6 +43,7 @@ */ public class Test10 extends Test { + static volatile boolean handlerInvoked; public static void main (String[] args) throws Exception { System.out.print ("Test10: "); Handler handler = new Handler(); @@ -65,10 +68,10 @@ } static class Handler implements HttpHandler { - volatile int invocation = 0; public void handle (HttpExchange t) throws IOException { + handlerInvoked = true; InputStream is = t.getRequestBody(); while (is.read() != -1); Headers map = t.getRequestHeaders(); @@ -88,6 +91,9 @@ int c; byte[] b = new byte [1024]; while ((c=is.read(b)) != -1) ; + if (!handlerInvoked) { + throw new RuntimeException("Handler not invoked"); + } is.close(); socket.close(); } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/Test3.java openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test3.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/Test3.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test3.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,13 +124,13 @@ "HTTP/1.1 200 OK.*Xtest: 3.*"; public static void doClient (int port) throws Exception { - String s = "GET /test/1.html HTTP/1.1\r\nContent-length: 20\r\n"+ + String s = "GET /test/1.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 20\r\n"+ "\r\n" +body1 + - "GET /test/2.html HTTP/1.1\r\nContent-length: 30\r\n"+ + "GET /test/2.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 30\r\n"+ "\r\n"+ body2 + - "GET /test/3.html HTTP/1.1\r\nContent-length: 10\r\n"+ + "GET /test/3.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 10\r\n"+ "\r\n"+ body3 + - "GET /test/4.html HTTP/1.1\r\nContent-length: 10\r\n"+ + "GET /test/4.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 10\r\n"+ "\r\n"+body4; Socket socket = new Socket (InetAddress.getLoopbackAddress(), port); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/Test4.java openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test4.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/Test4.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test4.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,13 +123,13 @@ "HTTP/1.1 200 OK.*Xtest: 3.*"; public static void doClient (int port) throws Exception { - String s = "GET /test/1.html HTTP/1.1\r\nContent-length: 20\r\n"+ + String s = "GET /test/1.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 20\r\n"+ "\r\n" +body1 + - "GET /test/2.html HTTP/1.1\r\nContent-length: 30\r\n"+ + "GET /test/2.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 30\r\n"+ "\r\n"+ body2 + - "GET /test/3.html HTTP/1.1\r\nContent-length: 10\r\n"+ + "GET /test/3.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 10\r\n"+ "\r\n"+ body3 + - "GET /test/4.html HTTP/1.1\r\nContent-length: 10\r\n"+ + "GET /test/4.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 10\r\n"+ "\r\n"+body4; Socket socket = new Socket (InetAddress.getLoopbackAddress(), port); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/Test5.java openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test5.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/Test5.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/Test5.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,13 +122,13 @@ "HTTP/1.1 200 OK.*Xtest: 3.*"; public static void doClient (int port) throws Exception { - String s = "GET /test/1.html HTTP/1.1\r\nContent-length: 20\r\n"+ + String s = "GET /test/1.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 20\r\n"+ "\r\n" +body1 + - "GET /test/2.html HTTP/1.1\r\nContent-length: 30\r\n"+ + "GET /test/2.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 30\r\n"+ "\r\n"+ body2 + - "GET /test/3.html HTTP/1.1\r\nContent-length: 10\r\n"+ + "GET /test/3.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 10\r\n"+ "\r\n"+ body3 + - "GET /test/4.html HTTP/1.1\r\nContent-length: 10\r\n"+ + "GET /test/4.html HTTP/1.1\r\nHost: localhost\r\nContent-length: 10\r\n"+ "\r\n"+body4; Socket socket = new Socket (InetAddress.getLoopbackAddress(), port); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/bugs/B6361557.java openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/B6361557.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/bugs/B6361557.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/B6361557.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import java.nio.*; import java.nio.channels.*; import java.net.*; +import java.util.concurrent.atomic.AtomicInteger; /** * The test simply opens 1,000 separate connections @@ -48,12 +49,14 @@ public static boolean error = false; static final int NUM = 1000; + static final AtomicInteger count = new AtomicInteger(0); static class Handler implements HttpHandler { int invocation = 1; public void handle (HttpExchange t) throws IOException { + count.getAndIncrement(); InputStream is = t.getRequestBody(); Headers map = t.getRequestHeaders(); Headers rmap = t.getResponseHeaders(); @@ -64,7 +67,9 @@ } } - final static String request = "GET /test/foo.html HTTP/1.1\r\nContent-length: 0\r\n\r\n"; + final static String request = "GET /test/foo.html HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Content-length: 0\r\n\r\n"; final static ByteBuffer requestBuf = ByteBuffer.wrap(request.getBytes()); public static void main (String[] args) throws Exception { @@ -126,6 +131,9 @@ break; } } + if (count.get() != NUM) { + throw new RuntimeException("Unexpected number of handled requests: " +count.get()); + } server.stop(0); selector.close(); executor.shutdown (); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/bugs/B6393710.java openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/B6393710.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/bugs/B6393710.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/B6393710.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,11 +57,13 @@ */ static String cmd = "POST /test/foo HTTP/1.1"+CRLF+ + "Host: localhost"+CRLF+ "Content-Length: 22"+CRLF+ "Pragma: no-cache"+CRLF+ "Cache-Control: no-cache"+CRLF+ CRLF+ ""+ "POST /test/foo HTTP/1.1"+CRLF+ + "Host: localhost"+CRLF+ "Content-Length: 22"+CRLF+ "Pragma: no-cache"+CRLF+ "Authorization: Basic ZnJlZDpmcmVkcGFzc3dvcmQ="+CRLF+ diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/bugs/B6433018.java openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/B6433018.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/bugs/B6433018.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/B6433018.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ static final String cmd = "POST /test/item HTTP/1.1"+CRLF+ + "Host: araku:9999"+CRLF+ "Keep-Alive: 300"+CRLF+ "Proxy-Connection: keep-alive"+CRLF+ "Content-Type: text/xml"+CRLF+ diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java 2026-10-19 12:10:20.000000000 +0000 @@ -103,7 +103,8 @@ // Test 1: fixed length Socket sock = new Socket(loopback, port); - String s1 = "POST /foo HTTP/1.1\r\nContent-length: 200000\r\n" + String s1 = "POST /foo HTTP/1.1\r\nHost: localhost\r\n" + + "Content-length: 200000\r\n" + "\r\nfoo bar99"; OutputStream os = sock.getOutputStream(); @@ -114,7 +115,8 @@ // Test 2: chunked - String s2 = "POST /foo HTTP/1.1\r\nTransfer-encoding: chunked\r\n\r\n" + + String s2 = "POST /foo HTTP/1.1\r\nHost: localhost\r\n" + + "Transfer-encoding: chunked\r\n\r\n" + "100\r\nFoo bar"; sock = new Socket(loopback, port); os = sock.getOutputStream(); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java --- openjdk-25-25.0.4.1+1/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -23,27 +23,33 @@ /* * @test + * @key randomness * @bug 8278398 * @summary Tests the jwebserver's maximum request time * @modules jdk.httpserver * @library /test/lib + * @build jdk.test.lib.RandomFactory * @run junit/othervm MaxRequestTimeTest */ import java.io.IOException; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLException; + import jdk.test.lib.Platform; -import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.RandomFactory; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.util.FileUtils; @@ -61,16 +67,16 @@ * * The jwebserver has a maximum request time of 5 seconds, which is set with the * "sun.net.httpserver.maxReqTime" system property. If this threshold is - * reached, for example in the case of an HTTPS request where the server keeps - * waiting for a plaintext request, the server closes the connection. Subsequent + * reached, the server closes the connection. Subsequent * requests are expected to be handled as normal. * * The test checks in the following order that: * 1. an HTTP request is handled successfully, - * 2. an HTTPS request fails due to the server closing the connection + * 2. an incomplete HTTP request fails due to the server closing the connection * 3. another HTTP request is handled successfully. */ public class MaxRequestTimeTest { + private static final Random RND = RandomFactory.getRandom(); static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); static final String LOCALE_OPT = "-J-Duser.language=en -J-Duser.country=US"; static final String JWEBSERVER = getJwebserver(JAVA_HOME); @@ -79,8 +85,6 @@ static final String LOOPBACK_ADDR = InetAddress.getLoopbackAddress().getHostAddress(); static final AtomicInteger PORT = new AtomicInteger(); - private static final SSLContext sslContext = SimpleSSLContext.findSSLContext(); - @BeforeAll public static void setup() throws IOException { if (Files.exists(TEST_DIR)) { @@ -94,10 +98,10 @@ final var sb = new StringBuffer(); // stdout & stderr final var p = startProcess("jwebserver", sb); try { - sendHTTPSRequest(); // server expected to terminate connection - sendHTTPRequest(); // server expected to respond successfully - sendHTTPSRequest(); // server expected to terminate connection - sendHTTPRequest(); // server expected to respond successfully + sendIncompleteRequest(); // server expected to terminate connection + sendCompleteRequest(); // server expected to respond successfully + sendIncompleteRequest(); // server expected to terminate connection + sendCompleteRequest(); // server expected to respond successfully } finally { p.destroy(); int exitCode = p.waitFor(); @@ -105,6 +109,12 @@ } } + static String requestText = """ + GET / HTTP/1.1\r + Host: localhost\r + \r + """; + static ByteBuffer requestBuffer = ByteBuffer.wrap(requestText.getBytes(StandardCharsets.UTF_8)); static String expectedBody = """ @@ -119,8 +129,8 @@ """; - static void sendHTTPRequest() throws IOException, InterruptedException { - out.println("\n--- sendHTTPRequest"); + static void sendCompleteRequest() throws IOException, InterruptedException { + out.println("\n--- sendCompleteRequest"); var client = HttpClient.newBuilder() .proxy(NO_PROXY) .build(); @@ -129,18 +139,21 @@ assertEquals(expectedBody, response.body()); } - static void sendHTTPSRequest() throws IOException, InterruptedException { - out.println("\n--- sendHTTPSRequest"); - var client = HttpClient.newBuilder() - .sslContext(sslContext) - .proxy(NO_PROXY) - .build(); - var request = HttpRequest.newBuilder(URI.create("https://localhost:" + PORT.get() + "/")).build(); - try { - client.send(request, HttpResponse.BodyHandlers.ofString()); - throw new RuntimeException("Expected SSLException not thrown"); - } catch (SSLException expected) { // server closes connection when max request time is reached - expected.printStackTrace(System.out); + static void sendIncompleteRequest() throws IOException { + out.println("\n--- sendIncompleteRequest"); + try (SocketChannel sc = SocketChannel.open( + new InetSocketAddress(LOOPBACK_ADDR, PORT.get()))) { + requestBuffer.clear(); + // only send a part of the HTTP request + int numBytes = RND.nextInt(1, requestBuffer.limit()); + System.out.println("Sending " + numBytes + " bytes"); + requestBuffer.limit(numBytes); + while (requestBuffer.hasRemaining()) { + sc.write(requestBuffer); + } + ByteBuffer responseBuffer = ByteBuffer.allocate(1); + int result = sc.read(responseBuffer); + assertEquals(-1, result); } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/awt/Graphics2D/ClearPolyLineUsingXORTest.java openjdk-25-25.0.5+8/test/jdk/java/awt/Graphics2D/ClearPolyLineUsingXORTest.java --- openjdk-25-25.0.4.1+1/test/jdk/java/awt/Graphics2D/ClearPolyLineUsingXORTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/awt/Graphics2D/ClearPolyLineUsingXORTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,95 @@ +/* + * 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 + * @key headful + * @bug 8387593 + * @summary Tests that clearing a polyline using XOR mode does not + * leave any traces. Using uiScale 1 helps us to + * reproduce the issue. + * @run main/othervm -Dsun.java2d.uiScale=1 ClearPolyLineUsingXORTest + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; + +public class ClearPolyLineUsingXORTest { + private static final int SIZE = 500; + + private static BufferedImage clearUsingXOR(GraphicsConfiguration gc) { + VolatileImage vImg = gc.createCompatibleVolatileImage(SIZE, SIZE); + int attempt = 0; + while (true) { + if (++attempt > 10) { + throw new RuntimeException("Unable to use VolatileImage after " + + attempt + " attempts"); + } + + int status = vImg.validate(gc); + if (status == VolatileImage.IMAGE_INCOMPATIBLE) { + vImg = gc.createCompatibleVolatileImage(SIZE, SIZE); + } + + Graphics2D g2d = vImg.createGraphics(); + g2d.setBackground(Color.BLACK); + g2d.clearRect(0, 0, 500, 500); + + int min = 10; + int max = 210; + int mid = 110; + + int xdp[] = {min, max, min, max, min, max}; + int ydp[] = {min, min, mid, max, max, mid}; + + g2d.setXORMode(Color.GREEN); + g2d.drawPolygon(xdp, ydp, xdp.length); + g2d.drawPolygon(xdp, ydp, xdp.length); + + BufferedImage snapshot = vImg.getSnapshot(); + if (vImg.contentsLost()) { + continue; + } + return snapshot; + } + } + public static void main(String[] args) { + GraphicsConfiguration gc = + GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + BufferedImage bImg = clearUsingXOR(gc); + + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + if (bImg.getRGB(x, y) != Color.BLACK.getRGB()) { + throw new RuntimeException("Clear using XOR is not" + + " working at x: " + x + " y: " + y); + } + } + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java openjdk-25-25.0.5+8/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java --- openjdk-25-25.0.4.1+1/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java 2026-10-19 12:10:20.000000000 +0000 @@ -27,6 +27,8 @@ * @bug 6430601 8198613 * @summary Verifies that copyArea() works properly when the * destination parameters are outside the destination bounds. + * @library /test/lib + * @build jdk.test.lib.Platform * @run main/othervm CopyAreaOOB */ @@ -49,23 +51,29 @@ import java.io.File; import java.io.IOException; import java.util.List; - import javax.imageio.ImageIO; +import jdk.test.lib.Platform; public class CopyAreaOOB extends Canvas { + private static final int PRIMARY_TOLERANCE = 2; + private static int TOLERANCE = 30; + private static final boolean DEBUG = false; private static Frame frame; private static Robot robot; private static BufferedImage captureImg; - private static StringBuffer errorLog = new StringBuffer(); + private static final StringBuffer errorLog = new StringBuffer(); private static final Point OFF_FRAME_LOC = new Point(50, 50); private static final int SIZE = 400; public static void main(String[] args) throws Exception { try { - robot = new Robot(); + if (!Platform.isOSX()) { + TOLERANCE = PRIMARY_TOLERANCE; + } + robot = new Robot(); // added to move mouse pointer away from test UI // so that it is not captured in the screenshot robot.mouseMove(OFF_FRAME_LOC.x, OFF_FRAME_LOC.y); @@ -77,7 +85,7 @@ if (!errorLog.isEmpty()) { saveImages(); - throw new RuntimeException("Test failed: \n" + errorLog.toString()); + throw new RuntimeException("Test failed for the following region(s)" + errorLog); } } finally { if (frame != null) { @@ -101,13 +109,13 @@ int h = getHeight(); Graphics2D g2d = (Graphics2D)g; - g2d.setColor(Color.black); + g2d.setColor(Color.BLUE); g2d.fillRect(0, 0, w, h); - g2d.setColor(Color.green); + g2d.setColor(Color.GREEN); g2d.fillRect(0, 0, w, 10); - g2d.setColor(Color.red); + g2d.setColor(Color.RED); g2d.fillRect(0, 10, 50, h - 10); // copy the region such that part of it goes below the bottom of the @@ -123,12 +131,12 @@ captureImg = robot.createScreenCapture(rect); // Test pixels - testRegion("green", 0, 0, 400, 10, 0xff00ff00); - testRegion("original-red", 0, 10, 50, 400, 0xffff0000); - testRegion("background", 50, 10, 60, 400, 0xff000000); - testRegion("in-between", 60, 10, 110, 20, 0xff000000); - testRegion("copied-red", 60, 20, 110, 400, 0xffff0000); - testRegion("background", 110, 10, 400, 400, 0xff000000); + testRegion("green", 0, 0, 400, 10, Color.GREEN); + testRegion("original-red", 0, 10, 50, 400, Color.RED); + testRegion("background", 50, 10, 60, 400, Color.BLUE); + testRegion("in-between", 60, 10, 110, 20, Color.BLUE); + testRegion("copied-red", 60, 20, 110, 400, Color.RED); + testRegion("background", 110, 10, 400, 400, Color.BLUE); } public Dimension getPreferredSize() { @@ -137,24 +145,23 @@ private static void testRegion(String region, int x1, int y1, int x2, int y2, - int expected) { - System.out.print("Test region: " + region); + Color expected) { for (int y = y1; y < y2; y++) { for (int x = x1; x < x2; x++) { - int actual = captureImg.getRGB(x, y); - if (actual != expected) { - System.out.print(" Status: FAILED\n"); - errorLog.append("Test failed for " + region - + " region at x: " + x + " y: " + y - + " (expected: " - + Integer.toHexString(expected) - + " actual: " - + Integer.toHexString(actual) + ")\n"); + Color actual = new Color(captureImg.getRGB(x, y)); + if (DEBUG) { + System.out.println("Actual color: " + actual); + } + if (!compareColor(expected, actual)) { + errorLog.append("\nTest region: " + region + " Status: FAILED!!!\n"); + errorLog.append("Test failed at x : " + x + " y : " + y + "\n" + + "Expected Color: " + expected + "\n" + + "Actual Color: " + actual + "\n"); return; } } } - System.out.print(" Status: PASSED\n"); + System.out.println("Test region: " + region + " Status: PASSED"); } private static void saveImages() { @@ -173,4 +180,14 @@ System.err.println("Can't write image " + e); } } + + private static boolean compareColor(Color expected, Color actual) { + return Math.abs(expected.getRed() - actual.getRed()) + < (expected.equals(Color.RED) ? PRIMARY_TOLERANCE : TOLERANCE) + && Math.abs(expected.getGreen() - actual.getGreen()) + < (expected.equals(Color.GREEN) ? PRIMARY_TOLERANCE : TOLERANCE) + && Math.abs(expected.getBlue() - actual.getBlue()) + < (expected.equals(Color.BLUE) ? PRIMARY_TOLERANCE : TOLERANCE); + } } + diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java openjdk-25-25.0.5+8/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java --- openjdk-25-25.0.4.1+1/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.awt.Color; -import java.awt.Dialog; -import java.awt.Frame; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Panel; -import java.awt.Rectangle; -import java.awt.Robot; -import java.awt.SplashScreen; -import java.awt.TextField; -import java.awt.Window; -import java.awt.event.KeyEvent; -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.imageio.ImageIO; - -/** - * @test - * @key headful - * @bug 8145174 8151787 8168657 - * @summary HiDPI splash screen support on Linux - * @modules java.desktop/sun.java2d - * @requires (os.family == "linux") - * @run main UnixMultiResolutionSplashTest - */ - -public class UnixMultiResolutionSplashTest { - - private static final int IMAGE_WIDTH = 300; - private static final int IMAGE_HEIGHT = 200; - private static int inx = 0; - private static final ImageInfo[] tests = { - new ImageInfo("splash1.png", "splash1@200pct.png", Color.BLUE, Color.GREEN), - new ImageInfo("splash2", "splash2@2x", Color.WHITE, Color.BLACK), - new ImageInfo("splash3.", "splash3@200pct.", Color.YELLOW, Color.RED) - }; - - public static void main(String[] args) throws Exception { - - if (args.length == 0) { - generateImages(); - for (ImageInfo test : tests) { - createChildProcess(test); - } - } else { - int index = Integer.parseInt(args[0]); - testSplash(tests[index]); - } - } - - static void createChildProcess(ImageInfo test) { - String javaPath = System.getProperty("java.home"); - File file = new File(test.name1x); - String classPathDir = System.getProperty("java.class.path"); - Map env = new HashMap(); - env.put("GDK_SCALE", "2"); - int exitValue = doExec(env, javaPath + File.separator + "bin" + File.separator - + "java", "-splash:" + file.getAbsolutePath(), "-cp", - classPathDir, "UnixMultiResolutionSplashTest", String.valueOf(inx++)); - if (exitValue != 0) { - throw new RuntimeException("Test Failed"); - } - } - - static void testSplash(ImageInfo test) throws Exception { - SplashScreen splashScreen = SplashScreen.getSplashScreen(); - if (splashScreen == null) { - throw new RuntimeException("Splash screen is not shown!"); - } - Graphics2D g = splashScreen.createGraphics(); - Rectangle splashBounds = splashScreen.getBounds(); - int screenX = (int) splashBounds.getCenterX(); - int screenY = (int) splashBounds.getCenterY(); - Robot robot = new Robot(); - Color splashScreenColor = robot.getPixelColor(screenX, screenY); - - float scaleFactor = getScaleFactor(); - Color testColor = (1 < scaleFactor) ? test.color2x : test.color1x; - if (!compare(testColor, splashScreenColor)) { - throw new RuntimeException( - "Image with wrong resolution is used for splash screen!"); - } - } - - static int doExec(Map envToSet, String... cmds) { - Process p = null; - ProcessBuilder pb = new ProcessBuilder(cmds); - Map env = pb.environment(); - for (String cmd : cmds) { - System.out.print(cmd + " "); - } - System.out.println(); - if (envToSet != null) { - env.putAll(envToSet); - } - BufferedReader rdr = null; - try { - List outputList = new ArrayList<>(); - pb.redirectErrorStream(true); - p = pb.start(); - rdr = new BufferedReader(new InputStreamReader(p.getInputStream())); - String in = rdr.readLine(); - while (in != null) { - outputList.add(in); - in = rdr.readLine(); - System.out.println(in); - } - p.waitFor(); - p.destroy(); - } catch (Exception ex) { - ex.printStackTrace(); - } - return p.exitValue(); - } - - static void testFocus() throws Exception { - - System.out.println("Focus Test!"); - Robot robot = new Robot(); - robot.setAutoDelay(50); - Frame frame = new Frame(); - frame.setSize(100, 100); - String test = "123"; - TextField textField = new TextField(test); - textField.selectAll(); - frame.add(textField); - frame.setVisible(true); - robot.waitForIdle(); - - robot.keyPress(KeyEvent.VK_A); - robot.keyRelease(KeyEvent.VK_A); - robot.keyPress(KeyEvent.VK_B); - robot.keyRelease(KeyEvent.VK_B); - robot.waitForIdle(); - - frame.dispose(); - if (!textField.getText().equals("ab")) { - throw new RuntimeException("Focus is lost! " + - "Expected 'ab' got " + "'" + textField.getText() + "'."); - } - } - - static boolean compare(Color c1, Color c2) { - return compare(c1.getRed(), c2.getRed()) - && compare(c1.getGreen(), c2.getGreen()) - && compare(c1.getBlue(), c2.getBlue()); - } - - static boolean compare(int n, int m) { - return Math.abs(n - m) <= 50; - } - - static float getScaleFactor() { - - final Dialog dialog = new Dialog((Window) null); - dialog.setSize(100, 100); - dialog.setModal(true); - float[] scaleFactors = new float[1]; - Panel panel = new Panel() { - - @Override - public void paint(Graphics g) { - String scaleStr = System.getenv("GDK_SCALE"); - if (scaleStr != null && !scaleStr.equals("")) { - try { - scaleFactors[0] = Float.valueOf(scaleStr); - } catch (NumberFormatException ex) { - scaleFactors[0] = 1.0f; - } - } - dialog.setVisible(false); - } - }; - dialog.add(panel); - dialog.setVisible(true); - dialog.dispose(); - return scaleFactors[0]; - } - - static void generateImages() throws Exception { - for (ImageInfo test : tests) { - generateImage(test.name1x, test.color1x, 1); - generateImage(test.name2x, test.color2x, 2); - } - } - - static void generateImage(String name, Color color, int scale) throws Exception { - File file = new File(name); - if (file.exists()) { - return; - } - BufferedImage image = new BufferedImage(scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT, - BufferedImage.TYPE_INT_RGB); - Graphics g = image.getGraphics(); - g.setColor(color); - g.fillRect(0, 0, scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT); - ImageIO.write(image, "png", file); - } - - static class ImageInfo { - - final String name1x; - final String name2x; - final Color color1x; - final Color color2x; - - public ImageInfo(String name1x, String name2x, Color color1x, Color color2x) { - this.name1x = name1x; - this.name2x = name2x; - this.color1x = color1x; - this.color2x = color2x; - } - } -} - diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java openjdk-25-25.0.5+8/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java --- openjdk-25-25.0.4.1+1/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -79,13 +79,15 @@ public void test() throws AWTException, InterruptedException, InvocationTargetException { - EventQueue.invokeAndWait(() -> { - onScreen = text_field.getLocationOnScreen(); - size = text_field.getSize(); - }); Robot robot = new Robot(); robot.setAutoDelay(50); robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + onScreen = text_field.getLocationOnScreen(); + size = text_field.getSize(); + }); + int y = onScreen.y + (size.height / 2); robot.mouseMove(onScreen.x + (size.width / 2), y); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/foreign/TestUpcallStress.java openjdk-25-25.0.5+8/test/jdk/java/foreign/TestUpcallStress.java --- openjdk-25-25.0.4.1+1/test/jdk/java/foreign/TestUpcallStress.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/foreign/TestUpcallStress.java 2026-10-19 12:10:20.000000000 +0000 @@ -24,14 +24,13 @@ /* * @test * @requires jdk.foreign.linker != "FALLBACK" - * @requires (os.arch == "aarch64" | os.arch=="riscv64") & os.name == "Linux" - * @requires os.maxMemory > 4G * @requires vm.compMode != "Xcomp" * @modules java.base/jdk.internal.foreign + * @library /test/lib * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * @bug 8337753 * - * @run testng/native/othervm/timeout=3200 + * @run testng/native/othervm * -Xcheck:jni * -XX:+IgnoreUnrecognizedVMOptions * -XX:-VerifyDependencies @@ -44,7 +43,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.MemorySegment; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import jdk.test.lib.Utils; import java.lang.invoke.MethodHandle; import java.util.ArrayList; @@ -59,11 +61,27 @@ System.loadLibrary("TestUpcall"); } + static final int THREAD_COUNT = 100; + + ExecutorService executor; + + @BeforeClass + public void setup() { + executor = Executors.newFixedThreadPool(THREAD_COUNT); + } + + @AfterClass + public void tearDown() throws InterruptedException { + executor.shutdown(); + // Let it run for a while, and then just terminate + executor.awaitTermination(Utils.adjustTimeout(30), TimeUnit.SECONDS); + } + + @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) public void testUpcallsStress(int count, String fName, Ret ret, List paramTypes, - List fields) throws Throwable { - ExecutorService executor = Executors.newFixedThreadPool(16); - for (int threadIdx = 0; threadIdx < 16; threadIdx++) { + List fields) { + for (int threadIdx = 0; threadIdx < THREAD_COUNT; threadIdx++) { executor.submit(() -> { for (int iter = 0; iter < 10000; iter++) { List> returnChecks = new ArrayList<>(); @@ -91,8 +109,5 @@ } }); } - // This shutdownNow is 'wrong', since it doesn't wait for tasks to terminate, - // but it seems to be the only way to reproduce the race of JDK-8337753 - executor.shutdownNow(); } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/lang/ProcessBuilder/Basic.java openjdk-25-25.0.5+8/test/jdk/java/lang/ProcessBuilder/Basic.java --- openjdk-25-25.0.4.1+1/test/jdk/java/lang/ProcessBuilder/Basic.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/lang/ProcessBuilder/Basic.java 2026-10-19 12:10:20.000000000 +0000 @@ -224,7 +224,7 @@ private static String winEnvFilter(String env) { return env.replaceAll("\r", "") - .replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT)=.*\n",""); + .replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT|PROCESSOR_ARCHITECTURE)=.*\n",""); } private static String unixEnvProg() { @@ -822,6 +822,14 @@ return vars.replace("AIXTHREAD_GUARDPAGES=0,", ""); } + /* Only used for Windows AArch64 -- + * Windows AArch64 adds the variable PROCESSOR_ARCHITECTURE=ARM64 to the environment. + * Remove it from the list of env variables + */ + private static String removeWindowsAArch64ExpectedVars(String vars) { + return vars.replace("PROCESSOR_ARCHITECTURE=ARM64,", ""); + } + private static String sortByLinesWindowsly(String text) { String[] lines = text.split("\n"); Arrays.sort(lines, new WindowsComparator()); @@ -1348,6 +1356,9 @@ if (AIX.is()) { result = removeAixExpectedVars(result); } + if (Windows.is() && Platform.isAArch64()) { + result = removeWindowsAArch64ExpectedVars(result); + } equal(result, expected); } catch (Throwable t) { unexpected(t); } @@ -1860,6 +1871,9 @@ if (AIX.is()) { commandOutput = removeAixExpectedVars(commandOutput); } + if (Windows.is() && Platform.isAArch64()) { + commandOutput = removeWindowsAArch64ExpectedVars(commandOutput); + } equal(commandOutput, expected); if (Windows.is()) { ProcessBuilder pb = new ProcessBuilder(childArgs); @@ -1867,7 +1881,11 @@ pb.environment().put("SystemRoot", systemRoot); pb.environment().put("=ExitValue", "3"); pb.environment().put("=C:", "\\"); - equal(commandOutput(pb), expected); + commandOutput = commandOutput(pb); + if (Platform.isAArch64()) { + commandOutput = removeWindowsAArch64ExpectedVars(commandOutput); + } + equal(commandOutput, expected); } } catch (Throwable t) { unexpected(t); } @@ -1919,6 +1937,9 @@ if (AIX.is()) { commandOutput = removeAixExpectedVars(commandOutput); } + if (Windows.is() && Platform.isAArch64()) { + commandOutput = removeWindowsAArch64ExpectedVars(commandOutput); + } check(commandOutput.equals(Windows.is() ? "LC_ALL=C,SystemRoot="+systemRoot+"," : AIX.is() diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/lang/Thread/virtual/JfrEvents.java openjdk-25-25.0.5+8/test/jdk/java/lang/Thread/virtual/JfrEvents.java --- openjdk-25-25.0.4.1+1/test/jdk/java/lang/Thread/virtual/JfrEvents.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/lang/Thread/virtual/JfrEvents.java 2026-10-19 12:10:20.000000000 +0000 @@ -42,6 +42,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.LockSupport; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; import jdk.jfr.EventType; @@ -77,12 +78,13 @@ // execute 100 tasks, each in their own virtual thread recording.start(); - ThreadFactory factory = Thread.ofVirtual().factory(); - try (var executor = Executors.newThreadPerTaskExecutor(factory)) { - for (int i = 0; i < 100; i++) { - executor.submit(() -> { }); + try { + List threads = IntStream.range(0, 100) + .mapToObj(_ -> Thread.startVirtualThread(() -> { })) + .toList(); + for (Thread t : threads) { + t.join(); } - Thread.sleep(1000); // give time for thread end events to be recorded } finally { recording.stop(); } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/AbstractConnectTimeout.java openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/AbstractConnectTimeout.java --- openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/AbstractConnectTimeout.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/AbstractConnectTimeout.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,258 +0,0 @@ -/* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.NoRouteToHostException; -import java.net.ProxySelector; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpClient.Version; -import java.net.http.HttpConnectTimeoutException; -import java.net.http.HttpRequest; -import java.net.http.HttpRequest.BodyPublishers; -import java.net.http.HttpResponse; -import java.net.http.HttpResponse.BodyHandlers; -import java.nio.channels.UnresolvedAddressException; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletionException; -import org.testng.annotations.DataProvider; -import static java.lang.System.out; -import static java.net.http.HttpClient.Builder.NO_PROXY; -import static java.net.http.HttpClient.Version.HTTP_1_1; -import static java.net.http.HttpClient.Version.HTTP_2; -import static java.time.Duration.*; -import static java.util.concurrent.TimeUnit.NANOSECONDS; -import static org.testng.Assert.fail; - -public abstract class AbstractConnectTimeout { - - static final Duration NO_DURATION = null; - - static List> TIMEOUTS = List.of( - // connectTimeout HttpRequest timeout - Arrays.asList( NO_DURATION, ofMillis(100) ), - Arrays.asList( NO_DURATION, ofNanos(1) ), - - Arrays.asList( ofMillis(100), NO_DURATION ), - Arrays.asList( ofNanos(1), NO_DURATION ), - - Arrays.asList( ofMillis(100), ofMinutes(1) ), - Arrays.asList( ofNanos(1), ofMinutes(1) ) - ); - - static final List METHODS = List.of("GET", "POST"); - static final List VERSIONS = List.of(HTTP_2, HTTP_1_1); - static final List SCHEMES = List.of("https", "http"); - - @DataProvider(name = "variants") - public Object[][] variants() { - List l = new ArrayList<>(); - for (List timeouts : TIMEOUTS) { - Duration connectTimeout = timeouts.get(0); - Duration requestTimeout = timeouts.get(1); - for (String method: METHODS) { - for (String scheme : SCHEMES) { - for (Version requestVersion : VERSIONS) { - l.add(new Object[] {requestVersion, scheme, method, connectTimeout, requestTimeout}); - }}}} - return l.stream().toArray(Object[][]::new); - } - - static final ProxySelector EXAMPLE_DOT_COM_PROXY = ProxySelector.of( - InetSocketAddress.createUnresolved("example.com", 8080)); - - //@Test(dataProvider = "variants") - protected void timeoutNoProxySync(Version requestVersion, - String scheme, - String method, - Duration connectTimeout, - Duration requestTimeout) - throws Exception - { - timeoutSync(requestVersion, scheme, method, connectTimeout, requestTimeout, NO_PROXY); - } - - //@Test(dataProvider = "variants") - protected void timeoutWithProxySync(Version requestVersion, - String scheme, - String method, - Duration connectTimeout, - Duration requestTimeout) - throws Exception - { - timeoutSync(requestVersion, scheme, method, connectTimeout, requestTimeout, EXAMPLE_DOT_COM_PROXY); - } - - private void timeoutSync(Version requestVersion, - String scheme, - String method, - Duration connectTimeout, - Duration requestTimeout, - ProxySelector proxy) - throws Exception - { - out.printf("%ntimeoutSync(requestVersion=%s, scheme=%s, method=%s," - + " connectTimeout=%s, requestTimeout=%s, proxy=%s)%n", - requestVersion, scheme, method, connectTimeout, requestTimeout, proxy); - - HttpClient client = newClient(connectTimeout, proxy); - HttpRequest request = newRequest(scheme, requestVersion, method, requestTimeout); - - for (int i = 0; i < 2; i++) { - out.printf("iteration %d%n", i); - long startTime = System.nanoTime(); - try { - HttpResponse resp = client.send(request, BodyHandlers.ofString()); - printResponse(resp); - fail("Unexpected response: " + resp); - } catch (HttpConnectTimeoutException expected) { // blocking thread-specific exception - long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime); - out.printf("Client: received in %d millis%n", elapsedTime); - assertExceptionTypeAndCause(expected.getCause()); - } catch (ConnectException e) { - long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime); - out.printf("Client: received in %d millis%n", elapsedTime); - Throwable t = e.getCause().getCause(); // blocking thread-specific exception - if (!isAcceptableCause(t)) { // tolerate only NRTHE or UAE - e.printStackTrace(out); - fail("Unexpected exception:" + e); - } else { - out.printf("Caught ConnectException with " - + " cause: %s - skipping%n", t.getCause()); - } - } - } - } - - //@Test(dataProvider = "variants") - protected void timeoutNoProxyAsync(Version requestVersion, - String scheme, - String method, - Duration connectTimeout, - Duration requestTimeout) { - timeoutAsync(requestVersion, scheme, method, connectTimeout, requestTimeout, NO_PROXY); - } - - //@Test(dataProvider = "variants") - protected void timeoutWithProxyAsync(Version requestVersion, - String scheme, - String method, - Duration connectTimeout, - Duration requestTimeout) { - timeoutAsync(requestVersion, scheme, method, connectTimeout, requestTimeout, EXAMPLE_DOT_COM_PROXY); - } - - private void timeoutAsync(Version requestVersion, - String scheme, - String method, - Duration connectTimeout, - Duration requestTimeout, - ProxySelector proxy) { - out.printf("%ntimeoutAsync(requestVersion=%s, scheme=%s, method=%s, " - + "connectTimeout=%s, requestTimeout=%s, proxy=%s)%n", - requestVersion, scheme, method, connectTimeout, requestTimeout, proxy); - - HttpClient client = newClient(connectTimeout, proxy); - HttpRequest request = newRequest(scheme, requestVersion, method, requestTimeout); - for (int i = 0; i < 2; i++) { - out.printf("iteration %d%n", i); - long startTime = System.nanoTime(); - try { - HttpResponse resp = client.sendAsync(request, BodyHandlers.ofString()).join(); - printResponse(resp); - fail("Unexpected response: " + resp); - } catch (CompletionException e) { - long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime); - out.printf("Client: received in %d millis%n", elapsedTime); - Throwable t = e.getCause(); - if (t instanceof ConnectException && isAcceptableCause(t.getCause())) { - // tolerate only NRTHE and UAE - out.printf("Caught ConnectException with " - + "cause: %s - skipping%n", t.getCause()); - } else { - assertExceptionTypeAndCause(t); - } - } - } - } - - static boolean isAcceptableCause(Throwable cause) { - if (cause instanceof NoRouteToHostException) return true; - if (cause instanceof UnresolvedAddressException) return true; - return false; - } - - static HttpClient newClient(Duration connectTimeout, ProxySelector proxy) { - HttpClient.Builder builder = HttpClient.newBuilder().proxy(proxy); - if (connectTimeout != NO_DURATION) - builder.connectTimeout(connectTimeout); - return builder.build(); - } - - static HttpRequest newRequest(String scheme, - Version reqVersion, - String method, - Duration requestTimeout) { - // Resolvable address. Most tested environments just ignore the TCP SYN, - // or occasionally return ICMP no route to host - URI uri = URI.create(scheme +"://example.com:81/"); - HttpRequest.Builder reqBuilder = HttpRequest.newBuilder(uri); - reqBuilder = reqBuilder.version(reqVersion); - switch (method) { - case "GET" : reqBuilder.GET(); break; - case "POST" : reqBuilder.POST(BodyPublishers.noBody()); break; - default: throw new AssertionError("Unknown method:" + method); - } - if (requestTimeout != NO_DURATION) - reqBuilder.timeout(requestTimeout); - return reqBuilder.build(); - } - - static void assertExceptionTypeAndCause(Throwable t) { - if (!(t instanceof HttpConnectTimeoutException)) { - t.printStackTrace(out); - fail("Expected HttpConnectTimeoutException, got:" + t); - } - Throwable connEx = t.getCause(); - if (!(connEx instanceof ConnectException)) { - t.printStackTrace(out); - fail("Expected ConnectException cause in:" + connEx); - } - out.printf("Caught expected HttpConnectTimeoutException with ConnectException" - + " cause: %n%s%n%s%n", t, connEx); - final String EXPECTED_MESSAGE = "HTTP connect timed out"; // impl dependent - if (!connEx.getMessage().equals(EXPECTED_MESSAGE)) - fail("Expected: \"" + EXPECTED_MESSAGE + "\", got: \"" + connEx.getMessage() + "\""); - - } - - static void printResponse(HttpResponse response) { - out.println("Unexpected response: " + response); - out.println("Headers: " + response.headers()); - out.println("Body: " + response.body()); - } -} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/ConnectTimeoutNoProxyAsync.java openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutNoProxyAsync.java --- openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/ConnectTimeoutNoProxyAsync.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutNoProxyAsync.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.net.http.HttpClient.Version; -import java.time.Duration; -import org.testng.annotations.Test; - -/* - * @test - * @summary Tests for connection related timeouts - * @bug 8208391 - * @run testng/othervm ConnectTimeoutNoProxyAsync - */ - -public class ConnectTimeoutNoProxyAsync extends AbstractConnectTimeout { - - @Test(dataProvider = "variants") - @Override - public void timeoutNoProxyAsync(Version requestVersion, - String scheme, - String method, - Duration connectTimeout, - Duration requestduration) - { - super.timeoutNoProxyAsync(requestVersion, scheme, method, connectTimeout, requestduration); - } -} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/ConnectTimeoutNoProxySync.java openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutNoProxySync.java --- openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/ConnectTimeoutNoProxySync.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutNoProxySync.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.net.http.HttpClient.Version; -import java.time.Duration; -import org.testng.annotations.Test; - -/* - * @test - * @summary Tests for connection related timeouts - * @bug 8208391 - * @run testng/othervm ConnectTimeoutNoProxySync - */ - -public class ConnectTimeoutNoProxySync extends AbstractConnectTimeout { - - @Test(dataProvider = "variants") - @Override - public void timeoutNoProxySync(Version requestVersion, - String scheme, - String method, - Duration connectTimeout, - Duration requestTimeout) - throws Exception - { - super.timeoutNoProxySync(requestVersion, scheme, method, connectTimeout, requestTimeout); - } -} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/ConnectTimeoutTest.java openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutTest.java --- openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/ConnectTimeoutTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,370 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.Utils; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.io.PrintStream; +import java.net.ConnectException; +import java.net.InetAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Version; +import java.net.http.HttpConnectTimeoutException; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletionException; +import java.util.stream.Stream; + +import static java.lang.Boolean.parseBoolean; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.Version.HTTP_1_1; +import static java.net.http.HttpClient.Version.HTTP_2; +import static java.time.Duration.*; +import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static org.junit.jupiter.api.Assertions.fail; + +/* + * @test id=sync + * @bug 8208391 8375352 + * @summary Verifies behavior on `connect()` timeouts + * @requires os.family != "windows" + * @library /test/lib + * @run junit/othervm ${test.main.class} + */ + +/* + * @test id=sync-proxy + * @bug 8208391 8375352 + * @summary Verifies behavior on `connect()` timeouts + * @requires os.family != "windows" + * @library /test/lib + * @run junit/othervm -Dtest.proxy=true ${test.main.class} + */ + +/* + * @test id=async + * @bug 8208391 8375352 + * @summary Verifies behavior on `connect()` timeouts + * @requires os.family != "windows" + * @library /test/lib + * @run junit/othervm -Dtest.async=true ${test.main.class} + */ + +/* + * @test id=async-proxy + * @bug 8208391 8375352 + * @summary Verifies behavior on `connect()` timeouts + * @requires os.family != "windows" + * @library /test/lib + * @run junit/othervm -Dtest.async=true -Dtest.proxy=true ${test.main.class} + */ + +class ConnectTimeoutTest { + + // This test verifies the `HttpClient` behavior on `connect()` failures. + // + // Earlier, the test was trying to connect `example.com:8080` to trigger a `connect()` failure. + // This worked, until it doesn't — `example.com:8080` started responding in certain test environments. + // + // Now we create a `ServerSocket` and exhaust all its "SYN backlog" and "Accept queue". + // The expectation is that the platform socket in this state will block on `connect()`. + // Well... It doesn't on Windows, whereas it does on Linux and macOS. + // Windows doesn't block and immediately responds with `java.net.ConnectException: Connection refused: connect`. + // Neither it is deterministic how many connections are needed to exhaust a socket admission queue. + // Hence, we took the following decisions: + // + // 1. Skip this test on Windows + // 2. Exhaust server socket admission queue by going into a loop + + private static final PrintStream LOGGER = System.out; + + private static final int BACKLOG = 1; + + /** + * A {@link ServerSocket} whose admission will be blocked by exhausting all its "SYN backlog" and "Accept queue". + */ + private static final ServerSocket SERVER_SOCKET = createServerSocket(); + + /** + * Client sockets exhausting the admission to {@link #SERVER_SOCKET}. + */ + private static final List CLIENT_SOCKETS = createClientSocketsExhaustingServerSocketAdmission(); + + private static ServerSocket createServerSocket() { + try { + LOGGER.println("Creating server socket"); + return new ServerSocket(0, BACKLOG, InetAddress.getLoopbackAddress()); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + } + + private static List createClientSocketsExhaustingServerSocketAdmission() { + List sockets = new ArrayList<>(); + int maxSocketCount = BACKLOG // To fill up the backlog + + 512; // Giving some slack, should be enough to exhaust the admission queue. + int connectTimeout = Math.toIntExact(Math.addExact(500, Utils.adjustTimeout(500))); + int socketIndex = 0; + for (; socketIndex < maxSocketCount; socketIndex++) { + try { + LOGGER.printf( + "Creating client socket %s/%s to exhaust the server socket admission%n", + (socketIndex + 1), maxSocketCount); + Socket socket = new Socket(); + socket.connect(SERVER_SOCKET.getLocalSocketAddress(), connectTimeout); + sockets.add(socket); + } catch (ConnectException | SocketTimeoutException exception) { + LOGGER.printf( + "Received expected `%s` while creating client socket %s/%s%n", + exception.getClass().getName(), (socketIndex + 1), maxSocketCount); + return sockets; + } catch (IOException ioe) { + String message = String.format( + "Received unexpected exception while creating client socket %s/%s", + (socketIndex + 1), maxSocketCount); + closeSockets(SERVER_SOCKET, sockets); + throw new RuntimeException(message, ioe); + } + } + String message = String.format( + "Connected %s sockets, but still could not exhaust the socket admission", + maxSocketCount); + closeSockets(SERVER_SOCKET, sockets); + throw new RuntimeException(message); + } + + @AfterAll + public static void closeSockets() { + closeSockets(SERVER_SOCKET, CLIENT_SOCKETS); + } + + private static void closeSockets(ServerSocket serverSocket, List clientSockets) { + Throwable[] throwable = {null}; + Stream.concat(clientSockets.stream(), Stream.of(serverSocket)).forEach(closeable -> { + try { + closeable.close(); + } catch (Exception exception) { + if (throwable[0] == null) { + throwable[0] = exception; + } else { + throwable[0].addSuppressed(exception); + } + } + }); + if (throwable[0] != null) { + throwable[0].printStackTrace(System.out); + } + } + + /** + * {@link ProxySelector} always pointing to {@link #SERVER_SOCKET}. + */ + private static final ProxySelector PROXY_SELECTOR = new ProxySelector() { + + private static final List PROXIES = + List.of(new Proxy(Proxy.Type.HTTP, SERVER_SOCKET.getLocalSocketAddress())); + + @Override + public List select(URI uri) { + return PROXIES; + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + // Do nothing + } + + }; + + private static final Duration NO_DURATION = null; + + private static List> TIMEOUTS = List.of( + // connectTimeout HttpRequest timeout + Arrays.asList( NO_DURATION, ofMillis(100) ), + Arrays.asList( NO_DURATION, ofNanos(1) ), + + Arrays.asList( ofMillis(100), NO_DURATION ), + Arrays.asList( ofNanos(1), NO_DURATION ), + + Arrays.asList( ofMillis(100), ofMinutes(1) ), + Arrays.asList( ofNanos(1), ofMinutes(1) ) + ); + + private static final List METHODS = List.of("GET", "POST"); + private static final List VERSIONS = List.of(HTTP_2, HTTP_1_1); + private static final List SCHEMES = List.of("https", "http"); + + static Object[][] variants() { + List l = new ArrayList<>(); + for (List timeouts : TIMEOUTS) { + Duration connectTimeout = timeouts.get(0); + Duration requestTimeout = timeouts.get(1); + for (String method: METHODS) { + for (String scheme : SCHEMES) { + for (Version requestVersion : VERSIONS) { + l.add(new Object[] {requestVersion, scheme, method, connectTimeout, requestTimeout}); + }}}} + return l.stream().toArray(Object[][]::new); + } + + @ParameterizedTest + @MethodSource("variants") + void test( + Version requestVersion, + String scheme, + String method, + Duration connectTimeout, + Duration requestTimeout) + throws Exception { + ProxySelector proxySelector = parseBoolean(System.getProperty("test.proxy")) ? PROXY_SELECTOR : NO_PROXY; + boolean async = parseBoolean(System.getProperty("test.async")); + if (async) { + timeoutAsync(requestVersion, scheme, method, connectTimeout, requestTimeout, proxySelector); + } else { + timeoutSync(requestVersion, scheme, method, connectTimeout, requestTimeout, proxySelector); + } + } + + private void timeoutSync(Version requestVersion, + String scheme, + String method, + Duration connectTimeout, + Duration requestTimeout, + ProxySelector proxy) + throws Exception + { + HttpClient client = newClient(connectTimeout, proxy); + HttpRequest request = newRequest(scheme, requestVersion, method, requestTimeout); + + for (int i = 0; i < 2; i++) { + LOGGER.printf("iteration %d%n", i); + long startTime = System.nanoTime(); + try { + HttpResponse resp = client.send(request, BodyHandlers.ofString()); + printResponse(resp); + fail("Unexpected response: " + resp); + } catch (HttpConnectTimeoutException expected) { // blocking thread-specific exception + long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime); + LOGGER.printf("Client: received in %d millis%n", elapsedTime); + assertExceptionTypeAndCause(expected.getCause()); + } catch (ConnectException e) { + long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime); + LOGGER.printf("Client: received in %d millis%n", elapsedTime); + Throwable t = e.getCause().getCause(); // blocking thread-specific exception + e.printStackTrace(LOGGER); + fail("Unexpected exception:" + e); + } + } + } + + private void timeoutAsync(Version requestVersion, + String scheme, + String method, + Duration connectTimeout, + Duration requestTimeout, + ProxySelector proxy) { + HttpClient client = newClient(connectTimeout, proxy); + HttpRequest request = newRequest(scheme, requestVersion, method, requestTimeout); + for (int i = 0; i < 2; i++) { + LOGGER.printf("iteration %d%n", i); + long startTime = System.nanoTime(); + try { + HttpResponse resp = client.sendAsync(request, BodyHandlers.ofString()).join(); + printResponse(resp); + fail("Unexpected response: " + resp); + } catch (CompletionException e) { + long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime); + LOGGER.printf("Client: received in %d millis%n", elapsedTime); + Throwable t = e.getCause(); + assertExceptionTypeAndCause(t); + } + } + } + + private static HttpClient newClient(Duration connectTimeout, ProxySelector proxy) { + HttpClient.Builder builder = HttpClient.newBuilder().proxy(proxy); + if (connectTimeout != NO_DURATION) + builder.connectTimeout(connectTimeout); + return builder.build(); + } + + private static HttpRequest newRequest(String scheme, + Version reqVersion, + String method, + Duration requestTimeout) { + String hostAddress = SERVER_SOCKET.getInetAddress().getHostAddress(); + int hostPort = SERVER_SOCKET.getLocalPort(); + URI uri = URI.create(scheme + "://" + hostAddress + ':' + hostPort); + HttpRequest.Builder reqBuilder = HttpRequest.newBuilder(uri); + reqBuilder = reqBuilder.version(reqVersion); + switch (method) { + case "GET" : reqBuilder.GET(); break; + case "POST" : reqBuilder.POST(BodyPublishers.noBody()); break; + default: throw new AssertionError("Unknown method:" + method); + } + if (requestTimeout != NO_DURATION) + reqBuilder.timeout(requestTimeout); + return reqBuilder.build(); + } + + private static void assertExceptionTypeAndCause(Throwable t) { + if (!(t instanceof HttpConnectTimeoutException)) { + t.printStackTrace(LOGGER); + fail("Expected HttpConnectTimeoutException, got:" + t); + } + Throwable connEx = t.getCause(); + if (!(connEx instanceof ConnectException)) { + t.printStackTrace(LOGGER); + fail("Expected ConnectException cause in:" + connEx); + } + LOGGER.printf("Caught expected HttpConnectTimeoutException with ConnectException" + + " cause: %n%s%n%s%n", t, connEx); + final String EXPECTED_MESSAGE = "HTTP connect timed out"; // impl dependent + if (!connEx.getMessage().equals(EXPECTED_MESSAGE)) + fail("Expected: \"" + EXPECTED_MESSAGE + "\", got: \"" + connEx.getMessage() + "\""); + + } + + private static void printResponse(HttpResponse response) { + LOGGER.println("Unexpected response: " + response); + LOGGER.println("Headers: " + response.headers()); + LOGGER.println("Body: " + response.body()); + } + +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/ConnectTimeoutWithProxyAsync.java openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutWithProxyAsync.java --- openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/ConnectTimeoutWithProxyAsync.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutWithProxyAsync.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.net.http.HttpClient.Version; -import java.time.Duration; -import org.testng.annotations.Test; - -/* - * @test - * @summary Tests for connection related timeouts - * @bug 8208391 - * @run testng/othervm ConnectTimeoutWithProxyAsync - */ - -public class ConnectTimeoutWithProxyAsync extends AbstractConnectTimeout { - - @Test(dataProvider = "variants") - @Override - public void timeoutWithProxyAsync(Version requestVersion, - String scheme, - String method, - Duration connectTimeout, - Duration requestTimeout) - { - super.timeoutWithProxyAsync(requestVersion, scheme, method, connectTimeout, requestTimeout); - } -} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/ConnectTimeoutWithProxySync.java openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutWithProxySync.java --- openjdk-25-25.0.4.1+1/test/jdk/java/net/httpclient/ConnectTimeoutWithProxySync.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/net/httpclient/ConnectTimeoutWithProxySync.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.net.http.HttpClient.Version; -import java.time.Duration; -import org.testng.annotations.Test; - -/* - * @test - * @summary Tests for connection related timeouts - * @bug 8208391 - * @run testng/othervm ConnectTimeoutWithProxySync - */ - -public class ConnectTimeoutWithProxySync extends AbstractConnectTimeout { - - @Test(dataProvider = "variants") - @Override - public void timeoutWithProxySync(Version requestVersion, - String scheme, - String method, - Duration connectTimeout, - Duration requestTimeout) - throws Exception - { - super.timeoutWithProxySync(requestVersion, scheme, method, connectTimeout, requestTimeout); - } -} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/ConfigFileTest.java openjdk-25-25.0.5+8/test/jdk/java/security/Security/ConfigFileTest.java --- openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/ConfigFileTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/security/Security/ConfigFileTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,927 +0,0 @@ -/* - * Copyright (c) 2022, 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. - */ - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpServer; -import jdk.test.lib.Utils; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.util.FileUtils; -import sun.net.www.ParseUtil; - -import java.io.Closeable; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.UncheckedIOException; -import java.lang.reflect.Method; -import java.net.HttpURLConnection; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.URI; -import java.nio.CharBuffer; -import java.nio.file.Files; -import java.nio.file.InvalidPathException; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.nio.file.StandardOpenOption; -import java.security.Security; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Stream; - -/* - * @test - * @summary Tests security properties passed through java.security, - * java.security.properties or included from other properties files. - * @bug 8155246 8292297 8292177 8281658 8319332 - * @modules java.base/sun.net.www - * @library /test/lib - * @run main ConfigFileTest - */ - -public class ConfigFileTest { - static final String SEPARATOR_THIN = "----------------------------"; - - private static void printTestHeader(String testName) { - System.out.println(); - System.out.println(SEPARATOR_THIN); - System.out.println(testName); - System.out.println(SEPARATOR_THIN); - System.out.println(); - } - - public static void main(String[] args) throws Exception { - if (args.length == 1 && Executor.RUNNER_ARG.equals(args[0])) { - // Executed by a test-launched JVM. - // Force the initialization of java.security.Security. - Security.getProviders(); - Security.setProperty("postInitTest", "shouldNotRecord"); - System.out.println(FilesManager.LAST_FILE_PROP_NAME + ": " + - Security.getProperty(FilesManager.LAST_FILE_PROP_NAME)); - assertTestSecuritySetPropertyShouldNotInclude(); - } else { - // Executed by the test JVM. - try (FilesManager filesMgr = new FilesManager()) { - for (Method m : ConfigFileTest.class.getDeclaredMethods()) { - if (m.getName().startsWith("test")) { - printTestHeader(m.getName()); - Executor.run(m, filesMgr); - } - } - } - } - } - - /* - * Success cases - */ - - static void testShowSettings(Executor ex, FilesManager filesMgr) - throws Exception { - // Sanity test passing the -XshowSettings:security option. - ex.addJvmArg("-XshowSettings:security"); - ex.setMasterFile(filesMgr.newMasterFile()); - ex.assertSuccess(); - ex.getOutputAnalyzer() - .shouldContain("Security properties:") - .shouldContain("Security provider static configuration:") - .shouldContain("Security TLS configuration"); - } - - static void testIncludeBasic(Executor ex, FilesManager filesMgr) - throws Exception { - PropsFile masterFile = filesMgr.newMasterFile(); - ExtraPropsFile extraFile = filesMgr.newExtraFile(); - PropsFile file0 = filesMgr.newFile("file0.properties"); - PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); - PropsFile file2 = filesMgr.newFile("dir1/dir2/file2.properties"); - - masterFile.addAbsoluteInclude(file0); - extraFile.addRelativeInclude(file2); - file2.addAbsoluteInclude(file1); - - ex.setMasterFile(masterFile); - ex.setExtraFile(extraFile, Executor.ExtraMode.FILE_URI, false); - ex.assertSuccess(); - } - - static void testRepeatedInclude(Executor ex, FilesManager filesMgr) - throws Exception { - PropsFile masterFile = filesMgr.newMasterFile(); - PropsFile file0 = filesMgr.newFile("file0.properties"); - PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); - - masterFile.addAbsoluteInclude(file0); - masterFile.addAbsoluteInclude(file1); - masterFile.addAbsoluteInclude(file0); - file1.addRelativeInclude(file0); - - ex.setMasterFile(masterFile); - ex.assertSuccess(); - } - - static void testIncludeWithOverrideAll(Executor ex, FilesManager filesMgr) - throws Exception { - PropsFile masterFile = filesMgr.newMasterFile(); - ExtraPropsFile extraFile = filesMgr.newExtraFile(); - PropsFile file0 = filesMgr.newFile("file0.properties"); - PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); - - masterFile.addRelativeInclude(file0); - extraFile.addAbsoluteInclude(file1); - - ex.setMasterFile(masterFile); - ex.setExtraFile(extraFile, Executor.ExtraMode.HTTP_SERVED, true); - ex.assertSuccess(); - } - - static void extraPropertiesByHelper(Executor ex, FilesManager filesMgr, - Executor.ExtraMode mode) throws Exception { - ExtraPropsFile extraFile = filesMgr.newExtraFile(); - PropsFile file0 = filesMgr.newFile("file0.properties"); - - extraFile.addRelativeInclude(file0); - - ex.setMasterFile(filesMgr.newMasterFile()); - ex.setExtraFile(extraFile, mode, true); - ex.assertSuccess(); - } - - static void testExtraPropertiesByPathAbsolute(Executor ex, - FilesManager filesMgr) throws Exception { - extraPropertiesByHelper(ex, filesMgr, Executor.ExtraMode.PATH_ABS); - } - - static void testExtraPropertiesByPathRelative(Executor ex, - FilesManager filesMgr) throws Exception { - extraPropertiesByHelper(ex, filesMgr, Executor.ExtraMode.PATH_REL); - } - - static void specialCharsIncludes(Executor ex, FilesManager filesMgr, - char specialChar, Executor.ExtraMode extraMode, - boolean useRelativeIncludes) throws Exception { - String suffix = specialChar + ".properties"; - ExtraPropsFile extraFile; - PropsFile file0, file1; - try { - extraFile = filesMgr.newExtraFile("extra" + suffix); - file0 = filesMgr.newFile("file0" + suffix); - file1 = filesMgr.newFile("file1" + suffix); - } catch (InvalidPathException ipe) { - // The platform encoding may not allow to create files with some - // special characters. Skip the test in these cases. - return; - } - - if (useRelativeIncludes) { - extraFile.addRelativeInclude(file0); - } else { - extraFile.addAbsoluteInclude(file0); - } - extraFile.addAbsoluteInclude(file1); - - ex.setMasterFile(filesMgr.newMasterFile()); - ex.setExtraFile(extraFile, extraMode, false); - ex.assertSuccess(); - } - - static void testUnicodeIncludes1(Executor ex, FilesManager filesMgr) - throws Exception { - specialCharsIncludes(ex, filesMgr, '\u2022', - Executor.ExtraMode.PATH_ABS, true); - } - - static void testUnicodeIncludes2(Executor ex, FilesManager filesMgr) - throws Exception { - specialCharsIncludes(ex, filesMgr, '\u2022', - Executor.ExtraMode.FILE_URI, true); - } - - static void testUnicodeIncludes3(Executor ex, FilesManager filesMgr) - throws Exception { - // Backward compatibility check. Malformed URLs such as - // file:/tmp/extra•.properties are supported for the extra file. - // However, relative includes are not allowed in these cases. - specialCharsIncludes(ex, filesMgr, '\u2022', - Executor.ExtraMode.RAW_FILE_URI1, false); - } - - static void testUnicodeIncludes4(Executor ex, FilesManager filesMgr) - throws Exception { - // Backward compatibility check. Malformed URLs such as - // file:///tmp/extra•.properties are supported for the extra file. - // However, relative includes are not allowed in these cases. - specialCharsIncludes(ex, filesMgr, '\u2022', - Executor.ExtraMode.RAW_FILE_URI2, false); - } - - static void testSpaceIncludes1(Executor ex, FilesManager filesMgr) - throws Exception { - specialCharsIncludes(ex, filesMgr, ' ', - Executor.ExtraMode.PATH_ABS, true); - } - - static void testSpaceIncludes2(Executor ex, FilesManager filesMgr) - throws Exception { - specialCharsIncludes(ex, filesMgr, ' ', - Executor.ExtraMode.FILE_URI, true); - } - - static void testSpaceIncludes3(Executor ex, FilesManager filesMgr) - throws Exception { - // Backward compatibility check. Malformed URLs such as - // file:/tmp/extra .properties are supported for the extra file. - // However, relative includes are not allowed in these cases. - specialCharsIncludes(ex, filesMgr, ' ', - Executor.ExtraMode.RAW_FILE_URI1, false); - } - - static void testSpaceIncludes4(Executor ex, FilesManager filesMgr) - throws Exception { - // Backward compatibility check. Malformed URLs such as - // file:///tmp/extra .properties are supported for the extra file. - // However, relative includes are not allowed in these cases. - specialCharsIncludes(ex, filesMgr, ' ', - Executor.ExtraMode.RAW_FILE_URI2, false); - } - - static void notOverrideOnFailureHelper(Executor ex, FilesManager filesMgr, - String nonExistentExtraFile) throws Exception { - // An overriding extra properties file that does not exist - // should not erase properties from the master file. - ex.setIgnoredExtraFile(nonExistentExtraFile, true); - ex.setMasterFile(filesMgr.newMasterFile()); - ex.assertSuccess(); - ex.getOutputAnalyzer().shouldContain("unable to load security " + - "properties from " + nonExistentExtraFile); - } - - static void testNotOverrideOnEmptyFailure(Executor ex, - FilesManager filesMgr) throws Exception { - notOverrideOnFailureHelper(ex, filesMgr, ""); - ex.getOutputAnalyzer() - .shouldContain("Empty extra properties file path"); - } - - static void testNotOverrideOnURLFailure(Executor ex, FilesManager filesMgr) - throws Exception { - notOverrideOnFailureHelper(ex, filesMgr, - "file:///nonExistentFile.properties"); - } - - static void testNotOverrideOnPathFailure(Executor ex, FilesManager filesMgr) - throws Exception { - notOverrideOnFailureHelper(ex, filesMgr, "nonExistentFile.properties"); - } - - static void testNotOverrideOnDirFailure(Executor ex, FilesManager filesMgr) - throws Exception { - notOverrideOnFailureHelper(ex, filesMgr, "file:///"); - ex.getOutputAnalyzer().shouldContain("Is a directory"); - } - - static void testNotOverrideOnBadFileURLFailure(Executor ex, - FilesManager filesMgr) throws Exception { - notOverrideOnFailureHelper(ex, filesMgr, "file:///%00"); - } - - static void testDisabledExtraPropertiesFile(Executor ex, - FilesManager filesMgr) throws Exception { - PropsFile masterFile = filesMgr.newMasterFile(); - PropsFile file0 = filesMgr.newFile("file0.properties"); - - masterFile.addRawProperty("security.overridePropertiesFile", "false"); - - ex.setMasterFile(masterFile); - ex.setIgnoredExtraFile(file0.path.toString(), true); - ex.assertSuccess(); - } - - static final String SECURITY_SET_PROP_FILE_PATH = - "testSecuritySetPropertyShouldNotInclude.propsFilePath"; - - static void testSecuritySetPropertyShouldNotInclude(Executor ex, - FilesManager filesMgr) throws Exception { - PropsFile masterFile = filesMgr.newMasterFile(); - PropsFile file0 = filesMgr.newFile("file0.properties"); - - ex.addSystemProp(SECURITY_SET_PROP_FILE_PATH, file0.path.toString()); - ex.setMasterFile(masterFile); - ex.assertSuccess(); - } - - static void assertTestSecuritySetPropertyShouldNotInclude() { - // This check is executed by the launched JVM. - String propsFilePath = System.getProperty(SECURITY_SET_PROP_FILE_PATH); - if (propsFilePath != null) { - String name = Path.of(propsFilePath).getFileName().toString(); - String setPropInvokeRepr = "Security.setProperty(\"include\", " + - "\"" + propsFilePath + "\")"; - try { - Security.setProperty("include", propsFilePath); - throw new RuntimeException(setPropInvokeRepr + " was " + - "expected to throw IllegalArgumentException."); - } catch (IllegalArgumentException expected) {} - if (FilesManager.APPLIED_PROP_VALUE.equals( - Security.getProperty(name))) { - throw new RuntimeException(setPropInvokeRepr + " caused " + - "a file inclusion."); - } - try { - Security.getProperty("include"); - throw new RuntimeException("Security.getProperty(\"include\")" + - " was expected to throw IllegalArgumentException."); - } catch (IllegalArgumentException expected) {} - } - } - - /* - * Error cases - */ - - static void testCannotResolveRelativeFromHTTPServed(Executor ex, - FilesManager filesMgr) throws Exception { - ExtraPropsFile extraFile = filesMgr.newExtraFile(); - PropsFile file0 = filesMgr.newFile("file0.properties"); - - extraFile.addRelativeInclude(file0); - - ex.setMasterFile(filesMgr.newMasterFile()); - ex.setExtraFile(extraFile, Executor.ExtraMode.HTTP_SERVED, true); - ex.assertError("InternalError: Cannot resolve '" + file0.fileName + - "' relative path when included from a non-regular " + - "properties file (e.g. HTTP served file)"); - } - - static void testCannotIncludeCycles(Executor ex, FilesManager filesMgr) - throws Exception { - PropsFile masterFile = filesMgr.newMasterFile(); - PropsFile file0 = filesMgr.newFile("file0.properties"); - PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); - - // Includes chain: master -> file0 -> file1 -> master. - file1.addRelativeInclude(masterFile); - file0.addRelativeInclude(file1); - masterFile.addRelativeInclude(file0); - - ex.setMasterFile(masterFile); - ex.assertError( - "InternalError: Cyclic include of '" + masterFile.path + "'"); - } - - static void testCannotIncludeURL(Executor ex, FilesManager filesMgr) - throws Exception { - PropsFile masterFile = filesMgr.newMasterFile(); - ExtraPropsFile extraFile = filesMgr.newExtraFile(); - - masterFile.addRawProperty("include", extraFile.url.toString()); - - ex.setMasterFile(masterFile); - ex.assertError("InternalError: Unable to include 'http://127.0.0.1:"); - } - - static void testCannotIncludeNonexistentFile(Executor ex, - FilesManager filesMgr) throws Exception { - PropsFile masterFile = filesMgr.newMasterFile(); - - String nonexistentPath = "/nonExistentFile.properties"; - masterFile.addRawProperty("include", nonexistentPath); - - ex.setMasterFile(masterFile); - ex.assertError( - "InternalError: Unable to include '" + nonexistentPath + "'"); - } - - static void testMustHaveMasterFile(Executor ex, FilesManager filesMgr) - throws Exception { - // Launch a JDK without a master java.security file present. - ex.assertError("InternalError: Error loading java.security file"); - } - - static void testMustHaveMasterFileEvenWithExtraFile(Executor ex, - FilesManager filesMgr) throws Exception { - // Launch a JDK without a master java.security file present, but with an - // extra file passed. Since the "security.overridePropertiesFile=true" - // security property is missing, it should fail anyway. - ex.setExtraFile( - filesMgr.newExtraFile(), Executor.ExtraMode.FILE_URI, true); - ex.assertError("InternalError: Error loading java.security file"); - } -} - -sealed class PropsFile permits ExtraPropsFile { - protected static final class Include { - final PropsFile propsFile; - final String value; - - private Include(PropsFile propsFile, String value) { - this.propsFile = propsFile; - this.value = value; - } - - static Include of(PropsFile propsFile) { - return new Include(propsFile, propsFile.path.toString()); - } - - static Include of(PropsFile propsFile, String value) { - return new Include(propsFile, value); - } - } - - protected final List includes = new ArrayList<>(); - protected final PrintWriter writer; - protected boolean includedFromExtra = false; - final String fileName; - final Path path; - - PropsFile(String fileName, Path path) throws IOException { - this.fileName = fileName; - this.path = path; - this.writer = new PrintWriter(Files.newOutputStream(path, - StandardOpenOption.CREATE, StandardOpenOption.APPEND), true); - } - - private static String escape(String text, boolean escapeSpace) { - StringBuilder sb = new StringBuilder(text.length()); - CharBuffer cb = CharBuffer.wrap(text); - while (cb.hasRemaining()) { - char c = cb.get(); - if (c == '\\' || escapeSpace && c == ' ') { - sb.append('\\'); - } - if (Character.UnicodeBlock.of(c) == - Character.UnicodeBlock.BASIC_LATIN) { - sb.append(c); - } else { - sb.append("\\u%04x".formatted((int) c)); - } - } - return sb.toString(); - } - - private void addRawProperty(String key, String value, String sep) { - writer.println(escape(key, true) + sep + escape(value, false)); - } - - protected void addIncludeDefinition(Include include) { - if (include.propsFile instanceof ExtraPropsFile) { - throw new RuntimeException("ExtraPropsFile should not be included"); - } - includes.add(include); - addRawProperty("include", include.value, " "); - } - - void addComment(String comment) { - writer.println("# " + comment); - } - - void addRawProperty(String key, String value) { - addRawProperty(key, value, "="); - } - - void addAbsoluteInclude(PropsFile propsFile) { - addIncludeDefinition(Include.of(propsFile)); - } - - void addRelativeInclude(PropsFile propsFile) { - addIncludeDefinition(Include.of(propsFile, - path.getParent().relativize(propsFile.path).toString())); - } - - void assertApplied(OutputAnalyzer oa) { - oa.shouldContain(Executor.INITIAL_PROP_LOG_MSG + fileName + "=" + - FilesManager.APPLIED_PROP_VALUE); - for (Include include : includes) { - include.propsFile.assertApplied(oa); - oa.shouldContain("processing include: '" + include.value + "'"); - oa.shouldContain("finished processing " + include.propsFile.path); - } - } - - void assertWasOverwritten(OutputAnalyzer oa) { - oa.shouldNotContain(Executor.INITIAL_PROP_LOG_MSG + fileName + "=" + - FilesManager.APPLIED_PROP_VALUE); - for (Include include : includes) { - if (!include.propsFile.includedFromExtra) { - include.propsFile.assertWasOverwritten(oa); - } - oa.shouldContain("processing include: '" + include.value + "'"); - oa.shouldContain("finished processing " + include.propsFile.path); - } - } - - void markAsIncludedFromExtra() { - includedFromExtra = true; - for (Include include : includes) { - include.propsFile.markAsIncludedFromExtra(); - } - } - - PropsFile getLastFile() { - return includes.isEmpty() ? - this : includes.getLast().propsFile.getLastFile(); - } - - void close() { - writer.close(); - } -} - -final class ExtraPropsFile extends PropsFile { - private final Map systemProps = new LinkedHashMap<>(); - final URI url; - - ExtraPropsFile(String fileName, URI url, Path path) throws IOException { - super(fileName, path); - this.url = url; - } - - @Override - protected void addIncludeDefinition(Include include) { - if (includes.isEmpty()) { - String propName = "props.fileName"; - systemProps.put(propName, include.propsFile.fileName); - include = Include.of(include.propsFile, - include.value.replace(include.propsFile.fileName, - "${props.none}${" + propName + "}")); - } - include.propsFile.markAsIncludedFromExtra(); - super.addIncludeDefinition(include); - } - - Map getSystemProperties() { - return Collections.unmodifiableMap(systemProps); - } -} - -final class FilesManager implements Closeable { - private static final Path ROOT_DIR = - Path.of(ConfigFileTest.class.getSimpleName()).toAbsolutePath(); - private static final Path PROPS_DIR = ROOT_DIR.resolve("properties"); - private static final Path JDK_DIR = ROOT_DIR.resolve("jdk"); - private static final Path MASTER_FILE = - JDK_DIR.resolve("conf/security/java.security"); - private static final Path MASTER_FILE_TEMPLATE = - MASTER_FILE.resolveSibling("java.security.template"); - static final String JAVA_EXECUTABLE = - JDK_DIR.resolve("bin/java").toString(); - static final String LAST_FILE_PROP_NAME = "last-file"; - static final String APPLIED_PROP_VALUE = "applied"; - - private final List createdFiles; - private final Set fileNamesInUse; - private final HttpServer httpServer; - private final URI serverUri; - private final long masterFileLines; - - FilesManager() throws Exception { - createdFiles = new ArrayList<>(); - fileNamesInUse = new HashSet<>(); - httpServer = HttpServer.create( - new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0); - httpServer.createContext("/", this::handleRequest); - InetSocketAddress address = httpServer.getAddress(); - httpServer.start(); - serverUri = new URI("http", null, address.getHostString(), - address.getPort(), null, null, null); - copyJDK(); - try (Stream s = Files.lines(MASTER_FILE_TEMPLATE)) { - masterFileLines = s.count(); - } - } - - private static void copyJDK() throws Exception { - Path testJDK = Path.of(Objects.requireNonNull( - System.getProperty("test.jdk"), "unspecified test.jdk")); - if (!Files.exists(testJDK)) { - throw new RuntimeException("test.jdk -> nonexistent JDK"); - } - Files.createDirectories(JDK_DIR); - try (Stream pathStream = Files.walk(testJDK)) { - pathStream.skip(1).forEach((Path file) -> { - try { - Files.copy(file, JDK_DIR.resolve(testJDK.relativize(file)), - StandardCopyOption.COPY_ATTRIBUTES); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - }); - } - Files.move(MASTER_FILE, MASTER_FILE_TEMPLATE); - } - - private void handleRequest(HttpExchange x) throws IOException { - String rawPath = x.getRequestURI().getRawPath(); - Path f = ROOT_DIR.resolve(x.getRequestURI().getPath().substring(1)); - int statusCode; - byte[] responseBody; - // Check for unescaped space, unresolved parent or backward slash. - if (rawPath.matches("^.*( |(\\.|%2[Ee]){2}|\\\\|%5[Cc]).*$")) { - statusCode = HttpURLConnection.HTTP_BAD_REQUEST; - responseBody = new byte[0]; - } else if (Files.isRegularFile(f)) { - x.getResponseHeaders().add("Content-type", "text/plain"); - statusCode = HttpURLConnection.HTTP_OK; - responseBody = Files.readAllBytes(f); - } else { - statusCode = HttpURLConnection.HTTP_NOT_FOUND; - responseBody = new byte[0]; - } - System.out.println("[" + Instant.now() + "] " + - getClass().getSimpleName() + ": " + - x.getRequestMethod() + " " + rawPath + " -> " + - statusCode + " (" + responseBody.length + " bytes)"); - try (OutputStream responseStream = x.getResponseBody()) { - x.sendResponseHeaders(statusCode, responseBody.length); - responseStream.write(responseBody); - } - } - - @FunctionalInterface - private interface PropsFileBuilder { - PropsFile build(String fileName, Path path) throws IOException; - } - - private PropsFile newFile(Path path, PropsFileBuilder builder) - throws IOException { - String fileName = path.getFileName().toString(); - if (!fileNamesInUse.add(fileName)) { - // Names must be unique in order for the special - // property = to work. - throw new RuntimeException(fileName + " is repeated"); - } - Files.createDirectories(path.getParent()); - PropsFile propsFile = builder.build(fileName, path); - propsFile.addComment("Property to determine if this properties file " + - "was parsed and not overwritten:"); - propsFile.addRawProperty(fileName, APPLIED_PROP_VALUE); - propsFile.addComment(ConfigFileTest.SEPARATOR_THIN); - propsFile.addComment("Property to be overwritten by every properties " + - "file (master, extra or included):"); - propsFile.addRawProperty(LAST_FILE_PROP_NAME, fileName); - propsFile.addComment(ConfigFileTest.SEPARATOR_THIN); - createdFiles.add(propsFile); - return propsFile; - } - - PropsFile newFile(String relPathStr) throws IOException { - return newFile(PROPS_DIR.resolve(relPathStr), PropsFile::new); - } - - PropsFile newMasterFile() throws IOException { - Files.copy(MASTER_FILE_TEMPLATE, MASTER_FILE); - return newFile(MASTER_FILE, PropsFile::new); - } - - ExtraPropsFile newExtraFile() throws IOException { - return newExtraFile("extra.properties"); - } - - ExtraPropsFile newExtraFile(String extraFileName) throws IOException { - return (ExtraPropsFile) newFile(PROPS_DIR.resolve(extraFileName), - (fileName, path) -> { - URI uri = serverUri.resolve(ParseUtil.encodePath( - ROOT_DIR.relativize(path).toString())); - return new ExtraPropsFile(fileName, uri, path); - }); - } - - void reportCreatedFiles() throws IOException { - for (PropsFile propsFile : createdFiles) { - System.err.println(); - System.err.println(propsFile.path.toString()); - System.err.println(ConfigFileTest.SEPARATOR_THIN.repeat(3)); - try (Stream lines = Files.lines(propsFile.path)) { - long lineNumber = 1L; - Iterator it = lines.iterator(); - while (it.hasNext()) { - String line = it.next(); - if (!propsFile.path.equals(MASTER_FILE) || - lineNumber > masterFileLines) { - System.err.println(line); - } - lineNumber++; - } - } - System.err.println(); - } - } - - void clear() throws IOException { - if (!createdFiles.isEmpty()) { - for (PropsFile propsFile : createdFiles) { - propsFile.close(); - Files.delete(propsFile.path); - } - FileUtils.deleteFileTreeUnchecked(PROPS_DIR); - createdFiles.clear(); - fileNamesInUse.clear(); - } - } - - @Override - public void close() throws IOException { - clear(); - httpServer.stop(0); - FileUtils.deleteFileTreeUnchecked(ROOT_DIR); - } -} - -final class Executor { - enum ExtraMode { - HTTP_SERVED, FILE_URI, RAW_FILE_URI1, RAW_FILE_URI2, PATH_ABS, PATH_REL - } - static final String RUNNER_ARG = "runner"; - static final String INITIAL_PROP_LOG_MSG = "Initial security property: "; - private static final String OVERRIDING_LOG_MSG = - "overriding other security properties files!"; - private static final String[] ALWAYS_UNEXPECTED_LOG_MSGS = { - "java.lang.AssertionError", - INITIAL_PROP_LOG_MSG + "postInitTest=shouldNotRecord", - INITIAL_PROP_LOG_MSG + "include=", - }; - private static final Path CWD = Path.of(".").toAbsolutePath(); - private static final String JAVA_SEC_PROPS = "java.security.properties"; - private static final String CLASS_PATH = Objects.requireNonNull( - System.getProperty("test.classes"), "unspecified test.classes"); - private static final String DEBUG_ARG = - "-Xrunjdwp:transport=dt_socket,address=localhost:8000,suspend=y"; - private final Map systemProps = new LinkedHashMap<>( - Map.of("java.security.debug", "all", "javax.net.debug", "all", - // Ensure we get UTF-8 debug outputs in Windows: - "stderr.encoding", "UTF-8", "stdout.encoding", "UTF-8")); - private final List jvmArgs = new ArrayList<>( - List.of(FilesManager.JAVA_EXECUTABLE, "-enablesystemassertions", - // Uncomment DEBUG_ARG to debug test-launched JVMs: - "-classpath", CLASS_PATH//, DEBUG_ARG - )); - private PropsFile masterPropsFile; - private ExtraPropsFile extraPropsFile; - private boolean expectedOverrideAll = false; - private OutputAnalyzer oa; - - static void run(Method m, FilesManager filesMgr) throws Exception { - try { - m.invoke(null, new Executor(), filesMgr); - } catch (Throwable e) { - filesMgr.reportCreatedFiles(); - throw e; - } finally { - filesMgr.clear(); - } - } - - void addSystemProp(String key, String value) { - systemProps.put(key, value); - } - - private void setRawExtraFile(String extraFile, boolean overrideAll) { - addSystemProp(JAVA_SEC_PROPS, (overrideAll ? "=" : "") + extraFile); - } - - void setMasterFile(PropsFile masterPropsFile) { - this.masterPropsFile = masterPropsFile; - } - - void setExtraFile(ExtraPropsFile extraPropsFile, ExtraMode mode, - boolean overrideAll) { - this.extraPropsFile = extraPropsFile; - expectedOverrideAll = overrideAll; - setRawExtraFile(switch (mode) { - case HTTP_SERVED -> extraPropsFile.url.toString(); - case FILE_URI -> extraPropsFile.path.toUri().toString(); - case RAW_FILE_URI1 -> "file:" + extraPropsFile.path; - case RAW_FILE_URI2 -> "file://" + - (extraPropsFile.path.startsWith("/") ? "" : "/") + - extraPropsFile.path; - case PATH_ABS -> extraPropsFile.path.toString(); - case PATH_REL -> CWD.relativize(extraPropsFile.path).toString(); - }, overrideAll); - } - - void setIgnoredExtraFile(String extraPropsFile, boolean overrideAll) { - setRawExtraFile(extraPropsFile, overrideAll); - expectedOverrideAll = false; - } - - void addJvmArg(String arg) { - jvmArgs.add(arg); - } - - private void execute(boolean successExpected) throws Exception { - List command = new ArrayList<>(jvmArgs); - Collections.addAll(command, Utils.getTestJavaOpts()); - addSystemPropertiesAsJvmArgs(command); - command.add(ConfigFileTest.class.getSimpleName()); - command.add(RUNNER_ARG); - oa = ProcessTools.executeProcess(new ProcessBuilder(command)); - oa.shouldHaveExitValue(successExpected ? 0 : 1); - for (String output : ALWAYS_UNEXPECTED_LOG_MSGS) { - oa.shouldNotContain(output); - } - } - - private void addSystemPropertiesAsJvmArgs(List command) { - Map allSystemProps = new LinkedHashMap<>(systemProps); - if (extraPropsFile != null) { - allSystemProps.putAll(extraPropsFile.getSystemProperties()); - } - for (Map.Entry e : allSystemProps.entrySet()) { - command.add("-D" + e.getKey() + "=" + e.getValue()); - } - } - - void assertSuccess() throws Exception { - execute(true); - - // Ensure every file was processed by checking a unique property used as - // a flag. Each file defines =applied. - // - // For example: - // - // file0 - // --------------- - // file0=applied - // include file1 - // - // file1 - // --------------- - // file1=applied - // - // The assertion would be file0 == applied AND file1 == applied. - // - if (extraPropsFile != null) { - extraPropsFile.assertApplied(oa); - } - if (expectedOverrideAll) { - // When overriding with an extra file, check that neither - // the master file nor its includes are visible. - oa.shouldContain(OVERRIDING_LOG_MSG); - masterPropsFile.assertWasOverwritten(oa); - } else { - oa.shouldNotContain(OVERRIDING_LOG_MSG); - masterPropsFile.assertApplied(oa); - } - - // Ensure the last included file overwrote a fixed property. Each file - // defines last-file=. - // - // For example: - // - // file0 - // --------------- - // last-file=file0 - // include file1 - // - // file1 - // --------------- - // last-file=file1 - // - // The assertion would be last-file == file1. - // - PropsFile lastFile = (extraPropsFile == null ? - masterPropsFile : extraPropsFile).getLastFile(); - oa.shouldContain(FilesManager.LAST_FILE_PROP_NAME + "=" + - lastFile.fileName); - oa.stdoutShouldContain(FilesManager.LAST_FILE_PROP_NAME + ": " + - lastFile.fileName); - } - - void assertError(String message) throws Exception { - execute(false); - oa.shouldContain(message); - } - - OutputAnalyzer getOutputAnalyzer() { - return oa; - } -} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/SecurityPropFile/ExtraFileAndIncludes.java openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/ExtraFileAndIncludes.java --- openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/SecurityPropFile/ExtraFileAndIncludes.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/ExtraFileAndIncludes.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,937 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpServer; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; +import sun.net.www.ParseUtil; + +import java.io.Closeable; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.UncheckedIOException; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.CharBuffer; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; +import java.security.Security; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Stream; + +/* + * @test + * @summary Tests security properties passed through java.security, + * java.security.properties or included from other properties files. + * @bug 4303068 8155246 8292297 8292177 8281658 8319332 + * @modules java.base/sun.net.www + * @library /test/lib + * @run main ExtraFileAndIncludes + */ + +public class ExtraFileAndIncludes { + static final String SEPARATOR_THIN = "----------------------------"; + + private static void printTestHeader(String testName) { + System.out.println(); + System.out.println(SEPARATOR_THIN); + System.out.println(testName); + System.out.println(SEPARATOR_THIN); + System.out.println(); + } + + public static void main(String[] args) throws Exception { + if (args.length == 1 && Executor.RUNNER_ARG.equals(args[0])) { + // Executed by a test-launched JVM. + // Force the initialization of java.security.Security. + Security.getProviders(); + Security.setProperty("postInitTest", "shouldNotRecord"); + System.out.println(FilesManager.LAST_FILE_PROP_NAME + ": " + + Security.getProperty(FilesManager.LAST_FILE_PROP_NAME)); + assertTestSecuritySetPropertyShouldNotInclude(); + } else { + // Executed by the test JVM. + try (FilesManager filesMgr = new FilesManager()) { + for (Method m : + ExtraFileAndIncludes.class.getDeclaredMethods()) { + if (m.getName().startsWith("test")) { + printTestHeader(m.getName()); + Executor.run(m, filesMgr); + } + } + } + } + } + + /* + * Success cases + */ + + static void testShowSettings(Executor ex, FilesManager filesMgr) + throws Exception { + // Sanity test passing the -XshowSettings:security option. + ex.addJvmArg("-XshowSettings:security"); + ex.setMasterFile(filesMgr.newMasterFile()); + ex.assertSuccess(); + ex.getOutputAnalyzer() + .shouldContain("Security properties:") + .shouldContain("Security provider static configuration:") + .shouldContain("Security TLS configuration"); + } + + static void testIncludeBasic(Executor ex, FilesManager filesMgr) + throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + ExtraPropsFile extraFile = filesMgr.newExtraFile(ExtraMode.FILE_URI); + PropsFile file0 = filesMgr.newFile("file0.properties"); + PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); + PropsFile file2 = filesMgr.newFile("dir1/dir2/file2.properties"); + + masterFile.addAbsoluteInclude(file0); + extraFile.addRelativeInclude(file2); + file2.addAbsoluteInclude(file1); + + ex.setMasterFile(masterFile); + ex.setExtraFile(extraFile, false); + ex.assertSuccess(); + } + + static void testRepeatedInclude(Executor ex, FilesManager filesMgr) + throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); + + masterFile.addAbsoluteInclude(file0); + masterFile.addAbsoluteInclude(file1); + masterFile.addAbsoluteInclude(file0); + file1.addRelativeInclude(file0); + + ex.setMasterFile(masterFile); + ex.assertSuccess(); + } + + static void testIncludeWithOverrideAll(Executor ex, FilesManager filesMgr) + throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + ExtraPropsFile extraFile = filesMgr.newExtraFile(ExtraMode.HTTP_SERVED); + PropsFile file0 = filesMgr.newFile("file0.properties"); + PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); + + masterFile.addRelativeInclude(file0); + extraFile.addAbsoluteInclude(file1); + + ex.setMasterFile(masterFile); + ex.setExtraFile(extraFile, true); + ex.assertSuccess(); + } + + static void extraPropertiesByHelper(Executor ex, FilesManager filesMgr, + ExtraMode mode) throws Exception { + ExtraPropsFile extraFile = filesMgr.newExtraFile(mode); + PropsFile file0 = filesMgr.newFile("file0.properties"); + + extraFile.addRelativeInclude(file0); + + ex.setMasterFile(filesMgr.newMasterFile()); + ex.setExtraFile(extraFile, true); + ex.assertSuccess(); + } + + static void testExtraPropertiesByPathAbsolute(Executor ex, + FilesManager filesMgr) throws Exception { + extraPropertiesByHelper(ex, filesMgr, ExtraMode.PATH_ABS); + } + + static void testExtraPropertiesByPathRelative(Executor ex, + FilesManager filesMgr) throws Exception { + extraPropertiesByHelper(ex, filesMgr, ExtraMode.PATH_REL); + } + + static void specialCharsIncludes(Executor ex, FilesManager filesMgr, + char specialChar, ExtraMode extraMode, boolean useRelativeIncludes) + throws Exception { + String suffix = specialChar + ".properties"; + ExtraPropsFile extraFile; + PropsFile file0, file1; + try { + extraFile = filesMgr.newExtraFile("extra" + suffix, extraMode); + file0 = filesMgr.newFile("file0" + suffix); + file1 = filesMgr.newFile("file1" + suffix); + } catch (InvalidPathException ipe) { + // The platform encoding may not allow to create files with some + // special characters. Skip the test in these cases. + return; + } + + if (useRelativeIncludes) { + extraFile.addRelativeInclude(file0); + } else { + extraFile.addAbsoluteInclude(file0); + } + extraFile.addAbsoluteInclude(file1); + + ex.setMasterFile(filesMgr.newMasterFile()); + ex.setExtraFile(extraFile, false); + ex.assertSuccess(); + } + + static void testUnicodeIncludes1(Executor ex, FilesManager filesMgr) + throws Exception { + specialCharsIncludes(ex, filesMgr, '\u2022', ExtraMode.PATH_ABS, true); + } + + static void testUnicodeIncludes2(Executor ex, FilesManager filesMgr) + throws Exception { + specialCharsIncludes(ex, filesMgr, '\u2022', ExtraMode.FILE_URI, true); + } + + static void testUnicodeIncludes3(Executor ex, FilesManager filesMgr) + throws Exception { + // Backward compatibility check. Malformed URLs such as + // file:/tmp/extra•.properties are supported for the extra file. + // However, relative includes are not allowed in these cases. + specialCharsIncludes(ex, filesMgr, '\u2022', + ExtraMode.RAW_FILE_URI1, false); + } + + static void testUnicodeIncludes4(Executor ex, FilesManager filesMgr) + throws Exception { + // Backward compatibility check. Malformed URLs such as + // file:///tmp/extra•.properties are supported for the extra file. + // However, relative includes are not allowed in these cases. + specialCharsIncludes(ex, filesMgr, '\u2022', + ExtraMode.RAW_FILE_URI2, false); + } + + static void testSpaceIncludes1(Executor ex, FilesManager filesMgr) + throws Exception { + specialCharsIncludes(ex, filesMgr, ' ', ExtraMode.PATH_ABS, true); + } + + static void testSpaceIncludes2(Executor ex, FilesManager filesMgr) + throws Exception { + specialCharsIncludes(ex, filesMgr, ' ', ExtraMode.FILE_URI, true); + } + + static void testSpaceIncludes3(Executor ex, FilesManager filesMgr) + throws Exception { + // Backward compatibility check. Malformed URLs such as + // file:/tmp/extra .properties are supported for the extra file. + // However, relative includes are not allowed in these cases. + specialCharsIncludes(ex, filesMgr, ' ', ExtraMode.RAW_FILE_URI1, false); + } + + static void testSpaceIncludes4(Executor ex, FilesManager filesMgr) + throws Exception { + // Backward compatibility check. Malformed URLs such as + // file:///tmp/extra .properties are supported for the extra file. + // However, relative includes are not allowed in these cases. + specialCharsIncludes(ex, filesMgr, ' ', ExtraMode.RAW_FILE_URI2, false); + } + + static void notOverrideOnFailureHelper(Executor ex, FilesManager filesMgr, + String nonExistentExtraFile) throws Exception { + // An overriding extra properties file that does not exist + // should not erase properties from the master file. + ex.setIgnoredExtraFile(nonExistentExtraFile, true); + ex.setMasterFile(filesMgr.newMasterFile()); + ex.assertSuccess(); + ex.getOutputAnalyzer().shouldContain("unable to load security " + + "properties from " + nonExistentExtraFile); + } + + static void testNotOverrideOnEmptyFailure(Executor ex, + FilesManager filesMgr) throws Exception { + notOverrideOnFailureHelper(ex, filesMgr, ""); + ex.getOutputAnalyzer() + .shouldContain("Empty extra properties file path"); + } + + static void testNotOverrideOnURLFailure(Executor ex, FilesManager filesMgr) + throws Exception { + notOverrideOnFailureHelper(ex, filesMgr, + "file:///nonExistentFile.properties"); + } + + static void testNotOverrideOnPathFailure(Executor ex, FilesManager filesMgr) + throws Exception { + notOverrideOnFailureHelper(ex, filesMgr, "nonExistentFile.properties"); + } + + static void testNotOverrideOnDirFailure(Executor ex, FilesManager filesMgr) + throws Exception { + notOverrideOnFailureHelper(ex, filesMgr, "file:///"); + ex.getOutputAnalyzer().shouldContain("Is a directory"); + } + + static void testNotOverrideOnBadFileURLFailure(Executor ex, + FilesManager filesMgr) throws Exception { + notOverrideOnFailureHelper(ex, filesMgr, "file:///%00"); + } + + static void testDisabledExtraPropertiesFile(Executor ex, + FilesManager filesMgr) throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + + masterFile.addRawProperty("security.overridePropertiesFile", "false"); + + ex.setMasterFile(masterFile); + ex.setIgnoredExtraFile(file0.path.toString(), true); + ex.assertSuccess(); + } + + static final String SECURITY_SET_PROP_FILE_PATH = + "testSecuritySetPropertyShouldNotInclude.propsFilePath"; + + static void testSecuritySetPropertyShouldNotInclude(Executor ex, + FilesManager filesMgr) throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + + ex.addSystemProp(SECURITY_SET_PROP_FILE_PATH, file0.path.toString()); + ex.setMasterFile(masterFile); + ex.assertSuccess(); + } + + static void assertTestSecuritySetPropertyShouldNotInclude() { + // This check is executed by the launched JVM. + String propsFilePath = System.getProperty(SECURITY_SET_PROP_FILE_PATH); + if (propsFilePath != null) { + String name = Path.of(propsFilePath).getFileName().toString(); + String setPropInvokeRepr = "Security.setProperty(\"include\", " + + "\"" + propsFilePath + "\")"; + try { + Security.setProperty("include", propsFilePath); + throw new RuntimeException(setPropInvokeRepr + " was " + + "expected to throw IllegalArgumentException."); + } catch (IllegalArgumentException expected) {} + if (FilesManager.APPLIED_PROP_VALUE.equals( + Security.getProperty(name))) { + throw new RuntimeException(setPropInvokeRepr + " caused " + + "a file inclusion."); + } + try { + Security.getProperty("include"); + throw new RuntimeException("Security.getProperty(\"include\")" + + " was expected to throw IllegalArgumentException."); + } catch (IllegalArgumentException expected) {} + } + } + + /* + * Error cases + */ + + static void testCannotResolveRelativeFromHTTPServed(Executor ex, + FilesManager filesMgr) throws Exception { + ExtraPropsFile extraFile = filesMgr.newExtraFile(ExtraMode.HTTP_SERVED); + PropsFile file0 = filesMgr.newFile("file0.properties"); + + extraFile.addRelativeInclude(file0); + + ex.setMasterFile(filesMgr.newMasterFile()); + ex.setExtraFile(extraFile, true); + ex.assertError("InternalError: Cannot resolve '" + file0.fileName + + "' relative path when included from a non-regular " + + "properties file (e.g. HTTP served file)"); + } + + static void testCannotIncludeCycles(Executor ex, FilesManager filesMgr) + throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); + + // Includes chain: master -> file0 -> file1 -> master. + file1.addRelativeInclude(masterFile); + file0.addRelativeInclude(file1); + masterFile.addRelativeInclude(file0); + + ex.setMasterFile(masterFile); + ex.assertError("Cyclic include"); + ex.getOutputAnalyzer().stderrShouldMatch("\\QInternalError: Cyclic " + + "include of '\\E[^']+\\Q" + masterFile.fileName + "'\\E"); + } + + static void testCannotIncludeURL(Executor ex, FilesManager filesMgr) + throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + ExtraPropsFile extraFile = filesMgr.newExtraFile(ExtraMode.HTTP_SERVED); + + masterFile.addRawProperty("include", extraFile.url.toString()); + + ex.setMasterFile(masterFile); + ex.assertError("InternalError: Unable to include 'http://127.0.0.1:"); + } + + static void testCannotIncludeNonexistentFile(Executor ex, + FilesManager filesMgr) throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + + String nonexistentPath = "/nonExistentFile.properties"; + masterFile.addRawProperty("include", nonexistentPath); + + ex.setMasterFile(masterFile); + ex.assertError( + "InternalError: Unable to include '" + nonexistentPath + "'"); + } + + static void testMustHaveMasterFile(Executor ex, FilesManager filesMgr) + throws Exception { + // Launch a JDK without a master java.security file present. + ex.assertError("InternalError: Error loading java.security file"); + } + + static void testMustHaveMasterFileEvenWithExtraFile(Executor ex, + FilesManager filesMgr) throws Exception { + // Launch a JDK without a master java.security file present, but with an + // extra file passed. Since the "security.overridePropertiesFile=true" + // security property is missing, it should fail anyway. + ex.setExtraFile(filesMgr.newExtraFile(ExtraMode.FILE_URI), true); + ex.assertError("InternalError: Error loading java.security file"); + } +} + +sealed class PropsFile permits ExtraPropsFile { + protected static final class Include { + final PropsFile propsFile; + final String value; + + private Include(PropsFile propsFile, String value) { + this.propsFile = propsFile; + this.value = value; + } + + static Include of(PropsFile propsFile) { + return new Include(propsFile, propsFile.path.toString()); + } + + static Include of(PropsFile propsFile, String value) { + return new Include(propsFile, value); + } + + void assertProcessed(OutputAnalyzer oa) { + oa.shouldContain("processing include: '" + value + "'"); + oa.shouldContain("finished processing " + propsFile.displayPath); + } + } + + protected final List includes = new ArrayList<>(); + protected final PrintWriter writer; + protected boolean includedFromExtra = false; + protected Path displayPath; + final String fileName; + final Path path; + + PropsFile(String fileName, Path path) throws IOException { + this.fileName = fileName; + this.path = path; + this.displayPath = path; + this.writer = new PrintWriter(Files.newOutputStream(path, + StandardOpenOption.CREATE, StandardOpenOption.APPEND), true); + } + + private static String escape(String text, boolean escapeSpace) { + StringBuilder sb = new StringBuilder(text.length()); + CharBuffer cb = CharBuffer.wrap(text); + while (cb.hasRemaining()) { + char c = cb.get(); + if (c == '\\' || escapeSpace && c == ' ') { + sb.append('\\'); + } + if (Character.UnicodeBlock.of(c) == + Character.UnicodeBlock.BASIC_LATIN) { + sb.append(c); + } else { + sb.append("\\u%04x".formatted((int) c)); + } + } + return sb.toString(); + } + + private void addRawProperty(String key, String value, String sep) { + writer.println(escape(key, true) + sep + escape(value, false)); + } + + protected void addIncludeDefinition(Include include) { + if (include.propsFile instanceof ExtraPropsFile) { + throw new RuntimeException("ExtraPropsFile should not be included"); + } + includes.add(include); + addRawProperty("include", include.value, " "); + } + + void addComment(String comment) { + writer.println("# " + comment); + } + + void addRawProperty(String key, String value) { + addRawProperty(key, value, "="); + } + + void addAbsoluteInclude(PropsFile propsFile) { + addIncludeDefinition(Include.of(propsFile)); + } + + void addRelativeInclude(PropsFile propsFile) { + Path rel = path.getParent().relativize(propsFile.path); + addIncludeDefinition(Include.of(propsFile, rel.toString())); + propsFile.displayPath = displayPath.getParent().resolve(rel); + } + + void assertApplied(OutputAnalyzer oa) { + oa.shouldContain(Executor.INITIAL_PROP_LOG_MSG + fileName + "=" + + FilesManager.APPLIED_PROP_VALUE); + for (Include include : includes) { + include.propsFile.assertApplied(oa); + include.assertProcessed(oa); + } + } + + void assertWasOverwritten(OutputAnalyzer oa) { + oa.shouldNotContain(Executor.INITIAL_PROP_LOG_MSG + fileName + "=" + + FilesManager.APPLIED_PROP_VALUE); + for (Include include : includes) { + if (!include.propsFile.includedFromExtra) { + include.propsFile.assertWasOverwritten(oa); + } + include.assertProcessed(oa); + } + } + + void markAsIncludedFromExtra() { + includedFromExtra = true; + for (Include include : includes) { + include.propsFile.markAsIncludedFromExtra(); + } + } + + PropsFile getLastFile() { + return includes.isEmpty() ? + this : includes.getLast().propsFile.getLastFile(); + } + + void close() { + writer.close(); + } +} + +enum ExtraMode { + HTTP_SERVED, FILE_URI, RAW_FILE_URI1, RAW_FILE_URI2, PATH_ABS, PATH_REL +} + +final class ExtraPropsFile extends PropsFile { + private static final Path CWD = Path.of(".").toAbsolutePath(); + private final Map systemProps = new LinkedHashMap<>(); + private final ExtraMode mode; + final URI url; + + ExtraPropsFile(String fileName, URI url, Path path, ExtraMode mode) + throws IOException { + super(fileName, path); + this.url = url; + this.mode = mode; + if (mode == ExtraMode.PATH_REL) { + this.displayPath = CWD.relativize(path); + } + } + + @Override + protected void addIncludeDefinition(Include include) { + if (includes.isEmpty()) { + String propName = "props.fileName"; + systemProps.put(propName, include.propsFile.fileName); + include = Include.of(include.propsFile, + include.value.replace(include.propsFile.fileName, + "${props.none}${" + propName + "}")); + } + include.propsFile.markAsIncludedFromExtra(); + super.addIncludeDefinition(include); + } + + String getSysPropValue() { + return switch (mode) { + case HTTP_SERVED -> url.toString(); + case FILE_URI -> path.toUri().toString(); + case RAW_FILE_URI1 -> "file:" + path; + case RAW_FILE_URI2 -> + "file://" + (path.startsWith("/") ? "" : "/") + path; + case PATH_ABS, PATH_REL -> displayPath.toString(); + }; + } + + Map getSystemProperties() { + return Collections.unmodifiableMap(systemProps); + } +} + +final class FilesManager implements Closeable { + private static final Path ROOT_DIR = Path.of( + ExtraFileAndIncludes.class.getSimpleName()).toAbsolutePath(); + private static final Path PROPS_DIR = ROOT_DIR.resolve("properties"); + private static final Path JDK_DIR = ROOT_DIR.resolve("jdk"); + private static final Path MASTER_FILE = + JDK_DIR.resolve("conf/security/java.security"); + private static final Path MASTER_FILE_TEMPLATE = + MASTER_FILE.resolveSibling("java.security.template"); + static final String JAVA_EXECUTABLE = + JDK_DIR.resolve("bin/java").toString(); + static final String LAST_FILE_PROP_NAME = "last-file"; + static final String APPLIED_PROP_VALUE = "applied"; + + private final List createdFiles; + private final Set fileNamesInUse; + private final HttpServer httpServer; + private final URI serverUri; + private final long masterFileLines; + + FilesManager() throws Exception { + createdFiles = new ArrayList<>(); + fileNamesInUse = new HashSet<>(); + httpServer = HttpServer.create( + new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0); + httpServer.createContext("/", this::handleRequest); + InetSocketAddress address = httpServer.getAddress(); + httpServer.start(); + serverUri = new URI("http", null, address.getHostString(), + address.getPort(), null, null, null); + copyJDK(); + try (Stream s = Files.lines(MASTER_FILE_TEMPLATE)) { + masterFileLines = s.count(); + } + } + + private static void copyJDK() throws Exception { + Path testJDK = Path.of(Objects.requireNonNull( + System.getProperty("test.jdk"), "unspecified test.jdk")); + if (!Files.exists(testJDK)) { + throw new RuntimeException("test.jdk -> nonexistent JDK"); + } + Files.createDirectories(JDK_DIR); + try (Stream pathStream = Files.walk(testJDK)) { + pathStream.skip(1).forEach((Path file) -> { + try { + Files.copy(file, JDK_DIR.resolve(testJDK.relativize(file)), + StandardCopyOption.COPY_ATTRIBUTES); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + }); + } + Files.move(MASTER_FILE, MASTER_FILE_TEMPLATE); + } + + private void handleRequest(HttpExchange x) throws IOException { + String rawPath = x.getRequestURI().getRawPath(); + Path f = ROOT_DIR.resolve(x.getRequestURI().getPath().substring(1)); + int statusCode; + byte[] responseBody; + // Check for unescaped space, unresolved parent or backward slash. + if (rawPath.matches("^.*( |(\\.|%2[Ee]){2}|\\\\|%5[Cc]).*$")) { + statusCode = HttpURLConnection.HTTP_BAD_REQUEST; + responseBody = new byte[0]; + } else if (Files.isRegularFile(f)) { + x.getResponseHeaders().add("Content-type", "text/plain"); + statusCode = HttpURLConnection.HTTP_OK; + responseBody = Files.readAllBytes(f); + } else { + statusCode = HttpURLConnection.HTTP_NOT_FOUND; + responseBody = new byte[0]; + } + System.out.println("[" + Instant.now() + "] " + + getClass().getSimpleName() + ": " + + x.getRequestMethod() + " " + rawPath + " -> " + + statusCode + " (" + responseBody.length + " bytes)"); + try (OutputStream responseStream = x.getResponseBody()) { + x.sendResponseHeaders(statusCode, responseBody.length); + responseStream.write(responseBody); + } + } + + @FunctionalInterface + private interface PropsFileBuilder { + PropsFile build(String fileName, Path path) throws IOException; + } + + private PropsFile newFile(Path path, PropsFileBuilder builder) + throws IOException { + String fileName = path.getFileName().toString(); + if (!fileNamesInUse.add(fileName)) { + // Names must be unique in order for the special + // property = to work. + throw new RuntimeException(fileName + " is repeated"); + } + Files.createDirectories(path.getParent()); + PropsFile propsFile = builder.build(fileName, path); + propsFile.addComment("Property to determine if this properties file " + + "was parsed and not overwritten:"); + propsFile.addRawProperty(fileName, APPLIED_PROP_VALUE); + propsFile.addComment(ExtraFileAndIncludes.SEPARATOR_THIN); + propsFile.addComment("Property to be overwritten by every properties " + + "file (master, extra or included):"); + propsFile.addRawProperty(LAST_FILE_PROP_NAME, fileName); + propsFile.addComment(ExtraFileAndIncludes.SEPARATOR_THIN); + createdFiles.add(propsFile); + return propsFile; + } + + PropsFile newFile(String relPathStr) throws IOException { + return newFile(PROPS_DIR.resolve(relPathStr), PropsFile::new); + } + + PropsFile newMasterFile() throws IOException { + Files.copy(MASTER_FILE_TEMPLATE, MASTER_FILE); + return newFile(MASTER_FILE, PropsFile::new); + } + + ExtraPropsFile newExtraFile(ExtraMode mode) throws IOException { + return newExtraFile("extra.properties", mode); + } + + ExtraPropsFile newExtraFile(String extraFileName, ExtraMode mode) + throws IOException { + return (ExtraPropsFile) newFile(PROPS_DIR.resolve(extraFileName), + (fileName, path) -> { + URI uri = serverUri.resolve(ParseUtil.encodePath( + ROOT_DIR.relativize(path).toString())); + return new ExtraPropsFile(fileName, uri, path, mode); + }); + } + + void reportCreatedFiles() throws IOException { + for (PropsFile propsFile : createdFiles) { + System.err.println(); + System.err.println(propsFile.path.toString()); + System.err.println(ExtraFileAndIncludes.SEPARATOR_THIN.repeat(3)); + try (Stream lines = Files.lines(propsFile.path)) { + long lineNumber = 1L; + Iterator it = lines.iterator(); + while (it.hasNext()) { + String line = it.next(); + if (!propsFile.path.equals(MASTER_FILE) || + lineNumber > masterFileLines) { + System.err.println(line); + } + lineNumber++; + } + } + System.err.println(); + } + } + + void clear() throws IOException { + if (!createdFiles.isEmpty()) { + for (PropsFile propsFile : createdFiles) { + propsFile.close(); + Files.delete(propsFile.path); + } + FileUtils.deleteFileTreeUnchecked(PROPS_DIR); + createdFiles.clear(); + fileNamesInUse.clear(); + } + } + + @Override + public void close() throws IOException { + clear(); + httpServer.stop(0); + FileUtils.deleteFileTreeUnchecked(ROOT_DIR); + } +} + +final class Executor { + static final String RUNNER_ARG = "runner"; + static final String INITIAL_PROP_LOG_MSG = "Initial security property: "; + private static final String OVERRIDING_LOG_MSG = + "overriding other security properties files!"; + private static final String[] ALWAYS_UNEXPECTED_LOG_MSGS = { + "java.lang.AssertionError", + INITIAL_PROP_LOG_MSG + "postInitTest=shouldNotRecord", + INITIAL_PROP_LOG_MSG + "include=", + }; + private static final String JAVA_SEC_PROPS = "java.security.properties"; + private static final String CLASS_PATH = Objects.requireNonNull( + System.getProperty("test.classes"), "unspecified test.classes"); + private static final String DEBUG_ARG = + "-Xrunjdwp:transport=dt_socket,address=localhost:8000,suspend=y"; + private final Map systemProps = new LinkedHashMap<>( + Map.of("java.security.debug", "all", "javax.net.debug", "all", + // Ensure we get UTF-8 debug outputs in Windows: + "stderr.encoding", "UTF-8", "stdout.encoding", "UTF-8")); + private final List jvmArgs = new ArrayList<>( + List.of(FilesManager.JAVA_EXECUTABLE, "-enablesystemassertions", + // Uncomment DEBUG_ARG to debug test-launched JVMs: + "-classpath", CLASS_PATH//, DEBUG_ARG + )); + private PropsFile masterPropsFile; + private ExtraPropsFile extraPropsFile; + private boolean expectedOverrideAll = false; + private OutputAnalyzer oa; + + static void run(Method m, FilesManager filesMgr) throws Exception { + try { + m.invoke(null, new Executor(), filesMgr); + } catch (Throwable e) { + filesMgr.reportCreatedFiles(); + throw e; + } finally { + filesMgr.clear(); + } + } + + void addSystemProp(String key, String value) { + systemProps.put(key, value); + } + + private void setRawExtraFile(String extraFile, boolean overrideAll) { + addSystemProp(JAVA_SEC_PROPS, (overrideAll ? "=" : "") + extraFile); + } + + void setMasterFile(PropsFile masterPropsFile) { + this.masterPropsFile = masterPropsFile; + } + + void setExtraFile(ExtraPropsFile extraPropsFile, boolean overrideAll) { + this.extraPropsFile = extraPropsFile; + expectedOverrideAll = overrideAll; + setRawExtraFile(extraPropsFile.getSysPropValue(), overrideAll); + } + + void setIgnoredExtraFile(String extraPropsFile, boolean overrideAll) { + setRawExtraFile(extraPropsFile, overrideAll); + expectedOverrideAll = false; + } + + void addJvmArg(String arg) { + jvmArgs.add(arg); + } + + private void execute(boolean successExpected) throws Exception { + List command = new ArrayList<>(jvmArgs); + Collections.addAll(command, Utils.getTestJavaOpts()); + addSystemPropertiesAsJvmArgs(command); + command.add(ExtraFileAndIncludes.class.getSimpleName()); + command.add(RUNNER_ARG); + oa = ProcessTools.executeProcess(new ProcessBuilder(command)); + oa.shouldHaveExitValue(successExpected ? 0 : 1); + for (String output : ALWAYS_UNEXPECTED_LOG_MSGS) { + oa.shouldNotContain(output); + } + } + + private void addSystemPropertiesAsJvmArgs(List command) { + Map allSystemProps = new LinkedHashMap<>(systemProps); + if (extraPropsFile != null) { + allSystemProps.putAll(extraPropsFile.getSystemProperties()); + } + for (Map.Entry e : allSystemProps.entrySet()) { + command.add("-D" + e.getKey() + "=" + e.getValue()); + } + } + + void assertSuccess() throws Exception { + execute(true); + + // Ensure every file was processed by checking a unique property used as + // a flag. Each file defines =applied. + // + // For example: + // + // file0 + // --------------- + // file0=applied + // include file1 + // + // file1 + // --------------- + // file1=applied + // + // The assertion would be file0 == applied AND file1 == applied. + // + if (extraPropsFile != null) { + extraPropsFile.assertApplied(oa); + } + if (expectedOverrideAll) { + // When overriding with an extra file, check that neither + // the master file nor its includes are visible. + oa.shouldContain(OVERRIDING_LOG_MSG); + masterPropsFile.assertWasOverwritten(oa); + } else { + oa.shouldNotContain(OVERRIDING_LOG_MSG); + masterPropsFile.assertApplied(oa); + } + + // Ensure the last included file overwrote a fixed property. Each file + // defines last-file=. + // + // For example: + // + // file0 + // --------------- + // last-file=file0 + // include file1 + // + // file1 + // --------------- + // last-file=file1 + // + // The assertion would be last-file == file1. + // + PropsFile lastFile = (extraPropsFile == null ? + masterPropsFile : extraPropsFile).getLastFile(); + oa.shouldContain(FilesManager.LAST_FILE_PROP_NAME + "=" + + lastFile.fileName); + oa.stdoutShouldContain(FilesManager.LAST_FILE_PROP_NAME + ": " + + lastFile.fileName); + } + + void assertError(String message) throws Exception { + execute(false); + oa.shouldContain(message); + } + + OutputAnalyzer getOutputAnalyzer() { + return oa; + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/SecurityPropFile/LinuxAnonymousFiles.java openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/LinuxAnonymousFiles.java --- openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/SecurityPropFile/LinuxAnonymousFiles.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/LinuxAnonymousFiles.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2026, Red Hat, Inc. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.process.ProcessTools; + +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Path; + +/* + * @test + * @summary Ensures the java executable is able to load extra security + * properties files from anonymous files and pipes. + * @bug 8352728 + * @requires os.family == "linux" + * @modules java.base/java.io:+open + * @library /test/lib + * @run main LinuxAnonymousFiles + */ + +public class LinuxAnonymousFiles { + private static final String TEST_PROP = "property.name=PROPERTY_VALUE"; + + private static final class AnonymousFile implements AutoCloseable { + public final Path fdPath; + private final FileInputStream fis; + + private AnonymousFile(CharSequence content) throws Exception { + Path tmp = Files.createTempFile("anonymous-file-", ""); + Files.writeString(tmp, content + System.lineSeparator()); + fis = new FileInputStream(tmp.toFile()); + Files.delete(tmp); + // Now the file is regular but anonymous, and will be unlinked + // when we close the last file descriptor referring to it. The + // fis instance ensures we keep it alive until close() is invoked. + Field field = FileDescriptor.class.getDeclaredField("fd"); + field.setAccessible(true); + int fd = field.getInt(fis.getFD()); + fdPath = Path.of("/proc/self").toRealPath().resolve("fd/" + fd); + } + + @Override + public void close() throws IOException { + fis.close(); + } + } + + public static void main(String[] args) throws Exception { + Path java = Path.of(System.getProperty("test.jdk"), "bin", "java"); + try (AnonymousFile af = new AnonymousFile("include /dev/stdin")) { + ProcessTools.executeProcess(new ProcessBuilder(java.toString(), + "-Djava.security.debug=properties", + "-Djava.security.properties=" + af.fdPath, + "-XshowSettings:security:properties", "-version"), + TEST_PROP).shouldHaveExitValue(0).shouldContain(TEST_PROP); + } + System.out.println("TEST PASS - OK"); + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/SecurityPropFile/SecurityPropFile.file openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/SecurityPropFile.file --- openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/SecurityPropFile/SecurityPropFile.file 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/SecurityPropFile.file 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -policy.url.2=file:${test.src}/SecurityPropFile.policy diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/SecurityPropFile/SecurityPropFile.java openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/SecurityPropFile.java --- openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/SecurityPropFile/SecurityPropFile.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/SecurityPropFile.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2001, 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 4303068 - * @summary be allowed to specify the security properties file - * as a -D system property - * - * @run main/othervm -Djava.security.properties=${test.src}/SecurityPropFile.file -Djava.security.debug=properties SecurityPropFile - */ - -public class SecurityPropFile { - public static void main(String[] args) { - System.out.println(java.security.Security.getProperty - ("policy.provider")); - System.out.println(java.security.Security.getProperty - ("policy.url.1")); - System.out.println(java.security.Security.getProperty - ("policy.url.2")); - } -} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/SecurityPropFile/WindowsParentDirPermissions.java openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/WindowsParentDirPermissions.java --- openjdk-25-25.0.4.1+1/test/jdk/java/security/Security/SecurityPropFile/WindowsParentDirPermissions.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/security/Security/SecurityPropFile/WindowsParentDirPermissions.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2026, Red Hat, Inc. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.AclEntry; +import java.nio.file.attribute.AclEntryType; +import java.nio.file.attribute.AclFileAttributeView; +import java.util.List; + +/* + * @test + * @summary Ensures java.security is loadable in Windows, even when the user + * does not have permissions on one of the parent directories. + * @bug 8352728 + * @requires os.family == "windows" + * @library /test/lib + * @run main WindowsParentDirPermissions + */ + +public class WindowsParentDirPermissions { + private static AutoCloseable restrictedAcl(Path path) throws IOException { + AclFileAttributeView view = + Files.getFileAttributeView(path, AclFileAttributeView.class); + List originalAcl = List.copyOf(view.getAcl()); + view.setAcl(List.of(AclEntry.newBuilder().setType(AclEntryType.DENY) + .setPrincipal(Files.getOwner(path)).build())); + return () -> view.setAcl(originalAcl); + } + + public static void main(String[] args) throws Exception { + Path temp = Files.createTempDirectory("JDK-8352728-tmp-"); + try (AutoCloseable a1 = () -> FileUtils.deleteFileTreeUnchecked(temp)) { + // Copy the jdk to a different directory + Path originalJdk = Path.of(System.getProperty("test.jdk")); + Path jdk = temp.resolve("jdk-parent-dir", "jdk"); + Files.createDirectories(jdk); + FileUtils.copyDirectory(originalJdk, jdk); + + // Remove current user permissions from jdk-parent-dir + try (AutoCloseable a2 = restrictedAcl(jdk.getParent())) { + // Make sure the permissions are affecting the current user + try { + jdk.toRealPath(); + throw new jtreg.SkippedException("Must run non-elevated!"); + } catch (IOException expected) { } + + // Execute the copied jdk, ensuring java.security.Security is + // loaded (i.e. use -XshowSettings:security:properties) + ProcessTools.executeProcess(new ProcessBuilder( + List.of(jdk.resolve("bin", "java.exe").toString(), + "-Djava.security.debug=properties", + "-XshowSettings:security:properties", + "-version"))).shouldHaveExitValue(0); + } + } + System.out.println("TEST PASS - OK"); + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/time/test/java/time/format/TestUnicodeExtension.java openjdk-25-25.0.5+8/test/jdk/java/time/test/java/time/format/TestUnicodeExtension.java --- openjdk-25-25.0.4.1+1/test/jdk/java/time/test/java/time/format/TestUnicodeExtension.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/time/test/java/time/format/TestUnicodeExtension.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -24,7 +24,7 @@ /* * @test * @bug 8176841 8202537 8244245 8265315 8284840 8296248 8306116 8333582 - * 8346948 + * 8346948 8392526 * @summary Tests java.time classes deals with Unicode extensions * correctly. * @modules jdk.localedata @@ -478,7 +478,7 @@ {"cnurc", "Asia/Urumqi"}, {"cobog", "America/Bogota"}, {"crsjo", "America/Costa_Rica"}, - {"cst6cdt", "America/Chicago"}, + {"cst6cdt", "CST6CDT"}, {"cuhav", "America/Havana"}, {"cvrai", "Atlantic/Cape_Verde"}, {"cxxch", "Indian/Christmas"}, @@ -501,7 +501,7 @@ {"esceu", "Africa/Ceuta"}, {"eslpa", "Atlantic/Canary"}, {"esmad", "Europe/Madrid"}, - {"est5edt", "America/New_York"}, + {"est5edt", "EST5EDT"}, {"etadd", "Africa/Addis_Ababa"}, {"fihel", "Europe/Helsinki"}, {"fimhq", "Europe/Mariehamn"}, @@ -610,7 +610,7 @@ {"mqfdf", "America/Martinique"}, {"mrnkc", "Africa/Nouakchott"}, {"msmni", "America/Montserrat"}, - {"mst7mdt", "America/Denver"}, + {"mst7mdt", "MST7MDT"}, {"mtmla", "Europe/Malta"}, {"muplu", "Indian/Mauritius"}, {"mvmle", "Indian/Maldives"}, @@ -658,7 +658,7 @@ {"pmmqc", "America/Miquelon"}, {"pnpcn", "Pacific/Pitcairn"}, {"prsju", "America/Puerto_Rico"}, - {"pst8pdt", "America/Los_Angeles"}, + {"pst8pdt", "PST8PDT"}, {"ptfnc", "Atlantic/Madeira"}, {"ptlis", "Europe/Lisbon"}, {"ptpdl", "Atlantic/Azores"}, diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java openjdk-25-25.0.5+8/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java --- openjdk-25-25.0.4.1+1/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -28,6 +28,7 @@ import java.text.DateFormatSymbols; import java.time.ZoneId; +import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; import java.time.format.DecimalStyle; @@ -41,6 +42,7 @@ import java.util.Date; import java.util.HashSet; import java.util.Locale; +import java.util.Map; import java.util.Random; import java.util.Set; import java.util.TimeZone; @@ -52,7 +54,7 @@ /* * @test * @bug 8081022 8151876 8166875 8177819 8189784 8206980 8277049 8278434 8346948 - * 8174269 + * 8174269 8390388 8388214 8392519 8393344 * @key randomness */ @@ -62,6 +64,21 @@ @Test public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { + // Explicit dstOffset attributes from CLDR pre-release v49 metazone data. + private static final Map CLDR_EXPLICIT_DST_OFFSETS = Map.ofEntries( + Map.entry("Africa/Windhoek", ZoneOffset.of("+02:00")), + Map.entry("America/Edmonton", ZoneOffset.of("-06:00")), + Map.entry("America/Inuvik", ZoneOffset.of("-06:00")), + Map.entry("America/Rainy_River", ZoneOffset.of("-05:00")), + Map.entry("America/Yellowknife", ZoneOffset.of("-06:00")), + Map.entry("America/Vancouver", ZoneOffset.of("-07:00")), + Map.entry("America/Winnipeg", ZoneOffset.of("-05:00")), + Map.entry("Canada/Central", ZoneOffset.of("-05:00")), + Map.entry("Canada/Mountain", ZoneOffset.of("-06:00")), + Map.entry("Canada/Pacific", ZoneOffset.of("-07:00")), + Map.entry("Europe/Dublin", ZoneOffset.of("+01:00")), + Map.entry("Eire", ZoneOffset.of("+01:00"))); + private static final Locale[] SAMPLE_LOCALES = { Locale.US, Locale.UK, Locale.FRANCE, Locale.GERMANY, Locale.ITALY, Locale.forLanguageTag("es"), Locale.forLanguageTag("pt-BR"), Locale.forLanguageTag("ru"), @@ -89,10 +106,17 @@ } zdt = zdt.withZoneSameLocal(ZoneId.of(zid)); TimeZone tz = TimeZone.getTimeZone(zid); - boolean isDST = tz.inDaylightTime(new Date(zdt.toInstant().toEpochMilli())); + long epochMilli = zdt.toInstant().toEpochMilli(); + boolean isDST = tz.inDaylightTime(new Date(epochMilli)); + // Some zones now use an explicit daylight offset in CLDR without java.util.TimeZone + // reporting DST for the instant. + ZoneOffset explicitDstOffset = CLDR_EXPLICIT_DST_OFFSETS.get(zid); + boolean useDaylightName = explicitDstOffset != null + ? zdt.getOffset().equals(explicitDstOffset) + : isDST; for (Locale locale : SAMPLE_LOCALES) { - String longDisplayName = tz.getDisplayName(isDST, TimeZone.LONG, locale); - String shortDisplayName = tz.getDisplayName(isDST, TimeZone.SHORT, locale); + String longDisplayName = tz.getDisplayName(useDaylightName, TimeZone.LONG, locale); + String shortDisplayName = tz.getDisplayName(useDaylightName, TimeZone.SHORT, locale); if ((longDisplayName.startsWith("GMT+") && shortDisplayName.startsWith("GMT+")) || (longDisplayName.startsWith("GMT-") && shortDisplayName.startsWith("GMT-"))) { // exclude ROOT @@ -104,9 +128,9 @@ continue; } printText(locale, zdt, TextStyle.FULL, tz, - tz.getDisplayName(isDST, TimeZone.LONG, locale)); + tz.getDisplayName(useDaylightName, TimeZone.LONG, locale)); printText(locale, zdt, TextStyle.SHORT, tz, - tz.getDisplayName(isDST, TimeZone.SHORT, locale)); + tz.getDisplayName(useDaylightName, TimeZone.SHORT, locale)); } } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/time/test/java/time/zone/TestZoneRules.java openjdk-25-25.0.5+8/test/jdk/java/time/test/java/time/zone/TestZoneRules.java --- openjdk-25-25.0.4.1+1/test/jdk/java/time/test/java/time/zone/TestZoneRules.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/time/test/java/time/zone/TestZoneRules.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ /** * @summary Tests for ZoneRules class. * - * @bug 8212970 8236903 8239836 + * @bug 8212970 8236903 8239836 8388214 */ @Test public class TestZoneRules { @@ -90,15 +90,17 @@ {WINDHOEK, LocalDate.of(1994, 3, 23), OFF_1, OFF_1, false}, {WINDHOEK, LocalDate.of(2016, 9, 23), OFF_2, OFF_1, true}, - // Africa/Casablanca for the Rule "Morocco" Defines negative DST till 2037 as of 2019a. + // Africa/Casablanca for the Rule "Morocco" defines negative DST until early 2026, + // then returns to standard UTC permanently later that year, starting with 2026c. {CASABLANCA, LocalDate.of(1939, 9, 13), OFF_1, OFF_0, true}, {CASABLANCA, LocalDate.of(1939, 11, 20), OFF_0, OFF_0, false}, {CASABLANCA, LocalDate.of(2018, 6, 18), OFF_1, OFF_0, true}, {CASABLANCA, LocalDate.of(2019, 1, 1), OFF_1, OFF_0, true}, {CASABLANCA, LocalDate.of(2019, 5, 6), OFF_0, OFF_0, false}, - {CASABLANCA, LocalDate.of(2037, 10, 5), OFF_0, OFF_0, false}, - {CASABLANCA, LocalDate.of(2037, 11, 16), OFF_1, OFF_0, true}, - {CASABLANCA, LocalDate.of(2038, 11, 8), OFF_1, OFF_0, true}, + {CASABLANCA, LocalDate.of(2026, 2, 16), OFF_0, OFF_0, false}, + {CASABLANCA, LocalDate.of(2026, 3, 23), OFF_1, OFF_0, true}, + {CASABLANCA, LocalDate.of(2026, 9, 21), OFF_0, OFF_0, false}, + {CASABLANCA, LocalDate.of(2038, 11, 8), OFF_0, OFF_0, false}, }; } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/AIXTzMappingTest.java openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/AIXTzMappingTest.java --- openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/AIXTzMappingTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/AIXTzMappingTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,102 @@ +/* + * 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 8380993 + * @library /test/lib + * @summary Validates AIX timezone mapping behavior where POSIX TZ strings + * with comma-separated DST rules are truncated and mapped through tzmappings + * to the expected IANA timezone IDs. + * @requires os.family == "aix" + * @run main/othervm AIXTzMappingTest + */ + +import java.util.TimeZone; + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class AIXTzMappingTest { + + // POSIX TZ strings that should be mapped via tzmappings + private static final String TZ_CET = "CET-1CEST,M3.5.0,M10.5.0"; + private static final String TZ_MEZ = "MEZ-1MESZ,M3.5.0,M10.5.0/3"; + + private static final String ID_PARIS = "Europe/Paris"; + private static final String ID_BERLIN = "Europe/Berlin"; + + public static void main(String[] args) throws Throwable { + if (args.length == 0) { + runWithTZ(TZ_CET, ID_PARIS); + runWithTZ(TZ_MEZ, ID_BERLIN); + } else if (args.length == 1) { + runTZTest(args[0]); + } else { + throw new RuntimeException( + "Expected 0 or 1 arguments, got " + args.length); + } + } + + private static void runWithTZ(String tz, String expectedId) + throws Throwable { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "AIXTzMappingTest", expectedId); + + pb.environment().put("TZ", tz); + + OutputAnalyzer output = ProcessTools.executeProcess(pb); + output.shouldHaveExitValue(0); + } + + /* + * On AIX, POSIX TZ strings such as: + * CET-1CEST,M3.5.0,M10.5.0 + * MEZ-1MESZ,M3.5.0,M10.5.0/3 + * are truncated at the comma and mapped through tzmappings to + * IANA timezone IDs. + * + * This test verifies that the expected IANA timezone ID is selected. + */ + private static void runTZTest(String expectedId) { + String tzStr = System.getenv("TZ"); + + if (tzStr == null) { + throw new RuntimeException( + "Got unexpected timezone information: TZ is null"); + } + + TimeZone tz = TimeZone.getDefault(); + String tzId = tz.getID(); + + if (!expectedId.equals(tzId)) { + throw new RuntimeException( + "Expected timezone ID " + expectedId + + " but got " + tzId + + " for TZ=" + tzStr); + } + + System.out.println( + "AIX timezone mapping test passed: " + + tzId + " for TZ=" + tzStr); + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/Bug6329116.java openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/Bug6329116.java --- openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/Bug6329116.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/Bug6329116.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -26,6 +26,7 @@ * @bug 6329116 6756569 6757131 6758988 6764308 6796489 6834474 6609737 6507067 * 7039469 7090843 7103108 7103405 7158483 8008577 8059206 8064560 8072042 * 8077685 8151876 8166875 8169191 8170316 8176044 8174269 8347841 8347955 + * 8388214 8392377 8393337 * @summary Make sure that timezone short display names are identical to Olson's data. * @run junit Bug6329116 */ @@ -41,6 +42,18 @@ public class Bug6329116 { + // As of CLDR v48.2, CLDR provides these short names for zones with explicit DST offsets. + private static final Map CLDR_SHORT_NAMES = Map.of( + "America/Edmonton", "MST", + "America/Inuvik", "MST", + "Canada/Mountain", "MST", + "America/Yellowknife", "MST", + "America/Vancouver", "PST", + "Canada/Pacific", "PST", + "America/Winnipeg", "CST", + "Canada/Central", "CST", + "America/Rainy_River", "CST"); + // Do not test all locales, as some locales have localized // short names in CLDR. Test only for the US locale @@ -250,6 +263,11 @@ return tz.getDisplayName().substring(0, 3).equals(got.substring(0, 3)); } + // Some zones use CLDR short names even when the tzdata FORMAT changed. + if (!inDST) { + return CLDR_SHORT_NAMES.getOrDefault(tz.getID(), "").equals(got); + } + return false; } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/CustomTzIDCheckDST.java openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/CustomTzIDCheckDST.java --- openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/CustomTzIDCheckDST.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/CustomTzIDCheckDST.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -26,7 +26,10 @@ * @library /test/lib * @summary This test will ensure that daylight savings rules are followed * appropriately when setting a custom timezone ID via the TZ env variable. - * @requires os.family != "windows" + * AIX is excluded because it uses a different timezone mapping mechanism + * through the tzmappings file; see AIXTzMappingTest.java for AIX-specific + * coverage. + * @requires os.family != "windows" & os.family != "aix" * @run main/othervm CustomTzIDCheckDST */ diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/NegativeDSTTest.java openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/NegativeDSTTest.java --- openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/NegativeDSTTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/NegativeDSTTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -38,7 +38,7 @@ /** * @test - * @bug 8212970 8324065 + * @bug 8212970 8324065 8388214 * @summary Test whether the savings are positive in time zones that have * negative savings in the source TZ files. * @run junit NegativeDSTTest @@ -73,18 +73,17 @@ {WINDHOEK, LocalDate.of(1994, 3, 23), ONE_HOUR, false}, {WINDHOEK, LocalDate.of(2016, 9, 23), 2 * ONE_HOUR, true}, - // Africa/Casablanca for the Rule "Morocco" Defines negative DST till 2037 as of 2019a. + // Africa/Casablanca for the Rule "Morocco" defines negative DST until early 2026, + // then returns to standard UTC permanently later that year, starting with 2026c. {CASABLANCA, LocalDate.of(1939, 9, 13), ONE_HOUR, true}, {CASABLANCA, LocalDate.of(1939, 11, 20), 0, false}, {CASABLANCA, LocalDate.of(2018, 6, 18), ONE_HOUR, true}, {CASABLANCA, LocalDate.of(2019, 1, 1), ONE_HOUR, true}, {CASABLANCA, LocalDate.of(2019, 5, 6), 0, false}, - {CASABLANCA, LocalDate.of(2037, 10, 5), 0, false}, - {CASABLANCA, LocalDate.of(2037, 11, 16), ONE_HOUR, true}, - {CASABLANCA, LocalDate.of(2038, 9, 27), 0, false}, - {CASABLANCA, LocalDate.of(2038, 11, 1), ONE_HOUR, true}, - {CASABLANCA, LocalDate.of(2087, 3, 31), 0, false}, - {CASABLANCA, LocalDate.of(2087, 5, 12), ONE_HOUR, true}, + {CASABLANCA, LocalDate.of(2026, 2, 16), 0, false}, + {CASABLANCA, LocalDate.of(2026, 3, 23), ONE_HOUR, true}, + {CASABLANCA, LocalDate.of(2026, 9, 21), 0, false}, + {CASABLANCA, LocalDate.of(2038, 11, 1), 0, false}, }; } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/TimeZoneData/VERSION openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/TimeZoneData/VERSION --- openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/TimeZoneData/VERSION 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/TimeZoneData/VERSION 2026-10-19 12:10:20.000000000 +0000 @@ -1 +1 @@ -tzdata2026b +tzdata2026e diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt --- openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt 2026-10-19 12:10:20.000000000 +0000 @@ -13,7 +13,6 @@ Link America/Sao_Paulo Brazil/East Link America/Manaus Brazil/West Link Europe/Brussels CET -Link America/Chicago CST6CDT Link America/Halifax Canada/Atlantic Link America/Winnipeg Canada/Central Link America/Toronto Canada/Eastern @@ -27,7 +26,6 @@ Link America/Havana Cuba Link Europe/Athens EET Link America/Panama EST -Link America/New_York EST5EDT Link Africa/Cairo Egypt Link Europe/Dublin Eire Link Etc/GMT Etc/GMT+0 @@ -53,7 +51,6 @@ Link Africa/Tripoli Libya Link Europe/Brussels MET Link America/Phoenix MST -Link America/Denver MST7MDT Link America/Tijuana Mexico/BajaNorte Link America/Mazatlan Mexico/BajaSur Link America/Mexico_City Mexico/General @@ -251,6 +248,5 @@ Link Europe/Kyiv Europe/Kiev Link Asia/Nicosia Europe/Nicosia Link Pacific/Honolulu HST -Link America/Los_Angeles PST8PDT Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt --- openjdk-25-25.0.4.1+1/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt 2026-10-19 12:10:20.000000000 +0000 @@ -30,7 +30,7 @@ America/Dawson_Creek MST America/Denver MST MDT America/Detroit EST EDT -America/Edmonton MST MDT +America/Edmonton CST America/El_Salvador CST CDT America/Fort_Nelson MST America/Glace_Bay AST ADT @@ -48,7 +48,7 @@ America/Indiana/Vevay EST EDT America/Indiana/Vincennes EST EDT America/Indiana/Winamac EST EDT -America/Inuvik MST MDT +America/Inuvik CST America/Iqaluit EST EDT America/Jamaica EST America/Juneau AKST AKDT @@ -86,9 +86,9 @@ America/Thule AST ADT America/Tijuana PST PDT America/Toronto EST EDT -America/Vancouver PST PDT +America/Vancouver MST America/Whitehorse MST -America/Winnipeg CST CDT +America/Winnipeg EST America/Yakutat AKST AKDT Antarctica/Macquarie AEST AEDT Asia/Beirut EET EEST @@ -122,6 +122,8 @@ Australia/Melbourne AEST AEDT Australia/Perth AWST AWDT Australia/Sydney AEST AEDT +CST6CDT CST CDT +EST5EDT EST EDT Europe/Andorra CET CEST Europe/Athens EET EEST Europe/Belgrade CET CEST @@ -154,6 +156,8 @@ Europe/Volgograd MSK Europe/Warsaw CET CEST Europe/Zurich CET CEST +MST7MDT MST MDT +PST8PDT PST PDT Pacific/Auckland NZST NZDT Pacific/Guam ChST Pacific/Honolulu HST diff -Nru openjdk-25-25.0.4.1+1/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java openjdk-25-25.0.5+8/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java --- openjdk-25-25.0.4.1+1/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java 2026-10-19 12:10:20.000000000 +0000 @@ -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,33 +25,26 @@ * @bug 8272746 * @modules java.base/jdk.internal.util * @summary Verify that ZipFile rejects files with CEN sizes exceeding the implementation limit + * @library /test/lib + * @build jdk.test.lib.util.ZipUtils * @run junit/othervm EndOfCenValidation */ import jdk.internal.util.ArraysSupport; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.io.*; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.FileChannel; -import java.nio.charset.StandardCharsets; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HexFormat; -import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; -import static org.junit.jupiter.api.Assertions.*; +import static jdk.test.lib.util.ZipUtils.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * This test augments {@link TestTooManyEntries}. It creates sparse ZIPs where @@ -65,36 +58,13 @@ public class EndOfCenValidation { // Zip files produced by this test - public static final Path CEN_TOO_LARGE_ZIP = Path.of("cen-size-too-large.zip"); - public static final Path INVALID_CEN_SIZE = Path.of("invalid-zen-size.zip"); - public static final Path BAD_CEN_OFFSET_ZIP = Path.of("bad-cen-offset.zip"); - // Some ZipFile constants for manipulating the 'End of central directory record' (END header) - private static final int ENDHDR = ZipFile.ENDHDR; // End of central directory record size - private static final int ENDSIZ = ZipFile.ENDSIZ; // Offset of CEN size field within ENDHDR - private static final int ENDOFF = ZipFile.ENDOFF; // Offset of CEN offset field within ENDHDR - // Maximum allowed CEN size allowed by ZipFile - private static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; - - // Expected message when CEN size does not match file size - private static final String INVALID_CEN_BAD_SIZE = "invalid END header (bad central directory size)"; - // Expected message when CEN offset is too large - private static final String INVALID_CEN_BAD_OFFSET = "invalid END header (bad central directory offset)"; - // Expected message when CEN size is too large - private static final String INVALID_CEN_SIZE_TOO_LARGE = "invalid END header (central directory size too large)"; - // Expected message when total entry count is too large - private static final String INVALID_BAD_ENTRY_COUNT = "invalid END header (total entries count too large)"; - - // A valid ZIP file, used as a template - private byte[] zipBytes; + static final Path CEN_TOO_LARGE_ZIP = Path.of("cen-size-too-large.zip"); + static final Path INVALID_CEN_SIZE = Path.of("invalid-zen-size.zip"); + static final Path BAD_CEN_OFFSET_ZIP = Path.of("bad-cen-offset.zip"); + static final Path BAD_ENTRY_COUNT_ZIP = Path.of("bad-entry-count.zip"); - /** - * Create a valid ZIP file, used as a template - * @throws IOException if an error occurs - */ - @BeforeEach - public void setup() throws IOException { - zipBytes = templateZip(); - } + // Maximum allowed CEN size allowed by ZipFile + static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; /** * Delete big files after test, in case the file system did not support sparse files. @@ -105,6 +75,7 @@ Files.deleteIfExists(CEN_TOO_LARGE_ZIP); Files.deleteIfExists(INVALID_CEN_SIZE); Files.deleteIfExists(BAD_CEN_OFFSET_ZIP); + Files.deleteIfExists(BAD_ENTRY_COUNT_ZIP); } /** @@ -115,14 +86,8 @@ @Test public void shouldRejectTooLargeCenSize() throws IOException { int size = MAX_CEN_SIZE + 1; - Path zip = zipWithModifiedEndRecord(size, true, 0, CEN_TOO_LARGE_ZIP); - - ZipException ex = assertThrows(ZipException.class, () -> { - new ZipFile(zip.toFile()); - }); - - assertEquals(INVALID_CEN_SIZE_TOO_LARGE, ex.getMessage()); + verifyRejection(zip, INVALID_CEN_SIZE_TOO_LARGE); } /** @@ -133,16 +98,9 @@ */ @Test public void shouldRejectInvalidCenSize() throws IOException { - int size = MAX_CEN_SIZE; - Path zip = zipWithModifiedEndRecord(size, false, 0, INVALID_CEN_SIZE); - - ZipException ex = assertThrows(ZipException.class, () -> { - new ZipFile(zip.toFile()); - }); - - assertEquals(INVALID_CEN_BAD_SIZE, ex.getMessage()); + verifyRejection(zip, INVALID_CEN_BAD_SIZE); } /** @@ -153,16 +111,9 @@ */ @Test public void shouldRejectInvalidCenOffset() throws IOException { - int size = MAX_CEN_SIZE; - Path zip = zipWithModifiedEndRecord(size, true, 100, BAD_CEN_OFFSET_ZIP); - - ZipException ex = assertThrows(ZipException.class, () -> { - new ZipFile(zip.toFile()); - }); - - assertEquals(INVALID_CEN_BAD_OFFSET, ex.getMessage()); + verifyRejection(zip, INVALID_CEN_BAD_OFFSET); } /** @@ -181,192 +132,20 @@ Long.MAX_VALUE // Unreasonably large }) public void shouldRejectBadTotalEntries(long totalEntries) throws IOException { - /** - * A small ZIP using the ZIP64 format. - * - * ZIP created using: "echo -n hello | zip zip64.zip -" - * Hex encoded using: "cat zip64.zip | xxd -ps" - * - * The file has the following structure: - * - * 0000 LOCAL HEADER #1 04034B50 - * 0004 Extract Zip Spec 2D '4.5' - * 0005 Extract OS 00 'MS-DOS' - * 0006 General Purpose Flag 0000 - * 0008 Compression Method 0000 'Stored' - * 000A Last Mod Time 5947AB78 'Mon Oct 7 21:27:48 2024' - * 000E CRC 363A3020 - * 0012 Compressed Length FFFFFFFF - * 0016 Uncompressed Length FFFFFFFF - * 001A Filename Length 0001 - * 001C Extra Length 0014 - * 001E Filename '-' - * 001F Extra ID #0001 0001 'ZIP64' - * 0021 Length 0010 - * 0023 Uncompressed Size 0000000000000006 - * 002B Compressed Size 0000000000000006 - * 0033 PAYLOAD hello. - * - * 0039 CENTRAL HEADER #1 02014B50 - * 003D Created Zip Spec 1E '3.0' - * 003E Created OS 03 'Unix' - * 003F Extract Zip Spec 2D '4.5' - * 0040 Extract OS 00 'MS-DOS' - * 0041 General Purpose Flag 0000 - * 0043 Compression Method 0000 'Stored' - * 0045 Last Mod Time 5947AB78 'Mon Oct 7 21:27:48 2024' - * 0049 CRC 363A3020 - * 004D Compressed Length 00000006 - * 0051 Uncompressed Length FFFFFFFF - * 0055 Filename Length 0001 - * 0057 Extra Length 000C - * 0059 Comment Length 0000 - * 005B Disk Start 0000 - * 005D Int File Attributes 0001 - * [Bit 0] 1 Text Data - * 005F Ext File Attributes 11B00000 - * 0063 Local Header Offset 00000000 - * 0067 Filename '-' - * 0068 Extra ID #0001 0001 'ZIP64' - * 006A Length 0008 - * 006C Uncompressed Size 0000000000000006 - * - * 0074 ZIP64 END CENTRAL DIR 06064B50 - * RECORD - * 0078 Size of record 000000000000002C - * 0080 Created Zip Spec 1E '3.0' - * 0081 Created OS 03 'Unix' - * 0082 Extract Zip Spec 2D '4.5' - * 0083 Extract OS 00 'MS-DOS' - * 0084 Number of this disk 00000000 - * 0088 Central Dir Disk no 00000000 - * 008C Entries in this disk 0000000000000001 - * 0094 Total Entries 0000000000000001 - * 009C Size of Central Dir 000000000000003B - * 00A4 Offset to Central dir 0000000000000039 - * - * 00AC ZIP64 END CENTRAL DIR 07064B50 - * LOCATOR - * 00B0 Central Dir Disk no 00000000 - * 00B4 Offset to Central dir 0000000000000074 - * 00BC Total no of Disks 00000001 - * - * 00C0 END CENTRAL HEADER 06054B50 - * 00C4 Number of this disk 0000 - * 00C6 Central Dir Disk no 0000 - * 00C8 Entries in this disk 0001 - * 00CA Total Entries 0001 - * 00CC Size of Central Dir 0000003B - * 00D0 Offset to Central Dir FFFFFFFF - * 00D4 Comment Length 0000 - */ - - byte[] zipBytes = HexFormat.of().parseHex(""" - 504b03042d000000000078ab475920303a36ffffffffffffffff01001400 - 2d010010000600000000000000060000000000000068656c6c6f0a504b01 - 021e032d000000000078ab475920303a3606000000ffffffff01000c0000 - 00000001000000b011000000002d010008000600000000000000504b0606 - 2c000000000000001e032d00000000000000000001000000000000000100 - 0000000000003b000000000000003900000000000000504b060700000000 - 740000000000000001000000504b050600000000010001003b000000ffff - ffff0000 - """.replaceAll("\n","")); - - // Buffer to manipulate the above ZIP - ByteBuffer buf = ByteBuffer.wrap(zipBytes).order(ByteOrder.LITTLE_ENDIAN); - // Offset of the 'total entries' in the 'ZIP64 END CENTRAL DIR' record - // Update ZIP64 entry count to a value which cannot possibly fit in the small CEN - buf.putLong(0x94, totalEntries); - // The corresponding END field needs the ZIP64 magic value - buf.putShort(0xCA, (short) 0xFFFF); - // Write the ZIP to disk - Path zipFile = Path.of("bad-entry-count.zip"); - Files.write(zipFile, zipBytes); - - // Verify that the END header is rejected - ZipException ex = assertThrows(ZipException.class, () -> { - try (var zf = new ZipFile(zipFile.toFile())) { - } - }); - - assertEquals(INVALID_BAD_ENTRY_COUNT, ex.getMessage()); - } - - /** - * Create an ZIP file with a single entry, then modify the CEN size - * in the 'End of central directory record' (END header) to the given size. - * - * The CEN is optionally "inflated" with trailing zero bytes such that - * its actual size matches the one stated in the END header. - * - * The CEN offset is optiontially adjusted by the given amount - * - * The resulting ZIP is technically not valid, but it does allow us - * to test that large or invalid CEN sizes are rejected - * @param cenSize the CEN size to put in the END record - * @param inflateCen if true, zero-pad the CEN to the desired size - * @param cenOffAdjust Adjust the CEN offset field of the END record with this amount - * @throws IOException if an error occurs - */ - private Path zipWithModifiedEndRecord(int cenSize, - boolean inflateCen, - int cenOffAdjust, - Path zip) throws IOException { - - // A byte buffer for reading the END - ByteBuffer buffer = ByteBuffer.wrap(zipBytes.clone()).order(ByteOrder.LITTLE_ENDIAN); - - // Offset of the END header - int endOffset = buffer.limit() - ENDHDR; - - // Modify the CEN size - int sizeOffset = endOffset + ENDSIZ; - int currentCenSize = buffer.getInt(sizeOffset); - buffer.putInt(sizeOffset, cenSize); - - // Optionally modify the CEN offset - if (cenOffAdjust != 0) { - int offOffset = endOffset + ENDOFF; - int currentCenOff = buffer.getInt(offOffset); - buffer.putInt(offOffset, currentCenOff + cenOffAdjust); - } - - // When creating a sparse file, the file must not already exit - Files.deleteIfExists(zip); - - // Open a FileChannel for writing a sparse file - EnumSet options = EnumSet.of(StandardOpenOption.CREATE_NEW, - StandardOpenOption.WRITE, - StandardOpenOption.SPARSE); - - try (FileChannel channel = FileChannel.open(zip, options)) { - - // Write everything up to END - channel.write(buffer.slice(0, buffer.limit() - ENDHDR)); - - if (inflateCen) { - // Inject "empty bytes" to make the actual CEN size match the END - int injectBytes = cenSize - currentCenSize; - channel.position(channel.position() + injectBytes); - } - // Write the modified END - channel.write(buffer.slice(buffer.limit() - ENDHDR, ENDHDR)); - } - return zip; + Path zip = zip64WithModifiedTotalEntries(BAD_ENTRY_COUNT_ZIP, totalEntries); + verifyRejection(zip, INVALID_BAD_ENTRY_COUNT); } /** - * Produce a byte array of a ZIP with a single entry - * - * @throws IOException if an error occurs + * Verify that ZipFile rejects the ZIP file with a ZipException + * with the given message + * @param zip ZIP file to open + * @param msg exception message to expect */ - private byte[] templateZip() throws IOException { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - try (ZipOutputStream zo = new ZipOutputStream(bout)) { - ZipEntry entry = new ZipEntry("duke.txt"); - zo.putNextEntry(entry); - zo.write("duke".getBytes(StandardCharsets.UTF_8)); - } - return bout.toByteArray(); + private static void verifyRejection(Path zip, String msg) { + ZipException ex = assertThrows(ZipException.class, () -> { + new ZipFile(zip.toFile()); + }); + assertEquals(msg, ex.getMessage()); } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java --- openjdk-25-25.0.4.1+1/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (C) 2022, Tencent. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,7 +27,7 @@ /* * @test - * @bug 8281236 + * @bug 8281236 8314323 * @summary Check TLS connection behaviors for named groups configuration * @library /javax/net/ssl/templates * @run main/othervm NamedGroups @@ -136,6 +137,60 @@ "secp256r1" }, true); + + runTest(new String[] { + "X25519MLKEM768" + }, + new String[] { + "X25519MLKEM768" + }, + false); + + runTest(new String[] { + "SecP256r1MLKEM768" + }, + new String[] { + "SecP256r1MLKEM768" + }, + false); + + runTest(new String[] { + "SecP384r1MLKEM1024" + }, + new String[] { + "SecP384r1MLKEM1024" + }, + false); + + runTest(new String[] { + "X25519MLKEM768" + }, + new String[] { + "SecP256r1MLKEM768" + }, + true); + + runTest(new String[] { + "X25519MLKEM768" + }, + new String[0], + true); + + runTest(new String[] { + "SecP256r1MLKEM768" + }, + null, + true); + + runTest(new String[] { + "X25519MLKEM768", + "x25519" + }, + new String[] { + "X25519MLKEM768", + "x25519" + }, + false); } private static void runTest(String[] serverNamedGroups, diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java --- openjdk-25-25.0.4.1+1/test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,11 @@ FFDHE3072("ffdhe3072"), FFDHE4096("ffdhe4096"), FFDHE6144("ffdhe6144"), - FFDHE8192("ffdhe8192"); + FFDHE8192("ffdhe8192"), + + X25519MLKEM768("X25519MLKEM768"), + SECP256R1MLKEM768("SecP256r1MLKEM768"), + SECP384R1MLKEM1024("SecP384r1MLKEM1024"); public final String name; diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java --- openjdk-25-25.0.4.1+1/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java 2026-10-19 12:10:20.000000000 +0000 @@ -27,16 +27,21 @@ /* * @test - * @bug 8247630 + * @bug 8247630 8314323 * @summary Use two key share entries - * @run main/othervm ClientHelloKeyShares 29 23 + * @run main/othervm ClientHelloKeyShares 4588 29 * @run main/othervm -Djdk.tls.namedGroups=secp384r1,secp521r1,x448,ffdhe2048 ClientHelloKeyShares 24 30 * @run main/othervm -Djdk.tls.namedGroups=sect163k1,sect163r1,x25519 ClientHelloKeyShares 29 * @run main/othervm -Djdk.tls.namedGroups=sect163k1,sect163r1,secp256r1 ClientHelloKeyShares 23 * @run main/othervm -Djdk.tls.namedGroups=sect163k1,sect163r1,ffdhe2048,ffdhe3072,ffdhe4096 ClientHelloKeyShares 256 * @run main/othervm -Djdk.tls.namedGroups=sect163k1,ffdhe2048,x25519,secp256r1 ClientHelloKeyShares 256 29 * @run main/othervm -Djdk.tls.namedGroups=secp256r1,secp384r1,ffdhe2048,x25519 ClientHelloKeyShares 23 256 - */ + * @run main/othervm -Djdk.tls.namedGroups=X25519MLKEM768 ClientHelloKeyShares 4588 + * @run main/othervm -Djdk.tls.namedGroups=x25519,X25519MLKEM768 ClientHelloKeyShares 29 4588 + * @run main/othervm -Djdk.tls.namedGroups=SecP256r1MLKEM768,x25519 ClientHelloKeyShares 4587 29 + * @run main/othervm -Djdk.tls.namedGroups=SecP384r1MLKEM1024,secp256r1 ClientHelloKeyShares 4589 23 + * @run main/othervm -Djdk.tls.namedGroups=X25519MLKEM768,SecP256r1MLKEM768,X25519,secp256r1 ClientHelloKeyShares 4588 29 +*/ import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; @@ -52,10 +57,6 @@ private static final int HELLO_EXT_SUPP_VERS = 43; private static final int HELLO_EXT_KEY_SHARE = 51; private static final int TLS_PROT_VER_13 = 0x0304; - private static final int NG_SECP256R1 = 0x0017; - private static final int NG_SECP384R1 = 0x0018; - private static final int NG_X25519 = 0x001D; - private static final int NG_X448 = 0x001E; public static void main(String args[]) throws Exception { // Arguments to this test are an abitrary number of integer diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java --- openjdk-25-25.0.4.1+1/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java 2026-10-19 12:10:20.000000000 +0000 @@ -27,10 +27,12 @@ /* * @test - * @bug 8247630 + * @bug 8247630 8314323 * @summary Use two key share entries * @library /test/lib - * @run main/othervm -Djdk.tls.namedGroups=x25519,secp256r1,secp384r1 HRRKeyShares + * @run main/othervm + * -Djdk.tls.namedGroups=x25519,secp256r1,secp384r1,X25519MLKEM768,SecP256r1MLKEM768,SecP384r1MLKEM1024 + * HRRKeyShares */ import java.io.ByteArrayOutputStream; @@ -63,6 +65,10 @@ private static final int NG_SECP384R1 = 0x0018; private static final int NG_X25519 = 0x001D; private static final int NG_X448 = 0x001E; + private static final int NG_X25519_MLKEM768 = 0x11EC; + private static final int NG_SECP256R1_MLKEM768 = 0x11EB; + private static final int NG_SECP384R1_MLKEM1024 = 0x11ED; + private static final int NG_GC512A = 0x0026; private static final int COMP_NONE = 0; private static final int ALERT_TYPE_FATAL = 2; @@ -224,6 +230,18 @@ System.out.println("Test 4: Bad HRR using known / unasserted x448"); hrrKeyShareTest(NG_X448, false); System.out.println(); + + System.out.println("Test 5: Good HRR exchange using X25519MLKEM768"); + hrrKeyShareTest(NG_X25519_MLKEM768, true); + System.out.println(); + + System.out.println("Test 6: Good HRR exchange using SecP256r1MLKEM768"); + hrrKeyShareTest(NG_SECP256R1_MLKEM768, true); + System.out.println(); + + System.out.println("Test 7: Good HRR exchange using SecP384r1MLKEM1024"); + hrrKeyShareTest(NG_SECP384R1_MLKEM1024, true); + System.out.println(); } private static void logResult(String str, SSLEngineResult result) { @@ -334,7 +352,8 @@ try { // Now we're expecting to reissue the ClientHello, this time - // with a secp384r1 share. + // with a key share for the HRR requested named + // group (hrrNamedGroup). cTOs.compact(); clientResult = engine.wrap(clientOut, cTOs); logResult("client wrap: ", clientResult); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/net/ssl/ciphersuites/BulkCipherDisabledAlgorithms.java openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/ciphersuites/BulkCipherDisabledAlgorithms.java --- openjdk-25-25.0.4.1+1/test/jdk/javax/net/ssl/ciphersuites/BulkCipherDisabledAlgorithms.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/net/ssl/ciphersuites/BulkCipherDisabledAlgorithms.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,197 @@ +/* + * 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 8387124 + * @summary Verify that disabling bulk cipher algorithms in + * jdk.tls.disabledAlgorithms disables associated TLS cipher suites. + * @library /test/lib + * /javax/net/ssl/TLSCommon + * /javax/net/ssl/templates + */ + +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLSocket; + +import jdk.test.lib.process.Proc; + +/* + * Each test case is executed in a separate JVM because + * jdk.tls.disabledAlgorithms is evaluated during JSSE initialization and + * cannot be reliably reconfigured within the same VM. + */ +public class BulkCipherDisabledAlgorithms { + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + // Sanity check: all enabled cipher suites should work before + // applying any jdk.tls.disabledAlgorithms restrictions. + testAllCipherSuitesEnabled(); + + // Verify that disabling a bulk cipher algorithm disables cipher + // suites that use that algorithm. + Map> cipherSuitesByBulkCipher = groupCipherSuitesByBulkCipher(); + + for (Map.Entry> entry : cipherSuitesByBulkCipher.entrySet()) { + String disabledBulkCipher = entry.getKey(); + List disabledCipherSuites = entry.getValue(); + + // Verify that all cipher suites associated with the disabled + // bulk cipher become unavailable. + Proc p = Proc.create( + BulkCipherDisabledAlgorithms.class.getName()) + .args(disabledBulkCipher, + String.join(",", disabledCipherSuites)) + .secprop("jdk.tls.disabledAlgorithms", disabledBulkCipher) + .inheritIO(); + + p.start().waitFor(0); + } + + System.out.println("TEST PASS - OK"); + return; + } + + String disabledBulkCipher = args[0]; + List disabledCipherSuites = Arrays.asList(args[1].split(",")); + + for (String disabledCipherSuite : disabledCipherSuites) { + System.out.println("================================================="); + System.out.println("Testing: suite=" + disabledCipherSuite + + ", disabled bulk cipher=" + disabledBulkCipher); + + testCipherSuiteDisabled(disabledCipherSuite); + testHandshake(disabledCipherSuite, true); + } + } + + private static void testAllCipherSuitesEnabled() throws Exception { + CipherSuite[] suites = getCipherSuites(); + + for (CipherSuite suite : suites) { + testHandshake(suite.name(), false); + } + } + + private static CipherSuite[] getCipherSuites() throws NoSuchAlgorithmException { + SSLEngine engine = SSLContext.getDefault().createSSLEngine(); + String[] suites = engine.getEnabledCipherSuites(); + return Arrays.stream(suites) + .map(CipherSuite::cipherSuite) + .filter(cs -> cs != CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) + .toArray(CipherSuite[]::new); + } + + private static Map> groupCipherSuitesByBulkCipher() throws NoSuchAlgorithmException { + Map> cipherSuitesByBulkCipher = new LinkedHashMap<>(); + CipherSuite[] suites = getCipherSuites(); + + for (CipherSuite suite : suites) { + String suiteName = suite.name(); + String bulkCipher = extractBulkCipher(suiteName); + List suitesForBulk = cipherSuitesByBulkCipher.get(bulkCipher); + + if (suitesForBulk == null) { + suitesForBulk = new ArrayList<>(); + cipherSuitesByBulkCipher.put(bulkCipher, suitesForBulk); + } + + suitesForBulk.add(suiteName); + } + + return cipherSuitesByBulkCipher; + } + + /** + * Separator used in TLS cipher suite names to mark the start of + * the bulk cipher component (e.g. TLS_RSA_WITH_AES_128_CBC_SHA). + */ + private static final String WITH = "_WITH_"; + + private static String extractBulkCipher(String suite) { + if (suite.contains(WITH)) { + String after = suite.substring(suite.indexOf(WITH) + WITH.length()); + int last = after.lastIndexOf('_'); + return after.substring(0, last); + } else { + int first = suite.indexOf('_'); + int last = suite.lastIndexOf('_'); + return suite.substring(first + 1, last); + } + } + + private static void testCipherSuiteDisabled(String suite) throws NoSuchAlgorithmException { + boolean visible = Arrays.asList(getCipherSuites()) + .contains(CipherSuite.cipherSuite(suite)); + + if (visible) { + throw new RuntimeException( + "Cipher suite '" + suite + "' visible but expected to be disabled"); + } + } + + private static void testHandshake(String cipherSuite, boolean expectedDisabled) throws Exception { + try { + new TLSHandshakeTest(cipherSuite).run(); + + if (expectedDisabled) { + throw new RuntimeException( + "Handshake succeeded but should fail: " + cipherSuite); + } + } catch (SSLHandshakeException e) { + if (!expectedDisabled) { + throw new RuntimeException( + "Handshake failed unexpectedly: " + cipherSuite, e); + } + } + } + + private static class TLSHandshakeTest extends SSLSocketTemplate { + private final String cipherSuite; + + TLSHandshakeTest(String cipherSuite) { + this.cipherSuite = cipherSuite; + } + + @Override + protected void configureClientSocket(SSLSocket socket) { + socket.setEnabledCipherSuites(new String[] { cipherSuite }); + } + + @Override + protected void configureServerSocket(SSLServerSocket socket) { + socket.setEnabledCipherSuites(new String[] { cipherSuite }); + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java --- openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java 2026-10-19 12:10:20.000000000 +0000 @@ -28,14 +28,21 @@ import java.io.FileInputStream; import java.io.FileReader; import java.io.InputStreamReader; +import java.io.StringReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStreamWriter; import java.math.BigDecimal; +import java.nio.file.Files; +import java.nio.file.Path; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; import java.util.Arrays; import javax.sql.rowset.WebRowSet; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertThrows; import static org.testng.Assert.assertEqualsNoOrder; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; @@ -97,7 +104,7 @@ } /* - * Utility method to write a WebRowSet XML file via an Writer + * Utility method to write a WebRowSet XML file via a Writer */ protected ByteArrayOutputStream writeWebRowSetWithOutputStreamWithWriter(WebRowSet rs) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -107,7 +114,7 @@ } /* - * Utility method to write a WebRowSet XML file via an Writer and populating + * Utility method to write a WebRowSet XML file via a Writer and populating * the WebRowSet via a ResultSet */ protected ByteArrayOutputStream writeWebRowSetWithOutputStreamWithWriter(ResultSet rs) throws Exception { @@ -397,4 +404,281 @@ wrs1.close(); } + private static final String ROWSET_VALIDATION_PROPERTY + = "jdk.sql.rowset.webrowsetValidation"; + + @FunctionalInterface + private interface ThrowingRunnable { + void run() throws Exception; + } + + /** + * Runs the given action with the WebRowSet validation system property set + * to the requested value, then restores the previous value. + * + * @param value the temporary property value, or {@code null} to clear it + * @param action the action to run while the property is set + */ + private static synchronized void withRowSetValidation(String value, + ThrowingRunnable action) throws Exception { + String previous = System.getProperty(ROWSET_VALIDATION_PROPERTY); + try { + if (value == null) { + System.clearProperty(ROWSET_VALIDATION_PROPERTY); + } else { + System.setProperty(ROWSET_VALIDATION_PROPERTY, value); + } + action.run(); + } finally { + if (previous == null) { + System.clearProperty(ROWSET_VALIDATION_PROPERTY); + } else { + System.setProperty(ROWSET_VALIDATION_PROPERTY, previous); + } + } + } + + /** + * Verifies that an updated row written as XML can be read back with schema + * validation enabled. + */ + @Test(dataProvider = "rowSetType") + public void testUpdatedRows(WebRowSet wrs) throws Exception { + try { + readCoffeeRows(wrs); + wrs.absolute(3); + wrs.updateInt(5, 21); + wrs.updateInt(6, 69); + wrs.updateRow(); + + ByteArrayOutputStream baos = + writeWebRowSetWithOutputStreamWithWriter(wrs); + withRowSetValidation(null, () -> { + // Clearing the property ensures validation is enabled; + // verifies the writer emits schema-compliant + // modifyRow/updateValue XML. + try (WebRowSet wrs1 = + readWebRowSetWithOInputStreamWithReader(baos)) { + assertEquals(wrs1.size(), COFFEES_ROWS); + assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); + + assertTrue(findRowByPrimaryKey(wrs1, 3, 1)); + assertTrue(wrs1.rowUpdated()); + assertEquals(wrs1.getInt(5), 21); + assertEquals(wrs1.getInt(6), 69); + } + }); + } finally { + wrs.close(); + } + } + + /** + * Verifies that a deleted row written as XML can be read back with schema + * validation enabled. + */ + @Test(dataProvider = "rowSetType") + public void testDeletedRows(WebRowSet wrs) + throws Exception { + try { + readCoffeeRows(wrs); + assertTrue(deleteRowByPrimaryKey(wrs, 2, 1)); + + ByteArrayOutputStream baos = + writeWebRowSetWithOutputStreamWithWriter(wrs); + withRowSetValidation(null, () -> { + // Clearing the property ensures validation is enabled; parsing + // fails if the writer omits schema-required empty updateValue + // elements. + try (WebRowSet wrs1 = + readWebRowSetWithOInputStreamWithReader(baos)) { + Object[] expectedRows = {1, 3, 4, 5}; + assertEquals(wrs1.size(), COFFEES_ROWS); + assertEquals(getPrimaryKeys(wrs1), expectedRows); + + wrs1.setShowDeleted(true); + assertTrue(findRowByPrimaryKey(wrs1, 2, 1)); + assertTrue(wrs1.rowDeleted()); + assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); + } + }); + } finally { + wrs.close(); + } + } + + /** + * Verifies that null properties are written as schema-compliant empty + * elements and read back as null. + */ + @Test(dataProvider = "rowSetType") + public void testNullProperties(WebRowSet wrs) throws Exception { + try { + readCoffeeRows(wrs); + assertNull(wrs.getCommand()); + assertNull(wrs.getDataSourceName()); + assertNull(wrs.getUrl()); + + ByteArrayOutputStream baos = + writeWebRowSetWithOutputStreamWithWriter(wrs); + withRowSetValidation(null, () -> { + // Reading with validation enabled fails if the writer emits the + // legacy invalid form for nullable properties. + try (WebRowSet wrs1 = + readWebRowSetWithOInputStreamWithReader(baos)) { + assertEquals(wrs1.size(), COFFEES_ROWS); + assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); + assertNull(wrs1.getCommand()); + assertNull(wrs1.getDataSourceName()); + assertNull(wrs1.getUrl()); + } + }); + } finally { + wrs.close(); + } + } + + /** + * Verifies that legacy XML is rejected since schema validation is enabled + * by default. + */ + @Test(dataProvider = "rowSetType") + public void testLegacyXmlWithValidation(WebRowSet wrs) + throws Exception { + String legacyXml = getLegacyXml(); + withRowSetValidation(null, () -> { + try { + assertThrows(SQLException.class, + () -> wrs.readXml(new StringReader(legacyXml))); + } finally { + wrs.close(); + } + }); + } + + /** + * Verifies that legacy XML is accepted when schema validation is explicitly + * disabled. + */ + @Test(dataProvider = "rowSetType") + public void testLegacyXmlWithoutValidation(WebRowSet wrs) + throws Exception { + String legacyXml = getLegacyXml() + // Exercise the path where an empty element follows a value bearing + // element. This is for JDK-8386783 + .replace("jdbc:derby://localhost:1527/testDB;create=true", ""); + withRowSetValidation("false", () -> { + try { + wrs.readXml(new StringReader(legacyXml)); + assertNull(wrs.getUrl()); + assertEquals(wrs.size(), COFFEES_ROWS); + assertEquals(getPrimaryKeys(wrs), COFFEES_PRIMARY_KEYS); + + wrs.beforeFirst(); + boolean foundUpdatedRow = false; + while (wrs.next()) { + if (wrs.getInt(1) == 3) { + foundUpdatedRow = true; + assertTrue(wrs.rowUpdated()); + assertEquals(wrs.getInt(5), 21); + assertEquals(wrs.getInt(6), 69); + } + } + assertTrue(foundUpdatedRow); + } finally { + wrs.close(); + } + }); + } + + /** + * Verifies that legacy null elements are rejected since schema validation + * is enabled by default. + */ + @Test(dataProvider = "rowSetType") + public void testLegacyNullXmlWithValidation(WebRowSet wrs) + throws Exception { + String legacyXml = getLegacyNullXml(); + withRowSetValidation(null, () -> { + try { + // Legacy property values are not valid against the + // standard schema. + assertThrows(SQLException.class, + () -> wrs.readXml(new StringReader(legacyXml))); + } finally { + wrs.close(); + } + }); + } + + /** + * Verifies that legacy null elements are accepted when schema validation is + * explicitly disabled. + */ + @Test(dataProvider = "rowSetType") + public void testLegacyNullXmlWithoutValidation(WebRowSet wrs) + throws Exception { + String legacyXml = getLegacyNullXml(); + withRowSetValidation("false", () -> { + try { + wrs.readXml(new StringReader(legacyXml)); + assertEquals(wrs.size(), COFFEES_ROWS); + assertEquals(getPrimaryKeys(wrs), COFFEES_PRIMARY_KEYS); + + // With validation disabled, preserve the old reader behavior + // for nullable properties and metadata represented by . + assertNull(wrs.getCommand()); + assertNull(wrs.getDataSourceName()); + assertNull(wrs.getUrl()); + + ResultSetMetaData md = wrs.getMetaData(); + for (int i = 1; i <= md.getColumnCount(); i++) { + assertEquals(md.getColumnLabel(i), ""); + assertEquals(md.getColumnTypeName(i), ""); + } + } finally { + wrs.close(); + } + }); + } + + /** + * Builds a legacy document from the schema-compliant UPDATED_COFFEE_ROWS_XML + * file. Older WebRowSet XML used currentRow/updateRow for modified rows, + * while the webrowset schema requires modifyRow/updateValue. + */ + private String getLegacyXml() throws Exception { + return Files.readString(Path.of(UPDATED_COFFEE_ROWS_XML)) + .replace("", "") + .replace("", "") + .replace("updateValue", "updateRow"); + } + + /** + * Builds a legacy document from the schema-compliant COFFEE_ROWS_XML file. + * Older WebRowSet XML used nested {@code } elements for nullable + * string properties and metadata, while the webrowset schema requires + * simple string content. + */ + private String getLegacyNullXml() throws Exception { + return Files.readString(Path.of(COFFEE_ROWS_XML)) + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", + "") + .replace("", + ""); + } + + + /** + * Reads COFFEE_ROWS_XML and populates the given WebRowSet. + */ + private void readCoffeeRows(WebRowSet wrs) throws Exception { + try (FileInputStream fis = new FileInputStream(COFFEE_ROWS_XML)) { + wrs.readXml(fis); + } + } + } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml --- openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml 2026-10-19 12:10:20.000000000 +0000 @@ -2,9 +2,9 @@ - + 1008 - + true 1000 0 @@ -20,7 +20,7 @@ ResultSet.TYPE_SCROLL_INSENSITIVE false COFFEES - + com.sun.rowset.providers.RIOptimisticProvider Oracle Corporation @@ -40,7 +40,7 @@ false false 0 - + COF_NAME 0 @@ -48,7 +48,7 @@ 4 - + 2 @@ -59,7 +59,7 @@ false false 0 - + SUP_ID 0 @@ -67,7 +67,7 @@ 12 - + 3 @@ -78,7 +78,7 @@ false false 0 - + PRICE 0 @@ -86,7 +86,7 @@ 4 - + 4 @@ -97,7 +97,7 @@ false false 0 - + SALES 10 @@ -105,7 +105,7 @@ 2 - + 5 @@ -116,7 +116,7 @@ false false 0 - + TOTAL 0 @@ -124,7 +124,7 @@ 4 - + 6 @@ -135,15 +135,15 @@ false false 0 - - + + 0 0 4 - + diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml --- openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml 2026-10-19 12:10:20.000000000 +0000 @@ -4,7 +4,7 @@ SELECT * FROM COFFEES 1008 - + true 1000 0 @@ -40,7 +40,7 @@ false false 0 - + COF_NAME 0 @@ -48,7 +48,7 @@ 4 - + 2 @@ -59,7 +59,7 @@ false false 0 - + SUP_ID 0 @@ -67,7 +67,7 @@ 12 - + 3 @@ -78,7 +78,7 @@ false false 0 - + PRICE 0 @@ -86,7 +86,7 @@ 4 - + 4 @@ -97,7 +97,7 @@ false false 0 - + SALES 10 @@ -105,7 +105,7 @@ 2 - + 5 @@ -116,7 +116,7 @@ false false 0 - + TOTAL 0 @@ -124,7 +124,7 @@ 4 - + 6 @@ -135,15 +135,15 @@ false false 0 - - + + 0 0 4 - + @@ -156,12 +156,12 @@ 0 - 2 - French_Roast - 49 - 8.99 - 0 - 0 + 2 + French_Roast + 49 + 8.99 + 0 + 0 3 @@ -172,12 +172,12 @@ 0 - 4 - Colombian_Decaf - 101 - 8.99 - 0 - 0 + 4 + Colombian_Decaf + 101 + 8.99 + 0 + 0 5 diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml --- openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml 2026-10-19 12:10:20.000000000 +0000 @@ -2,9 +2,9 @@ - + 1008 - + true 1000 0 @@ -20,7 +20,7 @@ ResultSet.TYPE_SCROLL_INSENSITIVE false COFFEES - + com.sun.rowset.providers.RIOptimisticProvider Oracle Corporation @@ -40,7 +40,7 @@ false false 0 - + COF_NAME 0 @@ -48,7 +48,7 @@ 4 - + 2 @@ -59,7 +59,7 @@ false false 0 - + SUP_ID 0 @@ -67,7 +67,7 @@ 12 - + 3 @@ -78,7 +78,7 @@ false false 0 - + PRICE 0 @@ -86,7 +86,7 @@ 4 - + 4 @@ -97,7 +97,7 @@ false false 0 - + SALES 10 @@ -105,7 +105,7 @@ 2 - + 5 @@ -116,7 +116,7 @@ false false 0 - + TOTAL 0 @@ -124,7 +124,7 @@ 4 - + 6 @@ -135,15 +135,15 @@ false false 0 - - + + 0 0 4 - + diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml --- openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml 2026-10-19 12:10:20.000000000 +0000 @@ -2,9 +2,9 @@ - + 1008 - + true 1000 0 @@ -20,7 +20,7 @@ ResultSet.TYPE_SCROLL_INSENSITIVE false COFFEES - + com.sun.rowset.providers.RIOptimisticProvider Oracle Corporation @@ -40,7 +40,7 @@ false false 0 - + COF_NAME 0 @@ -48,7 +48,7 @@ 4 - + 2 @@ -59,7 +59,7 @@ false false 0 - + SUP_ID 0 @@ -67,7 +67,7 @@ 12 - + 3 @@ -78,7 +78,7 @@ false false 0 - + PRICE 0 @@ -86,7 +86,7 @@ 4 - + 4 @@ -97,7 +97,7 @@ false false 0 - + SALES 10 @@ -105,7 +105,7 @@ 2 - + 5 @@ -116,7 +116,7 @@ false false 0 - + TOTAL 0 @@ -124,7 +124,7 @@ 4 - + 6 @@ -135,15 +135,15 @@ false false 0 - - + + 0 0 4 - + @@ -156,12 +156,12 @@ 0 - 2 - French_Roast - 49 - 8.99 - 0 - 0 + 2 + French_Roast + 49 + 8.99 + 0 + 0 3 @@ -172,12 +172,12 @@ 0 - 4 - Colombian_Decaf - 101 - 8.99 - 0 - 0 + 4 + Colombian_Decaf + 101 + 8.99 + 0 + 0 5 diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml --- openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml 2026-10-19 12:10:20.000000000 +0000 @@ -4,7 +4,7 @@ SELECT * FROM COFFEES 1008 - + true 1000 0 @@ -40,7 +40,7 @@ false false 0 - + COF_NAME 0 @@ -48,7 +48,7 @@ 4 - + 2 @@ -59,7 +59,7 @@ false false 0 - + SUP_ID 0 @@ -67,7 +67,7 @@ 12 - + 3 @@ -78,7 +78,7 @@ false false 0 - + PRICE 0 @@ -86,7 +86,7 @@ 4 - + 4 @@ -97,7 +97,7 @@ false false 0 - + SALES 10 @@ -105,7 +105,7 @@ 2 - + 5 @@ -116,7 +116,7 @@ false false 0 - + TOTAL 0 @@ -124,7 +124,7 @@ 4 - + 6 @@ -135,15 +135,15 @@ false false 0 - - + + 0 0 4 - + @@ -163,16 +163,20 @@ 0 0 - + 3 + 3 Espresso + Espresso 150 + 150 9.99 + 9.99 0 - 21 + 21 0 - 69 - + 69 + 4 Colombian_Decaf diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml --- openjdk-25-25.0.4.1+1/test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml 2026-10-19 12:10:20.000000000 +0000 @@ -2,9 +2,9 @@ - + 1008 - + true 1000 0 @@ -20,7 +20,7 @@ ResultSet.TYPE_SCROLL_INSENSITIVE false COFFEES - + com.sun.rowset.providers.RIOptimisticProvider Oracle Corporation @@ -40,7 +40,7 @@ false false 0 - + COF_NAME 0 @@ -48,7 +48,7 @@ 4 - + 2 @@ -59,7 +59,7 @@ false false 0 - + SUP_ID 0 @@ -67,7 +67,7 @@ 12 - + 3 @@ -78,7 +78,7 @@ false false 0 - + PRICE 0 @@ -86,7 +86,7 @@ 4 - + 4 @@ -97,7 +97,7 @@ false false 0 - + SALES 10 @@ -105,7 +105,7 @@ 2 - + 5 @@ -116,7 +116,7 @@ false false 0 - + TOTAL 0 @@ -124,7 +124,7 @@ 4 - + 6 @@ -135,15 +135,15 @@ false false 0 - - + + 0 0 4 - + @@ -192,10 +192,10 @@ Mocha 49 9.99 - 12.99 + 12.99 20 35 - 125 + 125 diff -Nru openjdk-25-25.0.4.1+1/test/jdk/javax/swing/SwingWorker/TestDoneBeforeDoInBackground.java openjdk-25-25.0.5+8/test/jdk/javax/swing/SwingWorker/TestDoneBeforeDoInBackground.java --- openjdk-25-25.0.4.1+1/test/jdk/javax/swing/SwingWorker/TestDoneBeforeDoInBackground.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/javax/swing/SwingWorker/TestDoneBeforeDoInBackground.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -23,6 +23,7 @@ /* * @test * @bug 8081474 + * @library /test/lib * @summary Verifies if SwingWorker calls 'done' * before the 'doInBackground' is finished * @run main TestDoneBeforeDoInBackground @@ -34,22 +35,25 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import jdk.test.lib.Utils; + public class TestDoneBeforeDoInBackground { - private static final int WAIT_TIME = 200; + private static final long WAIT_TIME = Utils.adjustTimeout(200); private static final long CLEANUP_TIME = 1000; private static final AtomicBoolean doInBackgroundStarted = new AtomicBoolean(false); private static final AtomicBoolean doInBackgroundFinished = new AtomicBoolean(false); private static final AtomicBoolean doneFinished = new AtomicBoolean(false); private static final CountDownLatch doneLatch = new CountDownLatch(1); + private static final CountDownLatch workerStarted = new CountDownLatch(1); public static void main(String[] args) throws InterruptedException { SwingWorker worker = new SwingWorker<>() { @Override protected String doInBackground() throws Exception { try { - while (!Thread.currentThread().isInterrupted()) { + while (true) { System.out.println("Working..."); Thread.sleep(WAIT_TIME); } @@ -85,6 +89,12 @@ worker.addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { + if (worker.getState() == SwingWorker.StateValue.STARTED) { + // Now the worker has started and we got a STARTED + // notification. It should be save to cancel now. + workerStarted.countDown(); + } + System.out.println("doInBackgroundStarted: " + doInBackgroundStarted.get() + " doInBackgroundFinished: " + @@ -121,7 +131,9 @@ } }); worker.execute(); - Thread.sleep(WAIT_TIME * 3); + if (!workerStarted.await(5 * WAIT_TIME, TimeUnit.MILLISECONDS)) { + throw new RuntimeException("worker didn't start in time"); + } final long start = System.currentTimeMillis(); worker.cancel(true); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, Red Hat, Inc. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @run main/timeout=360 TestDockerBasic */ @@ -42,10 +43,8 @@ private static final String imageName = Common.imageName("javaDockerBasic"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,8 @@ private static final String imageName = Common.imageName("metrics-cpu"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); // These tests create a docker image and run this image with // varying docker cpu options. The arguments passed to the docker diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java 2026-10-19 12:10:20.000000000 +0000 @@ -45,9 +45,8 @@ private static final String imageName = Common.imageName("metrics-memory"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); // These tests create a docker image and run this image with // varying docker memory options. The arguments passed to the docker diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java 2026-10-19 12:10:20.000000000 +0000 @@ -41,6 +41,7 @@ * @summary Cgroup v1 subsystem fails to set subsystem path * @requires container.support * @requires !vm.asan + * @requires !vm.ubsan * @library /test/lib * @modules java.base/jdk.internal.platform * @build MetricsMemoryTester @@ -58,10 +59,7 @@ System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java 2026-10-19 12:10:20.000000000 +0000 @@ -29,9 +29,11 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build GetFreeSwapSpaceSize * @run driver TestGetFreeSwapSpaceSize */ + import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; @@ -41,10 +43,8 @@ private static final String imageName = Common.imageName("osbeanSwapSpace"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. - * 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. * @@ -48,17 +48,19 @@ import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; import jdk.test.lib.process.OutputAnalyzer; +import jtreg.SkippedException; public class TestLimitsUpdating { private static final long M = 1024 * 1024; + private static final int CPU_PERIOD = 100_000; + private static final int INITIAL_CPU_COUNT = 1; + private static final int UPDATED_CPU_COUNT = 2; private static final String TARGET_CONTAINER = "limitsUpdatingJDK_" + Runtime.getRuntime().version().major(); private static final String imageName = Common.imageName("limitsUpdatingJDK"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { @@ -69,6 +71,10 @@ } private static void testLimitUpdates() throws Exception { + if (Runtime.getRuntime().availableProcessors() < UPDATED_CPU_COUNT) { + throw new SkippedException("Need at least " + UPDATED_CPU_COUNT + + " available CPUs to test CPU limit updates"); + } File sharedtmpdir = new File("jdk-sharedtmp"); File flag = new File(sharedtmpdir, "limitsUpdated"); // shared with LimitUpdateChecker File started = new File(sharedtmpdir, "started"); // shared with LimitUpdateChecker @@ -78,8 +84,8 @@ DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "LimitUpdateChecker"); opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/"); opts.addDockerOpts("--volume", sharedtmpdir.getAbsolutePath() + ":/tmp"); - opts.addDockerOpts("--cpu-period", "100000"); - opts.addDockerOpts("--cpu-quota", "200000"); + opts.addDockerOpts("--cpu-period", Integer.toString(CPU_PERIOD)); + opts.addDockerOpts("--cpu-quota", Integer.toString(INITIAL_CPU_COUNT * CPU_PERIOD)); opts.addDockerOpts("--memory", "500m"); opts.addDockerOpts("--memory-swap", "500m"); opts.addDockerOpts("--name", TARGET_CONTAINER); @@ -108,7 +114,7 @@ Thread.sleep(100); } - final List containerCommand = getContainerUpdate(300_000, 100_000, "300m"); + final List containerCommand = getContainerUpdate(UPDATED_CPU_COUNT * CPU_PERIOD, CPU_PERIOD, "300m"); // Run the update command so as to increase resources once the container signaled it has started. Thread t2 = new Thread() { public void run() { @@ -131,10 +137,10 @@ // Do assertions based on the output in target container OutputAnalyzer targetOut = out[0]; - targetOut.shouldContain("Runtime.availableProcessors: 2"); // initial value - targetOut.shouldContain("OperatingSystemMXBean.getAvailableProcessors: 2"); // initial value - targetOut.shouldContain("Runtime.availableProcessors: 3"); // updated value - targetOut.shouldContain("OperatingSystemMXBean.getAvailableProcessors: 3"); // updated value + targetOut.shouldContain("Runtime.availableProcessors: 1"); // initial value + targetOut.shouldContain("OperatingSystemMXBean.getAvailableProcessors: 1"); // initial value + targetOut.shouldContain("Runtime.availableProcessors: 2"); // updated value + targetOut.shouldContain("OperatingSystemMXBean.getAvailableProcessors: 2"); // updated value long memoryInBytes = 500 * M; targetOut.shouldContain("Metrics.getMemoryLimit() == " + memoryInBytes); // initial value targetOut.shouldContain("OperatingSystemMXBean.getTotalMemorySize: " + memoryInBytes); // initial value diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java 2026-10-19 12:10:20.000000000 +0000 @@ -30,6 +30,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build TestPidsLimit * @run driver TestPidsLimit */ @@ -49,10 +50,8 @@ private static final int UNLIMITED_PIDS_DOCKER = -1; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java 2026-10-19 12:10:20.000000000 +0000 @@ -42,10 +42,7 @@ private static final String imageName = Common.imageName("metrics"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java 2026-10-19 12:10:20.000000000 +0000 @@ -42,10 +42,7 @@ private static final String imageName = Common.imageName("useContainerSupport"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java openjdk-25-25.0.5+8/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java 2026-10-19 12:10:20.000000000 +0000 @@ -41,7 +41,6 @@ * @test * @requires vm.flagless * @requires vm.hasJFR & vm.gc.Z - * @requires vm.flagless * @library /test/lib /test/jdk * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/jfr/event/os/TestCPULoad.java openjdk-25-25.0.5+8/test/jdk/jdk/jfr/event/os/TestCPULoad.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/jfr/event/os/TestCPULoad.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/jfr/event/os/TestCPULoad.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/jfr/event/runtime/TestFlush.java openjdk-25-25.0.5+8/test/jdk/jdk/jfr/event/runtime/TestFlush.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/jfr/event/runtime/TestFlush.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/jfr/event/runtime/TestFlush.java 2026-10-19 12:10:20.000000000 +0000 @@ -143,8 +143,6 @@ printFlushEvent(re); Asserts.assertTrue(re.getEventType().getName().contains("Flush"), "invalid Event type"); Asserts.assertGT((long) re.getValue("flushId"), 0L, "Invalid flush ID"); - Asserts.assertGT((long) re.getValue("elements"), 0L, "No elements"); - Asserts.assertGT((long) re.getValue("size"), 0L, "Empty size"); } private static void acknowledgeFlushEvent() { diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/modules/etc/JmodExcludedFiles.java openjdk-25-25.0.5+8/test/jdk/jdk/modules/etc/JmodExcludedFiles.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/modules/etc/JmodExcludedFiles.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/modules/etc/JmodExcludedFiles.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,12 @@ * @test * @bug 8159927 * @modules java.base/jdk.internal.util + * @library /test/lib * @requires jlink.packagedModules - * @run main JmodExcludedFiles - * @summary Test that JDK JMOD files do not include native debug symbols + * @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 JmodExcludedFiles + * @summary Test that JDK JMOD files do not include native debug symbols when it is not configured */ import java.nio.file.DirectoryStream; @@ -37,9 +40,11 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import jdk.internal.util.OperatingSystem; +import jdk.test.whitebox.WhiteBox; public class JmodExcludedFiles { private static String javaHome = System.getProperty("java.home"); + private static final boolean expectSymbols = WhiteBox.getWhiteBox().shipsDebugInfo(); public static void main(String[] args) throws Exception { Path jmods = Path.of(javaHome, "jmods"); @@ -76,24 +81,19 @@ if (i != -1) { if (n.substring(0, i).endsWith(".dSYM")) { System.err.println("Found symbols in " + jmod + ": " + name); - return true; + return expectSymbols ? false: true; } } } if (OperatingSystem.isWindows() && name.endsWith(".pdb")) { - // on Windows we check if we should have public symbols through --with-external-symbols-in-bundles=public (JDK-8237192) - String strippedpdb = javaHome + "/bin/" + name.substring(index + 1, name.length() - 4) + ".stripped.pdb"; - if (!Files.exists(Paths.get(strippedpdb))) { - System.err.println("Found symbols in " + jmod + ": " + name + - ". No stripped pdb file " + strippedpdb + " exists."); - return true; - } + System.err.println("Found symbols in " + jmod + ": " + name); + return expectSymbols ? false: true; } if (name.endsWith(".diz") || name.endsWith(".debuginfo") || name.endsWith(".map")) { System.err.println("Found symbols in " + jmod + ": " + name); - return true; + return expectSymbols ? false: true; } } return false; diff -Nru openjdk-25-25.0.4.1+1/test/jdk/jdk/nio/zipfs/EndOfCenValidation.java openjdk-25-25.0.5+8/test/jdk/jdk/nio/zipfs/EndOfCenValidation.java --- openjdk-25-25.0.4.1+1/test/jdk/jdk/nio/zipfs/EndOfCenValidation.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/jdk/nio/zipfs/EndOfCenValidation.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,150 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @modules java.base/jdk.internal.util + * @summary Verify that ZipFileSystem rejects files with CEN sizes exceeding the implementation limit + * @library /test/lib + * @build jdk.test.lib.util.ZipUtils + * @run junit/othervm EndOfCenValidation + */ + +import jdk.internal.util.ArraysSupport; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.zip.ZipException; + +import static jdk.test.lib.util.ZipUtils.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * This test augments {@link TestTooManyEntries}. It creates sparse ZIPs where + * the CEN size is inflated to the desired value. This helps this test run + * fast with much less resources. + * + * While the CEN in these files are zero-filled and the produced ZIPs are technically + * invalid, the CEN is never actually read by ZipFileSystem since it does + * 'End of central directory record' (END header) validation before reading the CEN. + */ +public class EndOfCenValidation { + + // Zip files produced by this test + static final Path CEN_TOO_LARGE_ZIP = Path.of("cen-size-too-large.zip"); + static final Path INVALID_CEN_SIZE = Path.of("invalid-zen-size.zip"); + static final Path BAD_CEN_OFFSET_ZIP = Path.of("bad-cen-offset.zip"); + static final Path BAD_ENTRY_COUNT_ZIP = Path.of("bad-entry-count.zip"); + + // Maximum allowed CEN size allowed by ZipFileSystem + static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; + + /** + * Delete big files after test, in case the file system did not support sparse files. + * @throws IOException if an error occurs + */ + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(CEN_TOO_LARGE_ZIP); + Files.deleteIfExists(INVALID_CEN_SIZE); + Files.deleteIfExists(BAD_CEN_OFFSET_ZIP); + Files.deleteIfExists(BAD_ENTRY_COUNT_ZIP); + } + + /** + * Validates that an 'End of central directory record' (END header) with a CEN + * length exceeding {@link #MAX_CEN_SIZE} limit is rejected + * @throws IOException if an error occurs + */ + @Test + public void shouldRejectTooLargeCenSize() throws IOException { + int size = MAX_CEN_SIZE + 1; + Path zip = zipWithModifiedEndRecord(size, true, 0, CEN_TOO_LARGE_ZIP); + verifyRejection(zip, INVALID_CEN_SIZE_TOO_LARGE); + } + + /** + * Validate that an 'End of central directory record' (END header) + * where the value of the CEN size field exceeds the position of + * the END header is rejected. + * @throws IOException if an error occurs + */ + @Test + public void shouldRejectInvalidCenSize() throws IOException { + int size = MAX_CEN_SIZE; + Path zip = zipWithModifiedEndRecord(size, false, 0, INVALID_CEN_SIZE); + verifyRejection(zip, INVALID_CEN_BAD_SIZE); + } + + /** + * Validate that an 'End of central directory record' (the END header) + * where the value of the CEN offset field is larger than the position + * of the END header minus the CEN size is rejected + * @throws IOException if an error occurs + */ + @Test + public void shouldRejectInvalidCenOffset() throws IOException { + int size = MAX_CEN_SIZE; + Path zip = zipWithModifiedEndRecord(size, true, 100, BAD_CEN_OFFSET_ZIP); + verifyRejection(zip, INVALID_CEN_BAD_OFFSET); + } + + /** + * Validate that a 'Zip64 End of Central Directory' record (the END header) + * where the value of the 'total entries' field is larger than what fits + * in the CEN size is rejected. + * + * @throws IOException if an error occurs + */ + @ParameterizedTest + @ValueSource(longs = { + -1, // Negative + Long.MIN_VALUE, // Very negative + 0x3B / 3L - 1, // Cannot fit in test ZIP's CEN + MAX_CEN_SIZE / 3 + 1, // Too large to allocate int[] entries array + Long.MAX_VALUE // Unreasonably large + }) + public void shouldRejectBadTotalEntries(long totalEntries) throws IOException { + Path zip = zip64WithModifiedTotalEntries(BAD_ENTRY_COUNT_ZIP, totalEntries); + verifyRejection(zip, INVALID_BAD_ENTRY_COUNT); + } + + /** + * Verify that ZipFileSystem.newFileSystem rejects the ZIP file with a ZipException + * with the given message + * @param zip ZIP file to open + * @param msg exception message to expect + */ + private static void verifyRejection(Path zip, String msg) { + ZipException ex = assertThrows(ZipException.class, () -> { + FileSystems.newFileSystem(zip); + }); + assertEquals(msg, ex.getMessage()); + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java openjdk-25-25.0.5+8/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java --- openjdk-25-25.0.4.1+1/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java 2026-10-19 12:10:20.000000000 +0000 @@ -290,9 +290,8 @@ * @summary Interoperability tests with Microsoft TLS root CAs * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop microsoftrsa2017 OCSP - * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop microsoftrsa2017 OCSP - * @run main/othervm/manual -Djava.security.debug=certpath CAInterop microsoftrsa2017 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop microsoftrsa2017 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop microsoftrsa2017 DEFAULT */ /* @@ -607,8 +606,8 @@ new CATestURLs("https://valid.business.ca22.ssl.buypass.no", "https://revoked.business.ca22.ssl.buypass.no"); case "buypassclass3ca" -> - new CATestURLs("https://valid.qcevident.ca23.ssl.buypass.no", - "https://revoked.qcevident.ca23.ssl.buypass.no"); + new CATestURLs("https://valid.evident.ca23.ssl.buypass.no", + "https://revoked.evident.ca23.ssl.buypass.no"); case "comodorsaca" -> new CATestURLs("https://comodorsacertificationauthority-ev.comodoca.com", diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java openjdk-25-25.0.5+8/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -34,7 +34,7 @@ /** * @test - * @bug 8378201 + * @bug 8378201 8378506 * @key headful * @summary Verifies that window content survives a GL context switch to another * window and back diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java openjdk-25-25.0.5+8/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java 2026-10-19 12:10:20.000000000 +0000 @@ -147,8 +147,17 @@ } 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() + ")"); @@ -176,40 +185,39 @@ } } - 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; } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/net/www/protocol/http/NTLMFailTest.java openjdk-25-25.0.5+8/test/jdk/sun/net/www/protocol/http/NTLMFailTest.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/net/www/protocol/http/NTLMFailTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/net/www/protocol/http/NTLMFailTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8372731 + * @library /test/lib + * @run main/othervm NTLMFailTest + * @run main/othervm -Djdk.includeInExceptions= NTLMFailTest + * @summary check that the Authentication failure exception + * honors the jdk.includeInExceptions setting + */ + +import jdk.test.lib.net.HttpHeaderParser; +import jdk.test.lib.net.URIBuilder; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Authenticator; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.PasswordAuthentication; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; + +public class NTLMFailTest { + + static final int BODY_LEN = 8192; + + static final String RESP_SERVER_AUTH = + "HTTP/1.1 401 Unauthorized\r\n" + + "WWW-Authenticate: NTLM\r\n" + + "Connection: close\r\n" + + "Content-Length: " + BODY_LEN + "\r\n" + + "\r\n"; + + static final String RESP_SERVER_NTLM = + "HTTP/1.1 401 Unauthorized\r\n" + + "WWW-Authenticate: NTLM InvalidChallenge\r\n" + + "Connection: Keep-Alive\r\n" + + "Content-Length: " + BODY_LEN + "\r\n" + + "\r\n"; + + public static void main(String[] args) throws Exception { + Authenticator.setDefault(new TestAuthenticator()); + try (NTLMServer server = startServer(new ServerSocket(0, 0, InetAddress.getLoopbackAddress()))) { + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getLocalPort()) + .path("/") + .toURLUnchecked(); + HttpURLConnection uc = (HttpURLConnection) url.openConnection(); + uc.setRequestMethod("HEAD"); + uc.getInputStream().readAllBytes(); + throw new RuntimeException("Expected exception was not thrown"); + } catch (IOException e) { + if (e.getMessage().contains("Authentication failure")) { + System.err.println("Got expected exception:"); + e.printStackTrace(); + if (System.getProperty("jdk.includeInExceptions") == null) { + // detailed message enabled by default + if (e.getCause() == null) { + throw new RuntimeException("Expected a detailed exception", e); + } + // no checks on the detailed message; it's platform-specific and may be translated + } else { + // detailed message disabled + if (e.getCause() != null) { + throw new RuntimeException("Unexpected detailed exception", e); + } + } + } else { + throw e; + } + } + } + + static class NTLMServer extends Thread implements AutoCloseable { + final ServerSocket ss; + volatile boolean closed; + + NTLMServer(ServerSocket serverSS) { + super(); + setDaemon(true); + this.ss = serverSS; + } + + int getLocalPort() { return ss.getLocalPort(); } + + @Override + public void run() { + boolean doing2ndStageNTLM = false; + while (!closed) { + try { + Socket s = ss.accept(); + InputStream is = s.getInputStream(); + OutputStream os = s.getOutputStream(); + doServer(is, os, doing2ndStageNTLM); + if (!doing2ndStageNTLM) { + doing2ndStageNTLM = true; + } else { + os.close(); + } + } catch (IOException ioe) { + if (!closed) { + ioe.printStackTrace(); + } + } + } + } + + @Override + public void close() { + if (closed) return; + synchronized(this) { + if (closed) return; + closed = true; + } + try { ss.close(); } catch (IOException x) { }; + } + } + + static NTLMServer startServer(ServerSocket serverSS) { + NTLMServer server = new NTLMServer(serverSS); + server.start(); + return server; + } + + static void doServer(InputStream is, OutputStream os, boolean doing2ndStageNTLM) throws IOException { + if (!doing2ndStageNTLM) { + new HttpHeaderParser(is); + os.write(RESP_SERVER_AUTH.getBytes("ASCII")); + } else { + new HttpHeaderParser(is); + os.write(RESP_SERVER_NTLM.getBytes("ASCII")); + } + } + + static class TestAuthenticator extends Authenticator { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication("test", "secret".toCharArray()); + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java openjdk-25-25.0.5+8/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java 2026-10-19 12:10:20.000000000 +0000 @@ -28,7 +28,7 @@ * 8223499 8225392 8232019 8234245 8233223 8225068 8225069 8243321 8243320 * 8243559 8225072 8258630 8259312 8256421 8225081 8225082 8225083 8245654 * 8305975 8304760 8307134 8295894 8314960 8317373 8317374 8318759 8319187 - * 8321408 8316138 8341057 8303770 8350498 8359170 8361212 8372351 + * 8321408 8316138 8341057 8303770 8350498 8359170 8361212 8372351 8387123 * @summary Check root CA entries in cacerts file */ import java.io.ByteArrayInputStream; @@ -47,12 +47,12 @@ + File.separator + "security" + File.separator + "cacerts"; // The numbers of certs now. - private static final int COUNT = 111; + private static final int COUNT = 110; // SHA-256 of cacerts, can be generated with // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 private static final String CHECKSUM - = "26:75:A0:AA:6E:7C:15:8B:BC:CF:11:81:38:3E:E7:94:31:9E:36:2D:F9:A6:BC:88:E1:A5:F8:46:9A:4C:1D:D7"; + = "AA:C2:64:41:28:06:1F:83:92:54:7C:DD:95:82:61:4C:8F:FA:09:7B:17:64:A7:A8:7C:A9:F6:27:25:95:2D:BB"; // Hex formatter to upper case with ":" delimiter private static final HexFormat HEX = HexFormat.ofDelimiter(":").withUpperCase(); @@ -143,8 +143,6 @@ "96:BC:EC:06:26:49:76:F3:74:60:77:9A:CF:28:C5:A7:CF:E8:A3:C0:AA:E1:1A:8F:FC:EE:05:C0:BD:DF:08:C6"); put("letsencryptisrgx2 [jdk]", "69:72:9B:8E:15:A8:6E:FC:17:7A:57:AF:B7:17:1D:FC:64:AD:D2:8C:2F:CA:8C:F1:50:7E:34:45:3C:CB:14:70"); - put("luxtrustglobalrootca [jdk]", - "A1:B2:DB:EB:64:E7:06:C6:16:9E:3C:41:18:B2:3B:AA:09:01:8A:84:27:66:6D:8B:F0:E2:88:91:EC:05:19:50"); put("quovadisrootca [jdk]", "A4:5E:DE:3B:BB:F0:9C:8A:E1:5C:72:EF:C0:72:68:D6:93:A2:1C:99:6F:D5:1E:67:CA:07:94:60:FD:6D:88:73"); put("quovadisrootca1g3 [jdk]", @@ -296,8 +294,6 @@ add("addtrustexternalca [jdk]"); // Valid until: Sat May 30 10:44:50 GMT 2020 add("addtrustqualifiedca [jdk]"); - // Valid until: Wed Mar 17 02:51:37 PDT 2021 - add("luxtrustglobalrootca [jdk]"); // Valid until: Wed Mar 17 11:33:33 PDT 2021 add("quovadisrootca [jdk]"); // Valid until: Sat May 21 04:00:00 GMT 2022 diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,17 @@ * questions. */ +/* + * @test + * @bug 8240256 8269034 + * @summary + * @library /test/lib/ /sun/security/pkcs11/ + * @modules jdk.crypto.cryptoki/sun.security.pkcs11 + * @run main/othervm + * -DCUSTOM_P11_CONFIG=${test.src}/MultipleLogins-nss.txt + * -DCUSTOM_DB_DIR=./nss/db + * MultipleLogins + */ import sun.security.pkcs11.SunPKCS11; @@ -30,6 +41,7 @@ import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginException; + import java.io.IOException; import java.lang.ref.WeakReference; import java.security.*; @@ -37,28 +49,30 @@ import jdk.test.lib.util.ForceGC; import jtreg.SkippedException; -public class MultipleLogins { - private static final String KS_TYPE = "PKCS11"; +public class MultipleLogins extends PKCS11Test { private static final int NUM_PROVIDERS = 20; private static final SunPKCS11[] providers = new SunPKCS11[NUM_PROVIDERS]; public static void main(String[] args) throws Exception { - String nssConfig = null; - try { - nssConfig = PKCS11Test.getNssConfig(); - } catch (SkippedException exc) { - System.out.println("Skipping test: " + exc.getMessage()); - } + // This bypasses the PKCS11Test settings and run the mandatory + // main method directly. This is needed to keep the custom logic of the test + new MultipleLogins().main((Provider)null); + } + + @Override + public void main(Provider p) throws Exception { + copyNssCertKeyToClassesDir(); + + String nssConfig = getNssConfig(); if (nssConfig == null) { // No test framework support yet. Ignore - System.out.println("No NSS config found. Skipping."); - return; + throw new SkippedException("No NSS config found. Skipping."); } - for (int i =0; i < NUM_PROVIDERS; i++) { + for (int i = 0; i < NUM_PROVIDERS; i++) { // loop to set up test without security manger - providers[i] = (SunPKCS11)PKCS11Test.newPKCS11Provider(); + providers[i] = (SunPKCS11)newPKCS11Provider(); } for (int i =0; i < NUM_PROVIDERS; i++) { @@ -68,7 +82,7 @@ } WeakReference[] weakRef = new WeakReference[NUM_PROVIDERS]; - for (int i =0; i < NUM_PROVIDERS; i++) { + for (int i = 0; i < NUM_PROVIDERS; i++) { weakRef[i] = new WeakReference<>(providers[i]); providers[i].logout(); @@ -95,7 +109,7 @@ } private static void test(SunPKCS11 p) throws Exception { - KeyStore ks = KeyStore.getInstance(KS_TYPE, p); + KeyStore ks = KeyStore.getInstance(PKCS11, p); p.setCallbackHandler(new PasswordCallbackHandler()); try { ks.load(null, (char[]) null); @@ -111,23 +125,23 @@ try { ks.load(null, (char[]) null); } catch (IOException e) { - if (e.getCause() instanceof LoginException && - e.getCause().getMessage().contains("No token present")) { - // expected - } else { + if (!(e.getCause() instanceof LoginException) || + !(e.getCause().getMessage().contains("No token present"))) { + throw new RuntimeException("Token was present", e); - } + } // else expected } } public static class PasswordCallbackHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - if (!(callbacks[0] instanceof PasswordCallback)) { + if (callbacks[0] instanceof PasswordCallback pc) { + pc.setPassword(null); + } else { throw new UnsupportedCallbackException(callbacks[0]); } - PasswordCallback pc = (PasswordCallback)callbacks[0]; - pc.setPassword(null); + } } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,139 +0,0 @@ -# -# Copyright (c) 2021, 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 8240256 8269034 -# @summary -# @library /test/lib/ -# @build jdk.test.lib.util.ForceGC -# jdk.test.lib.Platform -# jdk.test.lib.Utils -# @run shell MultipleLogins.sh - -# set a few environment variables so that the shell-script can run stand-alone -# in the source directory - -# if running by hand on windows, change TESTSRC and TESTCLASSES to "." -if [ "${TESTSRC}" = "" ] ; then - TESTSRC=`pwd` -fi -if [ "${TESTCLASSES}" = "" ] ; then - TESTCLASSES=`pwd` -fi - -if [ "${TESTCLASSPATH}" = "" ] ; then - TESTCLASSPATH=`pwd` -fi - -if [ "${COMPILEJAVA}" = "" ]; then - COMPILEJAVA="${TESTJAVA}" -fi -echo TESTSRC=${TESTSRC} -echo TESTCLASSES=${TESTCLASSES} -echo TESTJAVA=${TESTJAVA} -echo COMPILEJAVA=${COMPILEJAVA} -echo "" - -# let java test exit if platform unsupported - -OS=`uname -s` -case "$OS" in - Linux ) - FS="/" - PS=":" - CP="${FS}bin${FS}cp" - CHMOD="${FS}bin${FS}chmod" - ;; - Darwin ) - FS="/" - PS=":" - CP="${FS}bin${FS}cp" - CHMOD="${FS}bin${FS}chmod" - ;; - AIX ) - FS="/" - PS=":" - CP="${FS}bin${FS}cp" - CHMOD="${FS}bin${FS}chmod" - ;; - Windows* ) - FS="\\" - PS=";" - CP="cp" - CHMOD="chmod" - ;; - CYGWIN* ) - FS="/" - PS=";" - CP="cp" - CHMOD="chmod" - # - # javac does not like /cygdrive produced by `pwd` - # - TESTSRC=`cygpath -d ${TESTSRC}` - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac - -# first make cert/key DBs writable - -${CP} ${TESTSRC}${FS}..${FS}nss${FS}db${FS}cert9.db ${TESTCLASSES} -${CHMOD} +w ${TESTCLASSES}${FS}cert9.db - -${CP} ${TESTSRC}${FS}..${FS}nss${FS}db${FS}key4.db ${TESTCLASSES} -${CHMOD} +w ${TESTCLASSES}${FS}key4.db - -${CP} ${TESTSRC}${FS}..${FS}nss${FS}db${FS}cert8.db ${TESTCLASSES} -${CHMOD} +w ${TESTCLASSES}${FS}cert8.db - -${CP} ${TESTSRC}${FS}..${FS}nss${FS}db${FS}key3.db ${TESTCLASSES} -${CHMOD} +w ${TESTCLASSES}${FS}key3.db - -# compile test -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ - -classpath ${TESTCLASSPATH} \ - -d ${TESTCLASSES} \ - --add-modules jdk.crypto.cryptoki \ - --add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED \ - ${TESTSRC}${FS}..${FS}..${FS}..${FS}..${FS}..${FS}lib${FS}jdk${FS}test${FS}lib${FS}artifacts${FS}*.java \ - ${TESTSRC}${FS}..${FS}..${FS}..${FS}..${FS}..${FS}lib${FS}jtreg${FS}*.java \ - ${TESTSRC}${FS}MultipleLogins.java \ - ${TESTSRC}${FS}..${FS}PKCS11Test.java - -TEST_ARGS="${TESTVMOPTS} ${TESTJAVAOPTS} -classpath ${TESTCLASSPATH} \ - --add-modules jdk.crypto.cryptoki \ - --add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED \ - -DCUSTOM_DB_DIR=${TESTCLASSES} \ - -DCUSTOM_P11_CONFIG=${TESTSRC}${FS}MultipleLogins-nss.txt \ - -Dtest.src=${TESTSRC} \ - -Dtest.classes=${TESTCLASSES} \ - -Djava.security.debug=${DEBUG}" - -# run test without security manager -${TESTJAVA}${FS}bin${FS}java ${TEST_ARGS} MultipleLogins || exit 10 - -echo Done -exit 0 diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8014618 + * @bug 8014618 8368694 * @summary Need to strip leading zeros in TlsPremasterSecret of DHKeyAgreement * @library /test/lib .. * @author Pasi Eronen @@ -87,6 +87,26 @@ throw new Exception("First byte is not zero as expected"); } + // generate generic shared secret + aliceKeyAgree.init(alicePrivKey); + aliceKeyAgree.doPhase(bobPubKey, true); + byte[] genericSecret = + aliceKeyAgree.generateSecret("Generic").getEncoded(); + System.out.println("generic secret:\n" + HEX.formatHex(genericSecret)); + + // verify that leading zero is present + if (genericSecret.length != 128) { + throw new Exception("Unexpected generic secret length"); + } + if (genericSecret[0] != 0) { + throw new Exception("First byte is not zero as expected"); + } + for (int i = 0; i < genericSecret.length; i++) { + if (genericSecret[i] != sharedSecret[i]) { + throw new Exception("Shared secrets differ"); + } + } + // now, test TLS premaster secret aliceKeyAgree.init(alicePrivKey); aliceKeyAgree.doPhase(bobPubKey, true); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8029661 8325164 8368073 8368514 8368520 + * @summary Test TLS 1.2 and TLS 1.3 + * @modules java.base/sun.security.internal.spec + * java.base/sun.security.util + * java.base/com.sun.crypto.provider + * @library /test/lib ../.. + * @run main/othervm/timeout=120 -Djdk.tls.client.protocols=TLSv1.2 + * -Djdk.tls.useExtendedMasterSecret=false + * -Djdk.tls.client.enableSessionTicketExtension=false FipsModeTLS + * @comment SunPKCS11 does not support (TLS1.2) SunTlsExtendedMasterSecret yet. + * Stateless resumption doesn't currently work with NSS-FIPS, see JDK-8368669. + * NSS-FIPS does not support ML-KEM, so configures the list of named groups. + * @run main/othervm/timeout=120 + * -Djdk.tls.client.protocols=TLSv1.3 + * -Djdk.tls.namedGroups=x25519,secp256r1,secp384r1,secp521r1,x448,ffdhe2048,ffdhe3072,ffdhe4096,ffdhe6144,ffdhe8192 + * FipsModeTLS + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.ByteBuffer; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import javax.crypto.Cipher; +import javax.crypto.KDF; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManagerFactory; + +import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; +import sun.security.internal.spec.TlsMasterSecretParameterSpec; +import sun.security.internal.spec.TlsPrfParameterSpec; +import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; + +public final class FipsModeTLS extends SecmodTest { + + private static final boolean enableDebug = true; + + private static Provider sunPKCS11NSSProvider; + private static Provider sunJCEProvider; + private static KeyStore ks; + private static KeyStore ts; + private static char[] passphrase = "JAHshj131@@".toCharArray(); + private static PrivateKey privateKey; + private static PublicKey publicKey; + + public static void main(String[] args) throws Exception { + // reduce the limit to trigger a key update later + Security.setProperty("jdk.tls.keyLimits", + "AES/GCM/NoPadding KeyUpdate 10000"); + try { + initialize(); + } catch (Exception e) { + if (enableDebug) { + System.out.println(e); + } + throw new SkippedException("Test skipped: failure during" + + " initialization"); + } + + if (shouldRun()) { + // Test against JCE + testTlsAuthenticationCodeGeneration(); + + // Self-integrity test (complete TLS communication) + testTLSSunPKCS11Communication.initSslContext(); + testTLSSunPKCS11Communication.run(); + + System.out.println("Test PASS - OK"); + } else { + throw new SkippedException("Test skipped: TLS 1.2 mechanisms" + + " not supported by current SunPKCS11 back-end"); + } + } + + private static boolean shouldRun() { + if (sunPKCS11NSSProvider == null) { + return false; + } + try { + String proto = System.getProperty("jdk.tls.client.protocols"); + if ("TLSv1.3".equals(proto)) { + KDF.getInstance("HKDF-SHA256", sunPKCS11NSSProvider); + } else { + KeyGenerator.getInstance("SunTls12MasterSecret", + sunPKCS11NSSProvider); + KeyGenerator.getInstance( + "SunTls12RsaPremasterSecret", sunPKCS11NSSProvider); + KeyGenerator.getInstance("SunTls12Prf", sunPKCS11NSSProvider); + } + } catch (NoSuchAlgorithmException e) { + return false; + } + return true; + } + + private static void testTlsAuthenticationCodeGeneration() + throws Exception { + // Generate RSA Pre-Master Secret in SunPKCS11 provider + SecretKey rsaPreMasterSecret = null; + @SuppressWarnings("deprecation") + TlsRsaPremasterSecretParameterSpec rsaPreMasterSecretSpec = + new TlsRsaPremasterSecretParameterSpec(0x0303, 0x0303); + { + KeyGenerator rsaPreMasterSecretKG = KeyGenerator.getInstance( + "SunTls12RsaPremasterSecret", sunPKCS11NSSProvider); + rsaPreMasterSecretKG.init(rsaPreMasterSecretSpec, null); + rsaPreMasterSecret = rsaPreMasterSecretKG.generateKey(); + } + + // Get RSA Pre-Master Secret in plain (from SunPKCS11 provider) + byte[] rsaPlainPreMasterSecret = null; + { + Cipher rsaPreMasterSecretWrapperCipher = + Cipher.getInstance("RSA/ECB/PKCS1Padding", + sunPKCS11NSSProvider); + rsaPreMasterSecretWrapperCipher.init(Cipher.WRAP_MODE, publicKey, + new SecureRandom()); + byte[] rsaEncryptedPreMasterSecret = + rsaPreMasterSecretWrapperCipher.wrap(rsaPreMasterSecret); + Cipher rsaPreMasterSecretUnwrapperCipher = + Cipher.getInstance("RSA/ECB/PKCS1Padding", sunJCEProvider); + rsaPreMasterSecretUnwrapperCipher.init(Cipher.UNWRAP_MODE, + privateKey, rsaPreMasterSecretSpec); + rsaPlainPreMasterSecret = rsaPreMasterSecretUnwrapperCipher.unwrap( + rsaEncryptedPreMasterSecret, "TlsRsaPremasterSecret", + Cipher.SECRET_KEY).getEncoded(); + + if (enableDebug) { + System.out.println("rsaPlainPreMasterSecret:"); + for (byte b : rsaPlainPreMasterSecret) { + System.out.printf("%02X, ", b); + } + System.out.println(""); + } + } + + // Generate Master Secret + SecretKey sunPKCS11MasterSecret = null; + SecretKey jceMasterSecret = null; + { + KeyGenerator sunPKCS11MasterSecretGenerator = + KeyGenerator.getInstance("SunTls12MasterSecret", + sunPKCS11NSSProvider); + KeyGenerator jceMasterSecretGenerator = KeyGenerator.getInstance( + "SunTls12MasterSecret", sunJCEProvider); + @SuppressWarnings("deprecation") + TlsMasterSecretParameterSpec sunPKCS11MasterSecretSpec = + new TlsMasterSecretParameterSpec(rsaPreMasterSecret, 3, 3, + new byte[32], new byte[32], "SHA-256", 32, 64); + @SuppressWarnings("deprecation") + TlsMasterSecretParameterSpec jceMasterSecretSpec = + new TlsMasterSecretParameterSpec( + new SecretKeySpec(rsaPlainPreMasterSecret, + "Generic"), 3, 3, new byte[32], + new byte[32], "SHA-256", 32, 64); + sunPKCS11MasterSecretGenerator.init(sunPKCS11MasterSecretSpec, + null); + jceMasterSecretGenerator.init(jceMasterSecretSpec, null); + sunPKCS11MasterSecret = + sunPKCS11MasterSecretGenerator.generateKey(); + jceMasterSecret = jceMasterSecretGenerator.generateKey(); + if (enableDebug) { + System.out.println("Master Secret (SunJCE):"); + if (jceMasterSecret != null) { + for (byte b : jceMasterSecret.getEncoded()) { + System.out.printf("%02X, ", b); + } + System.out.println(""); + } + } + } + + // Generate authentication codes + byte[] sunPKCS11AuthenticationCode = null; + byte[] jceAuthenticationCode = null; + { + // Generate SunPKCS11 authentication code + { + @SuppressWarnings("deprecation") + TlsPrfParameterSpec sunPKCS11AuthenticationCodeSpec = + new TlsPrfParameterSpec(sunPKCS11MasterSecret, + "client finished", "a".getBytes(), 12, + "SHA-256", 32, 64); + KeyGenerator sunPKCS11AuthCodeGenerator = + KeyGenerator.getInstance("SunTls12Prf", + sunPKCS11NSSProvider); + sunPKCS11AuthCodeGenerator.init( + sunPKCS11AuthenticationCodeSpec); + sunPKCS11AuthenticationCode = + sunPKCS11AuthCodeGenerator.generateKey().getEncoded(); + } + + // Generate SunJCE authentication code + { + @SuppressWarnings("deprecation") + TlsPrfParameterSpec jceAuthenticationCodeSpec = + new TlsPrfParameterSpec(jceMasterSecret, + "client finished", "a".getBytes(), 12, + "SHA-256", 32, 64); + KeyGenerator jceAuthCodeGenerator = + KeyGenerator.getInstance("SunTls12Prf", + sunJCEProvider); + jceAuthCodeGenerator.init(jceAuthenticationCodeSpec); + jceAuthenticationCode = + jceAuthCodeGenerator.generateKey().getEncoded(); + } + + if (enableDebug) { + System.out.println("SunPKCS11 Authentication Code: "); + for (byte b : sunPKCS11AuthenticationCode) { + System.out.printf("%02X, ", b); + } + System.out.println(""); + System.out.println("SunJCE Authentication Code: "); + for (byte b : jceAuthenticationCode) { + System.out.printf("%02X, ", b); + } + System.out.println(""); + } + } + + if (sunPKCS11AuthenticationCode == null || + jceAuthenticationCode == null || + sunPKCS11AuthenticationCode.length == 0 || + jceAuthenticationCode.length == 0 || + !Arrays.equals(sunPKCS11AuthenticationCode, + jceAuthenticationCode)) { + throw new Exception("Authentication codes from JCE" + + " and SunPKCS11 differ."); + } + } + + private static class testTLSSunPKCS11Communication { + public static void run() throws Exception { + SSLEngine[][] enginesToTest = getSSLEnginesToTest(); + boolean firstSession = true; + for (SSLEngine[] engineToTest : enginesToTest) { + + SSLEngine clientSSLEngine = engineToTest[0]; + SSLEngine serverSSLEngine = engineToTest[1]; + // The first connection needs to do a full handshake. + // Verify that subsequent handshakes use resumption. + clientSSLEngine.setEnableSessionCreation(firstSession); + firstSession = false; + // SSLEngine code based on RedhandshakeFinished.java + + boolean dataDone = false; + + ByteBuffer clientOut = null; + ByteBuffer clientIn = null; + ByteBuffer serverOut = null; + ByteBuffer serverIn = null; + ByteBuffer cTOs; + ByteBuffer sTOc; + + SSLSession session = clientSSLEngine.getSession(); + int appBufferMax = session.getApplicationBufferSize(); + int netBufferMax = session.getPacketBufferSize(); + + clientIn = ByteBuffer.allocate(appBufferMax + 50); + serverIn = ByteBuffer.allocate(appBufferMax + 50); + + cTOs = ByteBuffer.allocateDirect(netBufferMax); + sTOc = ByteBuffer.allocateDirect(netBufferMax); + + // big enough to trigger a key update + clientOut = ByteBuffer.wrap( + "a".repeat(16000).getBytes()); + serverOut = ByteBuffer.wrap( + "b".repeat(16000).getBytes()); + + SSLEngineResult clientResult; + SSLEngineResult serverResult; + + while (!dataDone) { + clientResult = clientSSLEngine.wrap(clientOut, cTOs); + runDelegatedTasks(clientResult, clientSSLEngine); + serverResult = serverSSLEngine.wrap(serverOut, sTOc); + runDelegatedTasks(serverResult, serverSSLEngine); + cTOs.flip(); + sTOc.flip(); + + if (enableDebug) { + System.out.println("Client -> Network"); + printTlsNetworkPacket("", cTOs); + System.out.println(""); + System.out.println("Server -> Network"); + printTlsNetworkPacket("", sTOc); + System.out.println(""); + } + + clientResult = clientSSLEngine.unwrap(sTOc, clientIn); + runDelegatedTasks(clientResult, clientSSLEngine); + serverResult = serverSSLEngine.unwrap(cTOs, serverIn); + runDelegatedTasks(serverResult, serverSSLEngine); + + cTOs.compact(); + sTOc.compact(); + + if (!dataDone && + (clientOut.limit() == serverIn.position()) && + (serverOut.limit() == clientIn.position())) { + checkTransfer(serverOut, clientIn); + checkTransfer(clientOut, serverIn); + dataDone = true; + } + } + } + } + + static void printTlsNetworkPacket(String prefix, ByteBuffer bb) { + ByteBuffer slice = bb.slice(); + byte[] buffer = new byte[slice.remaining()]; + slice.get(buffer); + for (int i = 0; i < buffer.length; i++) { + System.out.printf("%02X, ", (byte)(buffer[i] & (byte)0xFF)); + if (i % 8 == 0 && i % 16 != 0) { + System.out.print(" "); + } + if (i % 16 == 0) { + System.out.println(""); + } + } + System.out.flush(); + } + + private static void checkTransfer(ByteBuffer a, ByteBuffer b) + throws Exception { + a.flip(); + b.flip(); + if (!a.equals(b)) { + throw new Exception("Data didn't transfer cleanly"); + } + a.position(a.limit()); + b.position(b.limit()); + a.limit(a.capacity()); + b.limit(b.capacity()); + } + + private static void runDelegatedTasks(SSLEngineResult result, + SSLEngine engine) throws Exception { + + if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = engine.getDelegatedTask()) != null) { + runnable.run(); + } + HandshakeStatus hsStatus = engine.getHandshakeStatus(); + if (hsStatus == HandshakeStatus.NEED_TASK) { + throw new Exception( + "handshake shouldn't need additional tasks"); + } + } + } + + private static SSLEngine[][] getSSLEnginesToTest() throws Exception { + SSLEngine[][] enginesToTest = new SSLEngine[2][2]; + for (int i = 0; i < enginesToTest.length; i++) { + enginesToTest[i][0] = createSSLEngine(true); + enginesToTest[i][1] = createSSLEngine(false); + } + return enginesToTest; + } + + static private SSLEngine createSSLEngine(boolean client) + throws Exception { + SSLEngine ssle; + ssle = sslCtx.createSSLEngine("localhost", 443); + ssle.setUseClientMode(client); + SSLParameters sslParameters = ssle.getSSLParameters(); + // verify that FFDHE named groups are available + String[] namedGroups = sslParameters.getNamedGroups(); + boolean ffdheAvailable = Arrays.stream(namedGroups) + .anyMatch(ng -> ng.startsWith("ffdhe")); + if (!ffdheAvailable) { + throw new RuntimeException("No FFDHE named groups available"); + } + // verify that ECDHE named groups are available + boolean ecdheAvailable = Arrays.stream(namedGroups) + .anyMatch(ng -> ng.startsWith("secp")); + if (!ecdheAvailable) { + throw new RuntimeException("No ECDHE named groups available"); + } + // remove XDH named groups - not available in PKCS11 + namedGroups = Arrays.stream(namedGroups).filter(s-> !s.startsWith("x")).toArray(String[]::new); + sslParameters.setNamedGroups(namedGroups); + ssle.setSSLParameters(sslParameters); + + return ssle; + } + + private static SSLContext sslCtx; + private static void initSslContext() throws Exception { + KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX", "SunJSSE"); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE"); + tmf.init(ts); + + sslCtx = SSLContext.getInstance("TLS", "SunJSSE"); + sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + } + } + + private static void initialize() throws Exception { + // + // For a successful FIPS-mode TLS connection, the following + // cryptographic providers will be installed: + // + // 1. SunPKCS11 (with an NSS FIPS mode backend) + // 2. SUN (to handle X.509 certificates) + // 3. SunJSSE (for a TLS engine) + + initSecmod(); + String configName = BASE + SEP + "nss.cfg"; + sunPKCS11NSSProvider = getSunPKCS11(configName); + System.out.println("SunPKCS11 provider: " + sunPKCS11NSSProvider); + + List installedProviders = new LinkedList<>(); + for (Provider p : Security.getProviders()){ + installedProviders.add(p); + Security.removeProvider(p.getName()); + } + Security.addProvider(sunPKCS11NSSProvider); + for (Provider p : installedProviders){ + String providerName = p.getName(); + if (providerName.equals("SunJSSE") || providerName.equals("SUN")) { + Security.addProvider(p); + } else if (providerName.equals("SunJCE")) { + sunJCEProvider = p; + } + } + + ks = KeyStore.getInstance("PKCS11", sunPKCS11NSSProvider); + ks.load(null, "test12".toCharArray()); + ts = ks; + + KeyStore ksPlain = readTestKeyStore(); + privateKey = (PrivateKey)ksPlain.getKey("rh_rsa_sha256", + passphrase); + publicKey = (PublicKey)ksPlain.getCertificate( + "rh_rsa_sha256").getPublicKey(); + } + + private static KeyStore readTestKeyStore() throws Exception { + File file = new File(System.getProperty("test.src", "."), "keystore"); + InputStream in = new FileInputStream(file); + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(in, "passphrase".toCharArray()); + in.close(); + return ks; + } +} Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/cert8.db and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/cert8.db differ Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/cert9.db and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/cert9.db differ Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/key3.db and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/key3.db differ Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/key4.db and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/key4.db differ Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/keystore and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/keystore differ diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/nss.cfg openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/nss.cfg --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/nss.cfg 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/nss.cfg 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,27 @@ + +name = NSSKeyStore + +nssSecmodDirectory = ${pkcs11test.nss.db} + +nssLibraryDirectory = ${pkcs11test.nss.libdir} + +nssModule = fips + +# NSS-FIPS needs sensitive=true for key extraction. +# TLS 1.3 needs CKA_SIGN to sign the Finished message. + +attributes(*,CKO_SECRET_KEY,CKK_GENERIC_SECRET) = { + CKA_SIGN = true + CKA_SENSITIVE=true +} + +# NSS needs CKA_NETSCAPE_DB for DSA and DH private keys +# just put an arbitrary value in there to make it happy + +attributes(*,CKO_PRIVATE_KEY,CKK_DSA) = { + CKA_NETSCAPE_DB = 0h00 +} + +attributes(*,CKO_PRIVATE_KEY,CKK_DH) = { + CKA_NETSCAPE_DB = 0h00 +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/pkcs11.txt openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/pkcs11.txt --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/pkcs11.txt 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/pkcs11.txt 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,9 @@ +library= +name=NSS Internal PKCS #11 Module +parameters=configdir='sql:./tmpdb' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription='' +NSS=trustOrder=75 cipherOrder=100 slotParams={0x00000001=[slotFlags=RSA,RC4,RC2,DES,DH,SHA1,MD5,MD2,SSL,TLS,AES,RANDOM askpw=any timeout=30 ] } Flags=internal,critical,FIPS + +library=libnssckbi.so +name=Builtin Roots Module +NSS=trustOrder=100 + Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/fips/secmod.db and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/fips/secmod.db differ diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,486 +0,0 @@ -/* - * Copyright (c) 2019, Red Hat, Inc. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8029661 8325164 - * @summary Test TLS 1.2 - * @modules java.base/sun.security.internal.spec - * java.base/sun.security.util - * java.base/com.sun.crypto.provider - * @library /test/lib ../.. - * @run main/othervm/timeout=120 -Djdk.tls.useExtendedMasterSecret=false FipsModeTLS12 - */ - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.nio.ByteBuffer; - -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.KeyStore; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.security.SecureRandom; -import java.security.Security; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import javax.net.ssl.SSLParameters; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManagerFactory; - -import jdk.test.lib.security.SecurityUtils; -import jtreg.SkippedException; -import sun.security.internal.spec.TlsMasterSecretParameterSpec; -import sun.security.internal.spec.TlsPrfParameterSpec; -import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; - -public final class FipsModeTLS12 extends SecmodTest { - - private static final boolean enableDebug = true; - - private static Provider sunPKCS11NSSProvider; - private static Provider sunJCEProvider; - private static KeyStore ks; - private static KeyStore ts; - private static char[] passphrase = "JAHshj131@@".toCharArray(); - private static PrivateKey privateKey; - private static PublicKey publicKey; - - public static void main(String[] args) throws Exception { - // Re-enable TLS_RSA_* since test depends on it. - SecurityUtils.removeFromDisabledTlsAlgs("TLS_RSA_*"); - - try { - initialize(); - } catch (Exception e) { - if (enableDebug) { - System.out.println(e); - } - throw new SkippedException("Test skipped: failure during" + - " initialization"); - } - - if (shouldRun()) { - // Test against JCE - testTlsAuthenticationCodeGeneration(); - - // Self-integrity test (complete TLS 1.2 communication) - new testTLS12SunPKCS11Communication().run(); - - System.out.println("Test PASS - OK"); - } else { - throw new SkippedException("Test skipped: TLS 1.2 mechanisms" + - " not supported by current SunPKCS11 back-end"); - } - } - - private static boolean shouldRun() { - if (sunPKCS11NSSProvider == null) { - return false; - } - try { - KeyGenerator.getInstance("SunTls12MasterSecret", - sunPKCS11NSSProvider); - KeyGenerator.getInstance( - "SunTls12RsaPremasterSecret", sunPKCS11NSSProvider); - KeyGenerator.getInstance("SunTls12Prf", sunPKCS11NSSProvider); - } catch (NoSuchAlgorithmException e) { - return false; - } - return true; - } - - private static void testTlsAuthenticationCodeGeneration() - throws Exception { - // Generate RSA Pre-Master Secret in SunPKCS11 provider - SecretKey rsaPreMasterSecret = null; - @SuppressWarnings("deprecation") - TlsRsaPremasterSecretParameterSpec rsaPreMasterSecretSpec = - new TlsRsaPremasterSecretParameterSpec(0x0303, 0x0303); - { - KeyGenerator rsaPreMasterSecretKG = KeyGenerator.getInstance( - "SunTls12RsaPremasterSecret", sunPKCS11NSSProvider); - rsaPreMasterSecretKG.init(rsaPreMasterSecretSpec, null); - rsaPreMasterSecret = rsaPreMasterSecretKG.generateKey(); - } - - // Get RSA Pre-Master Secret in plain (from SunPKCS11 provider) - byte[] rsaPlainPreMasterSecret = null; - { - Cipher rsaPreMasterSecretWrapperCipher = - Cipher.getInstance("RSA/ECB/PKCS1Padding", - sunPKCS11NSSProvider); - rsaPreMasterSecretWrapperCipher.init(Cipher.WRAP_MODE, publicKey, - new SecureRandom()); - byte[] rsaEncryptedPreMasterSecret = - rsaPreMasterSecretWrapperCipher.wrap(rsaPreMasterSecret); - Cipher rsaPreMasterSecretUnwrapperCipher = - Cipher.getInstance("RSA/ECB/PKCS1Padding", sunJCEProvider); - rsaPreMasterSecretUnwrapperCipher.init(Cipher.UNWRAP_MODE, - privateKey, rsaPreMasterSecretSpec); - rsaPlainPreMasterSecret = rsaPreMasterSecretUnwrapperCipher.unwrap( - rsaEncryptedPreMasterSecret, "TlsRsaPremasterSecret", - Cipher.SECRET_KEY).getEncoded(); - - if (enableDebug) { - System.out.println("rsaPlainPreMasterSecret:"); - for (byte b : rsaPlainPreMasterSecret) { - System.out.printf("%02X, ", b); - } - System.out.println(""); - } - } - - // Generate Master Secret - SecretKey sunPKCS11MasterSecret = null; - SecretKey jceMasterSecret = null; - { - KeyGenerator sunPKCS11MasterSecretGenerator = - KeyGenerator.getInstance("SunTls12MasterSecret", - sunPKCS11NSSProvider); - KeyGenerator jceMasterSecretGenerator = KeyGenerator.getInstance( - "SunTls12MasterSecret", sunJCEProvider); - @SuppressWarnings("deprecation") - TlsMasterSecretParameterSpec sunPKCS11MasterSecretSpec = - new TlsMasterSecretParameterSpec(rsaPreMasterSecret, 3, 3, - new byte[32], new byte[32], "SHA-256", 32, 64); - @SuppressWarnings("deprecation") - TlsMasterSecretParameterSpec jceMasterSecretSpec = - new TlsMasterSecretParameterSpec( - new SecretKeySpec(rsaPlainPreMasterSecret, - "Generic"), 3, 3, new byte[32], - new byte[32], "SHA-256", 32, 64); - sunPKCS11MasterSecretGenerator.init(sunPKCS11MasterSecretSpec, - null); - jceMasterSecretGenerator.init(jceMasterSecretSpec, null); - sunPKCS11MasterSecret = - sunPKCS11MasterSecretGenerator.generateKey(); - jceMasterSecret = jceMasterSecretGenerator.generateKey(); - if (enableDebug) { - System.out.println("Master Secret (SunJCE):"); - if (jceMasterSecret != null) { - for (byte b : jceMasterSecret.getEncoded()) { - System.out.printf("%02X, ", b); - } - System.out.println(""); - } - } - } - - // Generate authentication codes - byte[] sunPKCS11AuthenticationCode = null; - byte[] jceAuthenticationCode = null; - { - // Generate SunPKCS11 authentication code - { - @SuppressWarnings("deprecation") - TlsPrfParameterSpec sunPKCS11AuthenticationCodeSpec = - new TlsPrfParameterSpec(sunPKCS11MasterSecret, - "client finished", "a".getBytes(), 12, - "SHA-256", 32, 64); - KeyGenerator sunPKCS11AuthCodeGenerator = - KeyGenerator.getInstance("SunTls12Prf", - sunPKCS11NSSProvider); - sunPKCS11AuthCodeGenerator.init( - sunPKCS11AuthenticationCodeSpec); - sunPKCS11AuthenticationCode = - sunPKCS11AuthCodeGenerator.generateKey().getEncoded(); - } - - // Generate SunJCE authentication code - { - @SuppressWarnings("deprecation") - TlsPrfParameterSpec jceAuthenticationCodeSpec = - new TlsPrfParameterSpec(jceMasterSecret, - "client finished", "a".getBytes(), 12, - "SHA-256", 32, 64); - KeyGenerator jceAuthCodeGenerator = - KeyGenerator.getInstance("SunTls12Prf", - sunJCEProvider); - jceAuthCodeGenerator.init(jceAuthenticationCodeSpec); - jceAuthenticationCode = - jceAuthCodeGenerator.generateKey().getEncoded(); - } - - if (enableDebug) { - System.out.println("SunPKCS11 Authentication Code: "); - for (byte b : sunPKCS11AuthenticationCode) { - System.out.printf("%02X, ", b); - } - System.out.println(""); - System.out.println("SunJCE Authentication Code: "); - for (byte b : jceAuthenticationCode) { - System.out.printf("%02X, ", b); - } - System.out.println(""); - } - } - - if (sunPKCS11AuthenticationCode == null || - jceAuthenticationCode == null || - sunPKCS11AuthenticationCode.length == 0 || - jceAuthenticationCode.length == 0 || - !Arrays.equals(sunPKCS11AuthenticationCode, - jceAuthenticationCode)) { - throw new Exception("Authentication codes from JCE" + - " and SunPKCS11 differ."); - } - } - - private static class testTLS12SunPKCS11Communication { - public static void run() throws Exception { - SSLEngine[][] enginesToTest = getSSLEnginesToTest(); - - for (SSLEngine[] engineToTest : enginesToTest) { - - SSLEngine clientSSLEngine = engineToTest[0]; - SSLEngine serverSSLEngine = engineToTest[1]; - - // SSLEngine code based on RedhandshakeFinished.java - - boolean dataDone = false; - - ByteBuffer clientOut = null; - ByteBuffer clientIn = null; - ByteBuffer serverOut = null; - ByteBuffer serverIn = null; - ByteBuffer cTOs; - ByteBuffer sTOc; - - SSLSession session = clientSSLEngine.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - clientIn = ByteBuffer.allocate(appBufferMax + 50); - serverIn = ByteBuffer.allocate(appBufferMax + 50); - - cTOs = ByteBuffer.allocateDirect(netBufferMax); - sTOc = ByteBuffer.allocateDirect(netBufferMax); - - clientOut = ByteBuffer.wrap( - "Hi Server, I'm Client".getBytes()); - serverOut = ByteBuffer.wrap( - "Hello Client, I'm Server".getBytes()); - - SSLEngineResult clientResult; - SSLEngineResult serverResult; - - while (!dataDone) { - clientResult = clientSSLEngine.wrap(clientOut, cTOs); - runDelegatedTasks(clientResult, clientSSLEngine); - serverResult = serverSSLEngine.wrap(serverOut, sTOc); - runDelegatedTasks(serverResult, serverSSLEngine); - cTOs.flip(); - sTOc.flip(); - - if (enableDebug) { - System.out.println("Client -> Network"); - printTlsNetworkPacket("", cTOs); - System.out.println(""); - System.out.println("Server -> Network"); - printTlsNetworkPacket("", sTOc); - System.out.println(""); - } - - clientResult = clientSSLEngine.unwrap(sTOc, clientIn); - runDelegatedTasks(clientResult, clientSSLEngine); - serverResult = serverSSLEngine.unwrap(cTOs, serverIn); - runDelegatedTasks(serverResult, serverSSLEngine); - - cTOs.compact(); - sTOc.compact(); - - if (!dataDone && - (clientOut.limit() == serverIn.position()) && - (serverOut.limit() == clientIn.position())) { - checkTransfer(serverOut, clientIn); - checkTransfer(clientOut, serverIn); - dataDone = true; - } - } - } - } - - static void printTlsNetworkPacket(String prefix, ByteBuffer bb) { - ByteBuffer slice = bb.slice(); - byte[] buffer = new byte[slice.remaining()]; - slice.get(buffer); - for (int i = 0; i < buffer.length; i++) { - System.out.printf("%02X, ", (byte)(buffer[i] & (byte)0xFF)); - if (i % 8 == 0 && i % 16 != 0) { - System.out.print(" "); - } - if (i % 16 == 0) { - System.out.println(""); - } - } - System.out.flush(); - } - - private static void checkTransfer(ByteBuffer a, ByteBuffer b) - throws Exception { - a.flip(); - b.flip(); - if (!a.equals(b)) { - throw new Exception("Data didn't transfer cleanly"); - } - a.position(a.limit()); - b.position(b.limit()); - a.limit(a.capacity()); - b.limit(b.capacity()); - } - - private static void runDelegatedTasks(SSLEngineResult result, - SSLEngine engine) throws Exception { - - if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - runnable.run(); - } - HandshakeStatus hsStatus = engine.getHandshakeStatus(); - if (hsStatus == HandshakeStatus.NEED_TASK) { - throw new Exception( - "handshake shouldn't need additional tasks"); - } - } - } - - private static SSLEngine[][] getSSLEnginesToTest() throws Exception { - SSLEngine[][] enginesToTest = new SSLEngine[2][2]; - // TLS_RSA_WITH_AES_128_GCM_SHA256 ciphersuite is available but - // must not be chosen for the TLS connection if not supported. - // See JDK-8222937. - String[][] preferredSuites = new String[][]{ new String[] { - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_128_CBC_SHA256" - }, new String[] { - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256" - }}; - for (int i = 0; i < enginesToTest.length; i++) { - enginesToTest[i][0] = createSSLEngine(true); - enginesToTest[i][1] = createSSLEngine(false); - // All CipherSuites enabled for the client. - enginesToTest[i][1].setEnabledCipherSuites(preferredSuites[i]); - } - return enginesToTest; - } - - static private SSLEngine createSSLEngine(boolean client) - throws Exception { - SSLEngine ssle; - KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX", "SunJSSE"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLSv1.2", "SunJSSE"); - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - ssle = sslCtx.createSSLEngine("localhost", 443); - ssle.setUseClientMode(client); - SSLParameters sslParameters = ssle.getSSLParameters(); - // verify that FFDHE named groups are available - boolean ffdheAvailable = Arrays.stream(sslParameters.getNamedGroups()) - .anyMatch(ng -> ng.startsWith("ffdhe")); - if (!ffdheAvailable) { - throw new RuntimeException("No FFDHE named groups available"); - } - // verify that ECDHE named groups are available - boolean ecdheAvailable = Arrays.stream(sslParameters.getNamedGroups()) - .anyMatch(ng -> ng.startsWith("secp")); - if (!ecdheAvailable) { - throw new RuntimeException("No ECDHE named groups available"); - } - ssle.setSSLParameters(sslParameters); - - return ssle; - } - } - - private static void initialize() throws Exception { - // - // For a successful FIPS-mode TLS connection, the following - // cryptographic providers will be installed: - // - // 1. SunPKCS11 (with an NSS FIPS mode backend) - // 2. SUN (to handle X.509 certificates) - // 3. SunJSSE (for a TLS engine) - - initSecmod(); - String configName = BASE + SEP + "nss.cfg"; - sunPKCS11NSSProvider = getSunPKCS11(configName); - System.out.println("SunPKCS11 provider: " + sunPKCS11NSSProvider); - - List installedProviders = new LinkedList<>(); - for (Provider p : Security.getProviders()){ - installedProviders.add(p); - Security.removeProvider(p.getName()); - } - Security.addProvider(sunPKCS11NSSProvider); - for (Provider p : installedProviders){ - String providerName = p.getName(); - if (providerName.equals("SunJSSE") || providerName.equals("SUN")) { - Security.addProvider(p); - } else if (providerName.equals("SunJCE")) { - sunJCEProvider = p; - } - } - - ks = KeyStore.getInstance("PKCS11", sunPKCS11NSSProvider); - ks.load(null, "test12".toCharArray()); - ts = ks; - - KeyStore ksPlain = readTestKeyStore(); - privateKey = (PrivateKey)ksPlain.getKey("rh_rsa_sha256", - passphrase); - publicKey = (PublicKey)ksPlain.getCertificate( - "rh_rsa_sha256").getPublicKey(); - } - - private static KeyStore readTestKeyStore() throws Exception { - File file = new File(System.getProperty("test.src", "."), "keystore"); - InputStream in = new FileInputStream(file); - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(in, "passphrase".toCharArray()); - in.close(); - return ks; - } -} Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/cert8.db and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/cert8.db differ Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/cert9.db and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/cert9.db differ Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/key3.db and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/key3.db differ Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/key4.db and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/key4.db differ Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/keystore and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/keystore differ diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/nss.cfg openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/nss.cfg --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/nss.cfg 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/nss.cfg 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ - -name = NSSKeyStore - -nssSecmodDirectory = ${pkcs11test.nss.db} - -nssLibraryDirectory = ${pkcs11test.nss.libdir} - -nssModule = fips - -# NSS needs CKA_NETSCAPE_DB for DSA and DH private keys -# just put an arbitrary value in there to make it happy - -attributes(*,CKO_PRIVATE_KEY,CKK_DSA) = { - CKA_NETSCAPE_DB = 0h00 -} - -attributes(*,CKO_PRIVATE_KEY,CKK_DH) = { - CKA_NETSCAPE_DB = 0h00 -} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/pkcs11.txt openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/pkcs11.txt --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/pkcs11.txt 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/pkcs11.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -library= -name=NSS Internal PKCS #11 Module -parameters=configdir='sql:./tmpdb' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription='' -NSS=trustOrder=75 cipherOrder=100 slotParams={0x00000001=[slotFlags=RSA,RC4,RC2,DES,DH,SHA1,MD5,MD2,SSL,TLS,AES,RANDOM askpw=any timeout=30 ] } Flags=internal,critical,FIPS - -library=libnssckbi.so -name=Builtin Roots Module -NSS=trustOrder=100 - Binary files /srv/release.debian.org/tmp/mk_OE3p0N3/openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs11/tls/tls12/secmod.db and /srv/release.debian.org/tmp/_EU3UEolTB/openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs11/tls/tls12/secmod.db differ diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -23,7 +23,7 @@ /* * @test id=GenerateOpensslPKCS12 - * @bug 8076190 8242151 8153005 8266182 + * @bug 8076190 8242151 8153005 8266182 8362894 * @summary This is java keytool <-> openssl interop test. This test generates * some openssl keystores on the fly, java operates on it and * vice versa. @@ -138,6 +138,11 @@ "pass:changeit", "-certpbe", "AES-256-CBC", "-keypbe", "AES-256-CBC", "-macalg", "SHA512") .shouldHaveExitValue(0); + + ProcessTools.executeCommand(opensslPath, "pkcs12", "-export", "-in", + "kandc", "-out", "os6", "-name", "a", "-passout", + "pass:changeit", "-pbmac1_pbkdf2", "-macalg", "sha256") + .shouldHaveExitValue(0); } private static void testWithJavaCommands() throws Throwable { @@ -168,6 +173,8 @@ // no storepass no cert check("os5", "a", null, "changeit", true, false, true); + check("os6", "a", "changeit", "changeit", true, true, true); + // keytool // Current default pkcs12 setting diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs12/PBMAC1Test.java openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/PBMAC1Test.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs12/PBMAC1Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/PBMAC1Test.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8343232 + * @summary Verify correctness of the structure of PKCS12 PBMAC1 + * keystores created with various property values. + * Verify that keystores load correctly from an input stream. + * @modules java.base/sun.security.util + * @library /test/lib + */ +import jdk.test.lib.Asserts; +import jdk.test.lib.security.DerUtils; +import sun.security.util.KnownOIDs; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +public class PBMAC1Test { + + static final char[] PASSWORD = "1234".toCharArray(); + + public static void main(String[] args) throws Exception { + create(); + migrate(); + overflow(); + } + + // PBMAC1 inside PKCS12 + //0019:008B [2] SEQUENCE + //001C:007B [20] SEQUENCE + //001E:0057 [200] SEQUENCE + //0020:000B [2000] OID 1.2.840.113549.1.5.14 (PBMAC1) + //002B:004A [2001] SEQUENCE + //002D:003A [20010] SEQUENCE + //002F:000B [200100] OID 1.2.840.113549.1.5.12 (PBKDF2) + //003A:002D [200101] SEQUENCE + //003C:0016 [2001010] OCTET STRING (20 bytes of salt) + //0052:0004 [2001011] INTEGER 10000 + //0056:0003 [2001012] INTEGER 32 + //0059:000E [2001013] SEQUENCE + //005B:000A [20010130] OID 1.2.840.113549.2.9 (HmacSHA256) + //0065:0002 [20010131] NULL + //0067:000E [20011] SEQUENCE + //0069:000A [200110] OID 1.2.840.113549.2.9 (HmacSHA256) + //0073:0002 [200111] NULL + //0075:0022 [201] OCTET STRING (32 bytes of mac) + //0097:000A [21] OCTET STRING (8 bytes of useless salt) + //00A1:0003 [22] INTEGER 1 + static void create() throws Exception { + System.setProperty("keystore.pkcs12.macAlgorithm", "pbewithhmacsha256"); + var der = emptyP12(); + DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2); + DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA256); + DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA256); + DerUtils.checkInt(der, "2001011", 10000); + DerUtils.checkInt(der, "2001012", 32); + + System.setProperty("keystore.pkcs12.macAlgorithm", "PBEWITHHMACSHA512"); + der = emptyP12(); + DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2); + DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA512); + DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA512); + DerUtils.checkInt(der, "2001011", 10000); + DerUtils.checkInt(der, "2001012", 64); + + System.setProperty("keystore.pkcs12.macAlgorithm", "PBEWiThHmAcSHA512/224"); + der = emptyP12(); + DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2); + DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA512$224); + DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA512$224); + DerUtils.checkInt(der, "2001011", 10000); + DerUtils.checkInt(der, "2001012", 28); + + // As strange as I can... + System.setProperty("keystore.pkcs12.macAlgorithm", + "PBEWithHmacSHA512/224AndHmacSHA3-384"); + der = emptyP12(); + DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2); + DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA512$224); + DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA3_384); + DerUtils.checkInt(der, "2001011", 10000); + DerUtils.checkInt(der, "2001012", 48); + + // Bad alg names + System.setProperty("keystore.pkcs12.macAlgorithm", "PBEWithHmacSHA456"); + var reason = Asserts.assertThrows(NoSuchAlgorithmException.class, + () -> emptyP12()).getMessage(); + Asserts.assertTrue(reason.contains("Algorithm hmacsha456 not available"), reason); + } + + static void migrate() throws Exception { + // A pkcs12 file using PBEWithHmacSHA256 but key length is 8 + var sha2p12 = """ + MIGhAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBiDB5MFUGCSqGSIb3DQEFDjBIMDgGCSqGSIb3DQEF + DDArBBSV6e5xI+9AYtGHQlDI0X4pmvWLBQICJxACAQgwDAYIKoZIhvcNAgkFADAMBggqhkiG9w0C + CQUABCAaaSO6JgEh1lDo1pvAC0CF5HqgIFBvzt1+GZlgFy7xFQQITk9UIFVTRUQCAQE= + """; + var der = Base64.getMimeDecoder().decode(sha2p12); + DerUtils.checkInt(der, "2001012", 8); // key length used to be 8 + + der = loadAndStore(sha2p12); + DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA256); + DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA256); + DerUtils.checkInt(der, "2001012", 32); // key length changed to 32 + } + + static void overflow() throws Exception { + + // Cannot create new + System.setProperty("keystore.pkcs12.macIterationCount", "5000001"); + System.setProperty("keystore.pkcs12.macAlgorithm", "pbewithhmacsha256"); + Asserts.assertThrows(IllegalArgumentException.class, PBMAC1Test::emptyP12); + System.clearProperty("keystore.pkcs12.macAlgorithm"); + Asserts.assertThrows(IllegalArgumentException.class, PBMAC1Test::emptyP12); + + // IC=5000001 using old algorithm + var bigICt = """ + MGYCAQMwEQYJKoZIhvcNAQcBoAQEAjAAME4wMTANBglghkgBZQMEAgEFAAQgyLBK5h9/E/2o7l2A + eALbI1otiS8kT3C41Ef3T38OMjUEFIic7isrAJNr+3+8fUbnMtmB0qytAgNMS0E= + """; + + // IC=5000000 using old algorithm + var smallICt = """ + MGYCAQMwEQYJKoZIhvcNAQcBoAQEAjAAME4wMTANBglghkgBZQMEAgEFAAQgR61YZLW6H81rkGTk + XfuU138mkIugdoQBhuNsnvWuBtQEFJ0wmMlpoUiji8PlvwCrmMbqWW4XAgNMS0A= + """; + + // IC=5000001 using PBMAC1 + var bigICp = """ + MIGiAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBiTB6MFYGCSqGSIb3DQEFDjBJMDkGCSqGSIb3DQEF + DDAsBBQFNf/gHCO5jNT429D6Q5gxTKHqVAIDTEtBAgEgMAwGCCqGSIb3DQIJBQAwDAYIKoZIhvcN + AgkFAAQgwEVMcyMPQXJSXUIbWqNWjMArtnXDlNUGnKD+19B7QFkECE5PVCBVU0VEAgEB + """; + + // IC=5000000 using PBMAC1 + var smallICp = """ + MIGiAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBiTB6MFYGCSqGSIb3DQEFDjBJMDkGCSqGSIb3DQEF + DDAsBBS/ZFfC7swsDHvaCXwyQkuMrZ7dbgIDTEtAAgEgMAwGCCqGSIb3DQIJBQAwDAYIKoZIhvcN + AgkFAAQgCRvE7LDbzkcYOVv/7iBv0KB3DoUkwnpTI0nsonVfv9UECE5PVCBVU0VEAgEB"""; + + loadAndStore(smallICp); + loadAndStore(smallICt); + + Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(bigICp)) + .getMessage().contains("MAC iteration count too large: 5000001")); + Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(bigICt)) + .getMessage().contains("MAC iteration count too large: 5000001")); + + // Incorrect Salt + var incorrectSalt = """ + MIGdAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBhDB1MFEGCSqGSIb3DQEFDjBEMDYGCSqGSIb3DQEF + DDApBBSakVhBLltKvqUj6EAxvWqJi+gc7AICJxACASAwCgYIKoZIhvcNAgkwCgYIKoZIhvcNAgkE + IG+euEHE8iN/2C7txbCjCJ9mU4TgEsHPsC9L3Rxa7malBAhOT1QgVVNFRAIBAQ=="""; + Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(incorrectSalt)) + .getMessage().contains("Integrity check failed")); + + // Incorrect Iteration Count + var incorrectIC = """ + MIGdAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBhDB1MFEGCSqGSIb3DQEFDjBEMDYGCSqGSIb3DQEF + DDApBBSZkVhBLltKvqUj6EAxvWqJi+gc7AICKBACASAwCgYIKoZIhvcNAgkwCgYIKoZIhvcNAgkE + IG+euEHE8iN/2C7txbCjCJ9mU4TgEsHPsC9L3Rxa7malBAhOT1QgVVNFRAIBAQ=="""; + Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(incorrectIC)) + .getMessage().contains("Integrity check failed")); + + // Missing Key Length + var missingKeyLength = """ + MIGaAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBgTByME4GCSqGSIb3DQEFDjBBMDMGCSqGSIb3DQEF + DDAmBBSZkVhBLltKvqUj6EAxvWqJi+gc7AICJxAwCgYIKoZIhvcNAgkwCgYIKoZIhvcNAgkEIG+e + uEHE8iN/2C7txbCjCJ9mU4TgEsHPsC9L3Rxa7malBAhOT1QgVVNFRAIBAQ=="""; + Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(missingKeyLength)) + .getMessage().contains("missing keyLength field")); + } + + static byte[] emptyP12() throws Exception { + var ks = KeyStore.getInstance("pkcs12"); + ks.load(null, null); + var os = new ByteArrayOutputStream(); + ks.store(os, PASSWORD); + return os.toByteArray(); + } + + static byte[] loadAndStore(String data) throws Exception { + var bytes = Base64.getMimeDecoder().decode(data); + var ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(bytes), PASSWORD); + var baos = new ByteArrayOutputStream(); + ks.store(baos, PASSWORD); + var newBytes = baos.toByteArray(); + var bais = new ByteArrayInputStream(newBytes); + ks.load(bais, PASSWORD); + return newBytes; + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs12/ParamsPreferences.java openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/ParamsPreferences.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs12/ParamsPreferences.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/ParamsPreferences.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ /* * @test - * @bug 8076190 8242151 8153005 8266293 + * @bug 8076190 8242151 8153005 8266293 8343232 * @library /test/lib * @modules java.base/sun.security.pkcs * java.base/sun.security.util @@ -244,7 +244,7 @@ checkAlg(data, "110c10", EncryptedData); checkAlg(data, "110c110110", certAlg); if (certAlg == PBES2) { - checkAlg(data, "110c11011100", PBKDF2WithHmacSHA1); + checkAlg(data, "110c11011100", PBKDF2); checkAlg(data, "110c1101110130", (KnownOIDs)args[i++]); checkAlg(data, "110c11011110", (KnownOIDs)args[i++]); checkInt(data, "110c110111011", (int) args[i++]); @@ -257,7 +257,7 @@ KnownOIDs keyAlg = (KnownOIDs)args[i++]; checkAlg(data, "110c010c01000", keyAlg); if (keyAlg == PBES2) { - checkAlg(data, "110c010c0100100", PBKDF2WithHmacSHA1); + checkAlg(data, "110c010c0100100", PBKDF2); checkAlg(data, "110c010c010010130", (KnownOIDs)args[i++]); checkAlg(data, "110c010c0100110", (KnownOIDs)args[i++]); checkInt(data, "110c010c01001011", (int) args[i++]); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs12/params/README openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/params/README --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs12/params/README 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/params/README 2026-10-19 12:10:20.000000000 +0000 @@ -14,6 +14,8 @@ -certpbe PBE-SHA1-RC4-128 -keypbe PBE-SHA1-RC4-128 -macalg SHA224 openssl pkcs12 -export -in kandc -out os5 -name a -passout pass:changeit \ -certpbe AES-256-CBC -keypbe AES-256-CBC -macalg SHA512 +openssl pkcs12 -export -in kandc -out os6 -name a -passout pass:changeit \ + -pbmac1_pbkdf2 -macalg sha256 for a in *; do openssl base64 -in $a -out ../$a done diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs12/params/os6 openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/params/os6 --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/pkcs12/params/os6 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/pkcs12/params/os6 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,23 @@ +MIIEOgIBAzCCA7QGCSqGSIb3DQEHAaCCA6UEggOhMIIDnTCCAmoGCSqGSIb3DQEH +BqCCAlswggJXAgEAMIICUAYJKoZIhvcNAQcBMF8GCSqGSIb3DQEFDTBSMDEGCSqG +SIb3DQEFDDAkBBBEpg+dmjxfnLMTmaHD/RjPAgIIADAMBggqhkiG9w0CCQUAMB0G +CWCGSAFlAwQBKgQQT731bM49PtePx/S4Xf6UZICCAeBeDpWGfpMn8d+wcAoHjUyg ++ceG2y75ac4UVsnVSpYCZaPHcOvUDbTAk5ylMGseLvl3x7xHmovIlShW1IBUWpTe +LhWNpa2f5yZ7t/BXB/oJFT7ol17WznHgmmCi6XbdiGq1YSV3X7SQEBw8WBWeOjGb +IURTAZCLMbGLXkSdg+2DRgP+PpM/Y29vFK2vo72s8bfYS9bGitEreyafP/jv8GxN +6SZx9+FSpTQ92Yj8qyFxvkR4fDyBnYe50KLf/bZmGMBq/d19lxNoheLGfuZ2ZM7W +Mw+wePBJsyntJfcce8iWjt6M8epVmx8SwarNkLU3UiX5XPDGJnnI/0QXEvJ2skQW +y9kCTP4DRYd2kg0tRvpsrK2DraP6xxBCviixoil1rbiQHmOhj6RKx1grGw94nvZq +JM7rZbKN3DvjSwjRn8S2QvycqGYhrQhwoQGqajmCuuBrkM6FCQUKjoWja1XCeQ3Q +8aRnQxwypB46Jrvvn4t3GghF3ZJ0X9LuimXQo9GAXf+X7eNOPpjFrIWlgICTgRN+ +v9elrcUOUKb9C24/Zws/B3nq8fvB9WY0Q9qaVZz9KUKfPjK1QwEr++5xJ5sBZgJz +kZNV0n4dxe4oCN+pE9ztpEswf4sWER92G+YDZB0IEV4wggErBgkqhkiG9w0BBwGg +ggEcBIIBGDCCARQwggEQBgsqhkiG9w0BDAoBAqCBxjCBwzBfBgkqhkiG9w0BBQ0w +UjAxBgkqhkiG9w0BBQwwJAQQvMlpTtrcoqg0XEC3z6KFEgICCAAwDAYIKoZIhvcN +AgkFADAdBglghkgBZQMEASoEEO7wolHeKZyoyII6h3l+iQ4EYEyg6yJWNUWo8ug2 +QNsXVUWmUb9nfu0+nIuhnpBwRewveSv+XMZ+C8szRQsefeMdfjzy91M/ZSHkR73K +HcKdUTVI5zNdBd61g9VNL6CvQCPZIj7AW5bsJ2cZg/GjpsepcDE4MBEGCSqGSIb3 +DQEJFDEEHgIAYTAjBgkqhkiG9w0BCRUxFgQUxCJpJWSVzAG4ZpwKuIUAgKBtWAkw +fTBtMEkGCSqGSIb3DQEFDjA8MCwGCSqGSIb3DQEFDDAfBAgMIRBR5kB3lgICCAAC +ASAwDAYIKoZIhvcNAgkFADAMBggqhkiG9w0CCQUABCDM5Ec9Anci3+OswMqEX22f +uAUrp9IqJSBF3ZY2g86utgQIDCEQUeZAd5YCAggA diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java openjdk-25-25.0.5+8/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,13 +88,13 @@ for (var t : kat.get("testGroups").asArray()) { var pname = t.get("parameterSet").asString(); System.out.println(">> " + pname + " sign"); - var det = Boolean.parseBoolean(t.get("deterministic").asString()); + var det = t.get("deterministic").asBoolean(); if (t.get("signatureInterface").asString().equals("internal")) { ML_DSA_Impls.version = ML_DSA_Impls.Version.DRAFT; } else { ML_DSA_Impls.version = ML_DSA_Impls.Version.FINAL; } - if (t.get("externalMu").asString().equals("true")) { + if (t.get("externalMu").asBoolean()) { continue; // Not supported } for (var c : t.get("tests").asArray()) { @@ -139,7 +139,7 @@ ML_DSA_Impls.version = ML_DSA_Impls.Version.FINAL; } - if (t.get("externalMu").asString().equals("true")) { + if (t.get("externalMu").asBoolean()) { continue; // Not supported } @@ -157,7 +157,7 @@ public byte[] getEncoded() { return toByteArray(c.get("pk").asString()); } }; // Only ML-DSA sigVer has negative tests - var expected = Boolean.parseBoolean(c.get("testPassed").asString()); + var expected = c.get("testPassed").asBoolean(); var actual = true; try { s.initVerify(pk); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,24 @@ /* * @test - * @bug 8246330 + * @bug 8246330 8314323 * @library /javax/net/ssl/templates /test/lib * @run main/othervm -Djdk.tls.namedGroups="secp384r1" DisabledCurve DISABLE_NONE PASS * @run main/othervm -Djdk.tls.namedGroups="secp384r1" DisabledCurve secp384r1 FAIL + * @run main/othervm -Djdk.tls.namedGroups="X25519MLKEM768" + DisabledCurve DISABLE_NONE PASS + * @run main/othervm -Djdk.tls.namedGroups="X25519MLKEM768" + DisabledCurve X25519MLKEM768 FAIL + * @run main/othervm -Djdk.tls.namedGroups="SecP256r1MLKEM768" + DisabledCurve DISABLE_NONE PASS + * @run main/othervm -Djdk.tls.namedGroups="SecP256r1MLKEM768" + DisabledCurve SecP256r1MLKEM768 FAIL + * @run main/othervm -Djdk.tls.namedGroups="SecP384r1MLKEM1024" + DisabledCurve DISABLE_NONE PASS + * @run main/othervm -Djdk.tls.namedGroups="SecP384r1MLKEM1024" + DisabledCurve SecP384r1MLKEM1024 FAIL */ import java.security.Security; import java.util.Arrays; @@ -45,8 +57,10 @@ private static final String[][][] protocols = { { { "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1" }, { "TLSv1.2" } }, { { "TLSv1.2" }, { "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1" } }, - { { "TLSv1.2" }, { "TLSv1.2" } }, { { "TLSv1.1" }, { "TLSv1.1" } }, - { { "TLSv1" }, { "TLSv1" } } }; + { { "TLSv1.2" }, { "TLSv1.2" } }, + { { "TLSv1.1" }, { "TLSv1.1" } }, + { { "TLSv1" }, { "TLSv1" } }, + { { "TLSv1.3" }, { "TLSv1.3" } } }; @Override protected SSLContext createClientSSLContext() throws Exception { @@ -94,17 +108,36 @@ String expected = args[1]; String disabledName = ("DISABLE_NONE".equals(args[0]) ? "" : args[0]); boolean disabled = false; - if (disabledName.equals("")) { + + if (disabledName.isEmpty()) { Security.setProperty("jdk.disabled.namedCurves", ""); + Security.setProperty("jdk.certpath.disabledAlgorithms", ""); } else { disabled = true; - Security.setProperty("jdk.certpath.disabledAlgorithms", "secp384r1"); + Security.setProperty("jdk.certpath.disabledAlgorithms", disabledName); + if (!disabledName.contains("MLKEM")) { + Security.setProperty("jdk.disabled.namedCurves", disabledName); + } else { + Security.setProperty("jdk.disabled.namedCurves", ""); + } } // Re-enable TLSv1 and TLSv1.1 since test depends on it. SecurityUtils.removeFromDisabledTlsAlgs("TLSv1", "TLSv1.1"); + String namedGroups = System.getProperty("jdk.tls.namedGroups", ""); + boolean hybridGroup = namedGroups.contains("MLKEM"); + for (index = 0; index < protocols.length; index++) { + if (hybridGroup) { + String[] clientProtos = protocols[index][0]; + String[] serverProtos = protocols[index][1]; + + if (!(isTLS13(clientProtos) && isTLS13(serverProtos))) { + continue; + } + } + try { (new DisabledCurve()).run(); if (expected.equals("FAIL")) { @@ -123,4 +156,8 @@ } } + + private static boolean isTLS13(String[] protocols) { + return protocols.length == 1 && "TLSv1.3".equals(protocols[0]); + } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,8 @@ * questions. */ +import java.util.Arrays; +import java.util.List; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLSocket; @@ -29,7 +31,7 @@ /* * @test - * @bug 8224650 8242929 + * @bug 8224650 8242929 8314323 * @library /javax/net/ssl/templates * /javax/net/ssl/TLSCommon * /test/lib @@ -44,17 +46,20 @@ * @run main/othervm NamedGroupsWithCipherSuite ffdhe4096 * @run main/othervm NamedGroupsWithCipherSuite ffdhe6144 * @run main/othervm NamedGroupsWithCipherSuite ffdhe8192 + * @run main/othervm NamedGroupsWithCipherSuite X25519MLKEM768 + * @run main/othervm NamedGroupsWithCipherSuite SecP256r1MLKEM768 + * @run main/othervm NamedGroupsWithCipherSuite SecP384r1MLKEM1024 */ public class NamedGroupsWithCipherSuite extends SSLSocketTemplate { - private static final Protocol[] PROTOCOLS = new Protocol[] { + private static final List PROTOCOLS = List.of( Protocol.TLSV1_3, Protocol.TLSV1_2, Protocol.TLSV1_1, Protocol.TLSV1 - }; + ); - private static final CipherSuite[] CIPHER_SUITES = new CipherSuite[] { + private static final List CIPHER_SUITES = List.of( CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_AES_256_GCM_SHA384, CipherSuite.TLS_CHACHA20_POLY1305_SHA256, @@ -75,7 +80,23 @@ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 - }; + ); + + private static final List HYBRID_NAMEDGROUPS = List.of( + "X25519MLKEM768", + "SecP256r1MLKEM768", + "SecP384r1MLKEM1024" + ); + + private static final List HYBRID_PROTOCOL = List.of( + Protocol.TLSV1_3 + ); + + private static final List HYBRID_CIPHER_SUITES = List.of( + CipherSuite.TLS_AES_128_GCM_SHA256, + CipherSuite.TLS_AES_256_GCM_SHA384, + CipherSuite.TLS_CHACHA20_POLY1305_SHA256 + ); private String protocol; private String cipher; @@ -151,48 +172,59 @@ // Re-enable TLSv1 and TLSv1.1 since test depends on it. SecurityUtils.removeFromDisabledTlsAlgs("TLSv1", "TLSv1.1"); - for (Protocol protocol : PROTOCOLS) { - for (CipherSuite cipherSuite : CIPHER_SUITES) { - // Named group converted to lower case just - // to satisfy Test condition + boolean hybridGroup = HYBRID_NAMEDGROUPS.contains(namedGroup); + List protocolList = hybridGroup ? + HYBRID_PROTOCOL : PROTOCOLS; + List cipherList = hybridGroup ? + HYBRID_CIPHER_SUITES : CIPHER_SUITES; + + // non-Hybrid named group converted to lower case just + // to satisfy Test condition + String normalizedGroup = hybridGroup ? + namedGroup : namedGroup.toLowerCase(); + + for (Protocol protocol : protocolList) { + for (CipherSuite cipherSuite : cipherList) { if (cipherSuite.supportedByProtocol(protocol) - && groupSupportdByCipher(namedGroup.toLowerCase(), - cipherSuite)) { + && groupSupportedByCipher(normalizedGroup, + cipherSuite)) { System.out.printf("Protocol: %s, cipher suite: %s%n", protocol, cipherSuite); - // Named group converted to lower case just - // to satisfy Test condition new NamedGroupsWithCipherSuite(protocol, - cipherSuite, namedGroup.toLowerCase()).run(); + cipherSuite, normalizedGroup).run(); } } } } - private static boolean groupSupportdByCipher(String group, + private static boolean groupSupportedByCipher(String group, CipherSuite cipherSuite) { + if (HYBRID_NAMEDGROUPS.contains(group)) { + return cipherSuite.keyExAlgorithm == null; + } + return (group.startsWith("x") - && xdhGroupSupportdByCipher(cipherSuite)) + && xdhGroupSupportedByCipher(cipherSuite)) || (group.startsWith("secp") - && ecdhGroupSupportdByCipher(cipherSuite)) + && ecdhGroupSupportedByCipher(cipherSuite)) || (group.startsWith("ffdhe") - && ffdhGroupSupportdByCipher(cipherSuite)); + && ffdhGroupSupportedByCipher(cipherSuite)); } - private static boolean xdhGroupSupportdByCipher( + private static boolean xdhGroupSupportedByCipher( CipherSuite cipherSuite) { return cipherSuite.keyExAlgorithm == null || cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_RSA; } - private static boolean ecdhGroupSupportdByCipher( + private static boolean ecdhGroupSupportedByCipher( CipherSuite cipherSuite) { return cipherSuite.keyExAlgorithm == null || cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_RSA || cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_ECDSA; } - private static boolean ffdhGroupSupportdByCipher( + private static boolean ffdhGroupSupportedByCipher( CipherSuite cipherSuite) { return cipherSuite.keyExAlgorithm == null || cipherSuite.keyExAlgorithm == KeyExAlgorithm.DHE_DSS diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/CipherSuite/RestrictNamedGroup.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/RestrictNamedGroup.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/CipherSuite/RestrictNamedGroup.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/RestrictNamedGroup.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8226374 8242929 + * @bug 8226374 8242929 8314323 * @library /javax/net/ssl/templates * @summary Restrict signature algorithms and named groups * @run main/othervm RestrictNamedGroup x25519 @@ -36,6 +36,9 @@ * @run main/othervm RestrictNamedGroup ffdhe4096 * @run main/othervm RestrictNamedGroup ffdhe6144 * @run main/othervm RestrictNamedGroup ffdhe8192 + * @run main/othervm RestrictNamedGroup X25519MLKEM768 + * @run main/othervm RestrictNamedGroup SecP256r1MLKEM768 + * @run main/othervm RestrictNamedGroup SecP384r1MLKEM1024 */ import java.security.Security; diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8171279 + * @bug 8171279 8314323 * @library /javax/net/ssl/templates * @summary Test TLS connection with each individual supported group * @run main/othervm SupportedGroups x25519 @@ -36,6 +36,9 @@ * @run main/othervm SupportedGroups ffdhe4096 * @run main/othervm SupportedGroups ffdhe6144 * @run main/othervm SupportedGroups ffdhe8192 + * @run main/othervm SupportedGroups X25519MLKEM768 + * @run main/othervm SupportedGroups SecP256r1MLKEM768 + * @run main/othervm SupportedGroups SecP384r1MLKEM1024 */ import java.net.InetAddress; import java.util.Arrays; @@ -45,15 +48,24 @@ public class SupportedGroups extends SSLSocketTemplate { private static volatile int index; - private static final String[][][] protocols = { + private static final String[][][] protocolsForClassic = { {{"TLSv1.3"}, {"TLSv1.3"}}, {{"TLSv1.3", "TLSv1.2"}, {"TLSv1.2"}}, {{"TLSv1.2"}, {"TLSv1.3", "TLSv1.2"}}, {{"TLSv1.2"}, {"TLSv1.2"}} }; - public SupportedGroups() { + private static final String[][][] protocolsForHybrid = { + {{"TLSv1.3"}, {"TLSv1.3"}}, + {{"TLSv1.3", "TLSv1.2"}, {"TLSv1.3"}}, + {{"TLSv1.3"}, {"TLSv1.3", "TLSv1.2"}} + }; + + private final String[][][] protocols; + + public SupportedGroups(String[][][] protocols) { this.serverAddress = InetAddress.getLoopbackAddress(); + this.protocols = protocols; } // Servers are configured before clients, increment test case after. @@ -85,8 +97,18 @@ public static void main(String[] args) throws Exception { System.setProperty("jdk.tls.namedGroups", args[0]); + boolean hybridGroup = hybridNamedGroup(args[0]); + String[][][] protocols = hybridGroup ? + protocolsForHybrid : protocolsForClassic; + for (index = 0; index < protocols.length; index++) { - (new SupportedGroups()).run(); + (new SupportedGroups(protocols)).run(); } } + + private static boolean hybridNamedGroup(String namedGroup) { + return namedGroup.equals("X25519MLKEM768") || + namedGroup.equals("SecP256r1MLKEM768") || + namedGroup.equals("SecP384r1MLKEM1024"); + } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/CipherSuite/TLS13BulkCipherDisabledCipherSuite.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/TLS13BulkCipherDisabledCipherSuite.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/CipherSuite/TLS13BulkCipherDisabledCipherSuite.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/CipherSuite/TLS13BulkCipherDisabledCipherSuite.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * 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 8387124 + * @summary Test disabling TLS 1.3 cipher suites with bulk ciphers names + * @run testng/othervm TLS13BulkCipherDisabledCipherSuite + */ + +import static org.testng.AssertJUnit.assertTrue; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import java.security.Security; +import java.util.List; + +public class TLS13BulkCipherDisabledCipherSuite extends AbstractDisableCipherSuites { + + private static final String SECURITY_PROPERTY = "jdk.tls.disabledAlgorithms"; + private static final String TEST_ALGORITHMS = "AES_256_GCM," + + " AES_128_GCM," + + " CHACHA20_POLY1305"; + private static final String[] CIPHER_SUITES = new String[] { + "TLS_AES_256_GCM_SHA384", + "TLS_AES_128_GCM_SHA256", + "TLS_CHACHA20_POLY1305_SHA256" + }; + static final List CIPHER_SUITES_IDS = List.of( + 0x1301, + 0x1302, + 0x1303); + + @Override + protected String getProtocol() { + return "TLSv1.3"; + } + + @BeforeTest + void setUp() throws Exception { + Security.setProperty(SECURITY_PROPERTY, TEST_ALGORITHMS); + } + + @Test + public void testDefault() throws Exception { + assertTrue(testDefaultCase(CIPHER_SUITES_IDS)); + } + + @Test + public void testAddDisabled() throws Exception { + assertTrue(testEngAddDisabled(CIPHER_SUITES, CIPHER_SUITES_IDS)); + } + + @Test + public void testOnlyDisabled() throws Exception { + assertTrue(testEngOnlyDisabled(CIPHER_SUITES)); + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/HybridKeyExchange/TestHybrid.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/HybridKeyExchange/TestHybrid.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/HybridKeyExchange/TestHybrid.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/HybridKeyExchange/TestHybrid.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,67 @@ +/* + * 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 8379433 + * @summary Test expected DecapsulateException thrown by Hybrid KEM implementation + * @modules java.base/sun.security.ssl + * @run main/othervm TestHybrid +*/ +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; +import java.util.Arrays; +import javax.crypto.DecapsulateException; +import javax.crypto.KEM; + +public class TestHybrid { + + public static void main(String[] args) throws Exception { + + Class clazz = Class.forName("sun.security.ssl.HybridProvider"); + Provider p = (Provider) clazz.getField("PROVIDER").get(null); + + String alg = "X25519MLKEM768"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance(alg, p); + KeyPair kp = kpg.generateKeyPair(); + + KEM kem = KEM.getInstance(alg, p); + KEM.Encapsulator e = kem.newEncapsulator(kp.getPublic()); + KEM.Decapsulator d = kem.newDecapsulator(kp.getPrivate()); + + int secretSize = e.secretSize(); + KEM.Encapsulated enc = e.encapsulate(); + byte[] ciphertext = enc.encapsulation(); + + byte[] badCiphertext = Arrays.copyOf(ciphertext, + ciphertext.length - 1); + try { + d.decapsulate(badCiphertext, 0, secretSize, "Generic"); + throw new RuntimeException( + "Expected DecapsulateException not thrown"); + } catch (DecapsulateException expected) { + System.out.println("Expected DecapsulateException thrown"); + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/SSLAlgorithmDecomposer/BulkCipherDecomposition.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/SSLAlgorithmDecomposer/BulkCipherDecomposition.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/SSLAlgorithmDecomposer/BulkCipherDecomposition.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/SSLAlgorithmDecomposer/BulkCipherDecomposition.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,109 @@ +/* + * 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 8387124 + * @summary Verify SSLAlgorithmDecomposer bulk cipher decomposition + * @library /javax/net/ssl/TLSCommon + * @run main/othervm + * --add-opens java.base/sun.security.ssl=ALL-UNNAMED + * BulkCipherDecomposition + */ + +import java.lang.reflect.Method; +import java.security.NoSuchAlgorithmException; +import java.security.Security; +import java.util.Arrays; +import java.util.Set; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; + +public class BulkCipherDecomposition { + + private static void testDecomposition(Object instance, Method decomposeMethod, String suite) + throws Exception { + @SuppressWarnings("unchecked") + Set result = (Set) decomposeMethod.invoke(instance, suite); + + String expectedBulk = extractBulkCipher(suite); + + System.out.println("================================================="); + System.out.println("Testing suite : " + suite); + System.out.println("Expected bulk : " + expectedBulk); + System.out.println("Decomposition : " + result); + + if (!result.contains(expectedBulk)) { + throw new RuntimeException( + "Missing bulk cipher decomposition\n" + + "Suite: " + suite + "\n" + + "Expected: " + expectedBulk + "\n" + + "Actual: " + result); + } + } + + /** + * Separator used in TLS cipher suite names to mark the start of + * the bulk cipher component (e.g. TLS_RSA_WITH_AES_128_CBC_SHA). + */ + private static final String WITH = "_WITH_"; + + private static String extractBulkCipher(String suite) { + if (suite.contains(WITH)) { + String after = suite.substring(suite.indexOf(WITH) + WITH.length()); + int last = after.lastIndexOf('_'); + return after.substring(0, last); + } else { + int first = suite.indexOf('_'); + int last = suite.lastIndexOf('_'); + return suite.substring(first + 1, last); + } + } + + private static String[] getCipherSuites() throws NoSuchAlgorithmException { + SSLEngine engine = SSLContext.getDefault().createSSLEngine(); + return Arrays.stream(engine.getSupportedCipherSuites()) + .map(CipherSuite::cipherSuite) + .filter(cs -> cs != CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) + .map(CipherSuite::name) + .toArray(String[]::new); + } + + public static void main(String[] args) throws Exception { + // disabledAlgorithms limits supported suites; clear to list all + Security.setProperty("jdk.tls.disabledAlgorithms", ""); + + Class c = Class.forName("sun.security.ssl.SSLAlgorithmDecomposer"); + var ctor = c.getDeclaredConstructor(); + ctor.setAccessible(true); + Object instance = ctor.newInstance(); + Method decomposeMethod = c.getDeclaredMethod("decompose", String.class); + decomposeMethod.setAccessible(true); + + for (String suite : getCipherSuites()) { + testDecomposition(instance, decomposeMethod, suite); + } + + System.out.println("PASS"); + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruteForceClose.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruteForceClose.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruteForceClose.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruteForceClose.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -73,7 +73,7 @@ protected void configureClientSocket(SSLSocket socket) { try { socket.setSoLinger(true, 3); - socket.setSoTimeout(1000); + socket.setSoTimeout(5000); } catch (SocketException exc) { throw new RuntimeException("Could not configure client socket", exc); } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Camerfirma.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Camerfirma.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Camerfirma.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Camerfirma.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ * @modules java.base/sun.security.validator * @run main/othervm Camerfirma after policyOn invalid * @run main/othervm Camerfirma after policyOff valid - * @run main/othervm Camerfirma before policyOn valid + * @run main/othervm Camerfirma before policyOn invalid * @run main/othervm Camerfirma before policyOff valid */ @@ -50,7 +50,7 @@ // named "-chain.pem". private static final String ROOT_TO_TEST = "camerfirmachambersca"; - // Date after the restrictions take effect + // Date after the restrictions took effect when distrust was first announced private static final ZonedDateTime DISTRUST_DATE = LocalDate.of(2025, 04, 16).atStartOfDay(ZoneOffset.UTC); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java 2026-10-19 12:10:20.000000000 +0000 @@ -42,6 +42,7 @@ * @run main/othervm Chunghwa before policyOff valid */ + public class Chunghwa { private static final String CERT_PATH = "chains" + File.separator + "chunghwa"; @@ -50,12 +51,18 @@ // named "-chain.pem". private static final String ROOT_TO_TEST = "chunghwaepkirootca"; - // Date after the restrictions take effect + // Date after the restrictions took effect when distrust was first announced private static final ZonedDateTime DISTRUST_DATE = LocalDate.of(2026, 03, 18).atStartOfDay(ZoneOffset.UTC); + private static final LocalDate APRIL_19_2027 = LocalDate.of(2027, 04, 19); + private static final LocalDate TODAY = LocalDate.now(); public static void main(String[] args) throws Exception { + if (args[1].equals("policyOn") && TODAY.isAfter(APRIL_19_2027)) { + args[2] = "invalid"; + } + Distrust distrust = new Distrust(args); X509TrustManager[] tms = new X509TrustManager[]{ diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java 2026-10-19 12:10:20.000000000 +0000 @@ -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,7 +35,7 @@ * @modules java.base/sun.security.validator * @run main/othervm Entrust after policyOn invalid * @run main/othervm Entrust after policyOff valid - * @run main/othervm Entrust before policyOn valid + * @run main/othervm Entrust before policyOn invalid * @run main/othervm Entrust before policyOff valid */ @@ -49,7 +49,7 @@ "entrustevca", "entrustrootcaec1", "entrustrootcag2", "entrustrootcag4", "entrust2048ca"}; - // Date when the restrictions take effect + // Date after the restrictions took effect when distrust was first announced private static final ZonedDateTime DISTRUST_DATE = LocalDate.of(2024, 11, 12).atStartOfDay(ZoneOffset.UTC); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * @modules java.base/sun.security.validator * @run main/othervm Symantec after policyOn invalid * @run main/othervm Symantec after policyOff valid - * @run main/othervm Symantec before policyOn valid + * @run main/othervm Symantec before policyOn invalid * @run main/othervm Symantec before policyOff valid */ @@ -57,7 +57,7 @@ // chain stored in a file named "-chain.pem". private static String[] subCAsToTest = new String[]{"appleistca8g1"}; - // Date when the restrictions take effect + // Date after the restrictions took effect when distrust was first announced private static final ZonedDateTime ROOTS_DISTRUST_DATE = LocalDate.of(2019, 4, 17).atStartOfDay(ZoneOffset.UTC); @@ -87,9 +87,5 @@ // test code-signing chain (should be valid as restrictions don't apply) Date validationDate = new Date(1544197375493L); distrust.testCodeSigningChain(certPath, "verisignclass3g5ca-codesigning", validationDate); - - // test chains issued through subCAs - notBefore = distrust.getNotBefore(SUBCA_DISTRUST_DATE); - distrust.testCertificateChain(certPath, notBefore, tms, subCAsToTest); } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java openjdk-25-25.0.5+8/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -196,6 +196,7 @@ check(checker, "altfoo1.com", cert3, true); check(checker, "altfoo2.com", cert3, true); check(checker, "5.6.7.8", cert3, true); + check(checker, "::ffff:5.6.7.8", cert3, true); check(checker, "foo.bar.com", cert4, true); check(checker, "altfoo.bar.com", cert4, false); check(checker, "2001:db8:3c4d:15::1a2f:1a2b", cert5, true); @@ -221,6 +222,7 @@ check(checker, "altfoo1.com", cert3, true); check(checker, "altfoo2.com", cert3, true); check(checker, "5.6.7.8", cert3, true); + check(checker, "::ffff:5.6.7.8", cert3, true); check(checker, "foo.bar.com", cert4, true); check(checker, "altfoo.bar.com", cert4, false); } @@ -239,11 +241,11 @@ throws Exception { try { checker.match(name, cert); - if (expectedResult == false) { + if (!expectedResult) { throw new Exception("Passed invalid test: " + name); } } catch (CertificateException e) { - if (expectedResult == true) { + if (expectedResult) { throw new Exception("Failed valid test: " + name, e); } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java openjdk-25-25.0.5+8/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,16 +24,19 @@ /* * @test * @author Gary Ellison - * @bug 4170635 8258247 + * @bug 4170635 8258247 8367008 + * @library /test/lib * @summary Verify equals()/hashCode() contract honored * @modules java.base/sun.security.x509 java.base/sun.security.util */ -import java.io.*; +import java.io.IOException; import java.security.AlgorithmParameters; import java.security.spec.MGF1ParameterSpec; import java.security.spec.PSSParameterSpec; +import jdk.test.lib.Asserts; + import sun.security.util.DerValue; import sun.security.x509.*; @@ -97,5 +100,20 @@ } else { System.out.println("PASSED equals() test"); } + + // Construct an AlgorithmId with explicit DER NULL parameters + DerValue explicitNullParams = new DerValue(DerValue.tag_Null, new byte[0]); + AlgorithmId aiNullParams = new AlgorithmId(AlgorithmId.SHA256_oid, + explicitNullParams); + // The constructor should canonicalize this to "no parameters" + Asserts.assertTrue(aiNullParams.getEncodedParams() == null); + AlgorithmId aiNormal = AlgorithmId.get("SHA-256"); + Asserts.assertEquals(aiNullParams, aiNormal); + Asserts.assertEquals(aiNullParams.hashCode(), aiNormal.hashCode()); + + // Test invalid ASN.1 NULL (non-zero length) + DerValue invalidNull = new DerValue(DerValue.tag_Null, new byte[]{0x00}); + Asserts.assertThrows(IOException.class, + () -> new AlgorithmId(AlgorithmId.SHA256_oid, invalidNull)); } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/x509/AlgorithmId/NullParams.java openjdk-25-25.0.5+8/test/jdk/sun/security/x509/AlgorithmId/NullParams.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/x509/AlgorithmId/NullParams.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/x509/AlgorithmId/NullParams.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,6 +67,13 @@ test("SHA3-256withRSA", true); test("SHA3-384withRSA", true); test("SHA3-512withRSA", true); + test("HmacSHA1", true); + test("HmacSHA224", true); + test("HmacSHA256", true); + test("HmacSHA384", true); + test("HmacSHA512", true); + test("HmacSHA512/224", true); + test("HmacSHA512/256", true); // Full old list: must be absent test("SHA1withECDSA", false); @@ -83,7 +90,6 @@ // Others test("DSA", false); test("SHA1withDSA", false); - test("HmacSHA1", false); if (failed) { throw new RuntimeException("At least one failed"); diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java openjdk-25-25.0.5+8/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -21,132 +21,126 @@ * questions. */ -/** - * @test - * @summary DNSName parsing tests - * @bug 8213952 8186143 - * @modules java.base/sun.security.x509 - * @run testng DNSNameTest - */ +import static jdk.test.lib.Asserts.fail; import java.io.IOException; +import java.net.IDN; +import java.util.List; +import java.util.stream.Stream; import sun.security.x509.DNSName; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.testng.Assert.*; +/* + * @test + * @summary DNSName parsing tests + * @bug 8213952 8186143 8381771 + * @library /test/lib + * @modules java.base/sun.security.x509 + * @run main DNSNameTest + */ public class DNSNameTest { - @DataProvider(name = "goodNames") - public Object[][] goodNames() { - Object[][] data = { - {"abc.com"}, - {"ABC.COM"}, - {"a12.com"}, - {"a1b2c3.com"}, - {"1abc.com"}, - {"123.com"}, - {"abc.com-"}, // end with hyphen - {"a-b-c.com"}, // hyphens - }; - return data; - } - - @DataProvider(name = "goodSanNames") - public Object[][] goodSanNames() { - Object[][] data = { - {"abc.com"}, - {"ABC.COM"}, - {"a12.com"}, - {"a1b2c3.com"}, - {"1abc.com"}, - {"123.com"}, - {"abc.com-"}, // end with hyphen - {"a-b-c.com"}, // hyphens - {"*.domain.com"}, // wildcard in 1st level subdomain - {"*.com"}, - }; - return data; - } - - @DataProvider(name = "badNames") - public Object[][] badNames() { - Object[][] data = { - {" 1abc.com"}, // begin with space - {"1abc.com "}, // end with space - {"1a bc.com "}, // no space allowed - {"-abc.com"}, // begin with hyphen - {"a..b"}, // .. - {".a"}, // begin with . - {"a."}, // end with . - {""}, // empty - {" "}, // space only - {"*.domain.com"}, // wildcard not allowed - {"a*.com"}, // only allow letter, digit, or hyphen - }; - return data; - } - @DataProvider(name = "badSanNames") - public Object[][] badSanNames() { - Object[][] data = { - {" 1abc.com"}, // begin with space - {"1abc.com "}, // end with space - {"1a bc.com "}, // no space allowed - {"-abc.com"}, // begin with hyphen - {"a..b"}, // .. - {".a"}, // begin with . - {"a."}, // end with . - {""}, // empty - {" "}, // space only - {"*"}, // wildcard only - {"*a.com"}, // partial wildcard disallowed - {"abc.*.com"}, // wildcard not allowed in 2nd level - {"*.*.domain.com"}, // double wildcard not allowed - {"a*.com"}, // only allow letter, digit, or hyphen - }; - return data; + private static final List GOOD_NAMES = List.of( + "abc", + String.join(".", "a".repeat(63), "b".repeat(63), + "c".repeat(63), "d".repeat(61)), + "abc.com", + "tesT.Abc.com", + "ABC.COM", + "a12.com", + "a1b2c3.com", + "1abc.com", + "123.com", + "a-b-c.com", // hyphens + IDN.toASCII("公司.江利子") // IDN punycode + ); + + private static final List GOOD_SAN_NAMES = Stream.concat( + Stream.of( + "*.domain.com", // wildcard in 1st level subdomain + "*.com"), + GOOD_NAMES.stream()) + .toList(); + + private static final List BAD_NAMES = List.of( + // DNSName too long + String.join(".", "a".repeat(63), "b".repeat(63), + "c".repeat(63), "d".repeat(62)), + // DNSName label too long + "a".repeat(64), + " 1abc.com", // begin with space + "1abc.com ", // end with space + "1a bc.com ", // no space allowed + "-abc.com", // name begins with a hyphen + "abc.com-", // name ends with a hyphen + "abc.-com", // label begins with a hyphen + "abc-.com", // label ends with a hyphen + "a..b", // .. + ".a", // begin with . + "a.", // end with . + "", // empty + " ", // space only + "*.domain.com", // wildcard not allowed + "a*.com" // only allow letter, digit, or hyphen + ); + + private static final List BAD_SAN_NAMES = Stream.concat( + Stream.of( + "*", // wildcard only + "*.", // wildcard with a period + "*a.com", // partial wildcard disallowed + "abc.*.com", // wildcard not allowed in 2nd level + "**.domain.com", // double wildcard not allowed + "*.domain.com*", // can't end with wildcard + "a*.com"), // only allow letter, digit, or hyphen + BAD_NAMES.stream().filter(n -> !n.contains("*"))) + .toList(); + + + public static void main(String[] args) { + GOOD_NAMES.forEach(DNSNameTest::testGoodDNSName); + GOOD_SAN_NAMES.forEach(DNSNameTest::testGoodSanDNSName); + BAD_NAMES.forEach(DNSNameTest::testBadDNSName); + BAD_SAN_NAMES.forEach(DNSNameTest::testBadSanDNSName); } - - @Test(dataProvider = "goodNames") - public void testGoodDNSName(String dnsNameString) { + private static void testGoodDNSName(String dnsNameString) { try { DNSName dn = new DNSName(dnsNameString); } catch (IOException e) { - fail("Unexpected IOException"); + fail("Unexpected IOException with input " + dnsNameString + ": " + + e.getMessage()); } } - @Test(dataProvider = "goodSanNames") - public void testGoodSanDNSName(String dnsNameString) { + private static void testGoodSanDNSName(String dnsNameString) { try { DNSName dn = new DNSName(dnsNameString, true); } catch (IOException e) { - fail("Unexpected IOException"); + fail("Unexpected IOException with input " + dnsNameString + ": " + + e.getMessage()); } } - @Test(dataProvider = "badNames") - public void testBadDNSName(String dnsNameString) { + private static void testBadDNSName(String dnsNameString) { try { DNSName dn = new DNSName(dnsNameString); - fail("IOException expected"); + fail("IOException expected with input " + dnsNameString); } catch (IOException e) { - if (!e.getMessage().contains("DNSName")) + if (!e.getMessage().contains("DNSName")) { fail("Unexpected message: " + e); + } } } - @Test(dataProvider = "badSanNames") - public void testBadSanDNSName(String dnsNameString) { + private static void testBadSanDNSName(String dnsNameString) { try { DNSName dn = new DNSName(dnsNameString, true); - fail("IOException expected"); + fail("IOException expected with input " + dnsNameString); } catch (IOException e) { - if (!e.getMessage().contains("DNSName")) + if (!e.getMessage().contains("DNSName")) { fail("Unexpected message: " + e); + } } } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/security/x509/IPAddressName/ConstrainsTest.java openjdk-25-25.0.5+8/test/jdk/sun/security/x509/IPAddressName/ConstrainsTest.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/security/x509/IPAddressName/ConstrainsTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/security/x509/IPAddressName/ConstrainsTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -21,58 +21,88 @@ * questions. */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import sun.security.x509.GeneralNameInterface; -import sun.security.x509.IPAddressName; +import static jdk.test.lib.Asserts.assertEquals; +import static sun.security.x509.GeneralNameInterface.NAME_MATCH; +import static sun.security.x509.GeneralNameInterface.NAME_NARROWS; +import static sun.security.x509.GeneralNameInterface.NAME_SAME_TYPE; +import static sun.security.x509.GeneralNameInterface.NAME_WIDENS; import java.io.IOException; - -import static org.testng.Assert.assertEquals; +import java.util.List; +import sun.security.x509.IPAddressName; /* * @test * @summary Verify IPAddressName.constrains * @bug 8267617 + * @library /test/lib * @modules java.base/sun.security.x509 - * @run testng ConstrainsTest */ + public class ConstrainsTest { IPAddressName ipv4Addr = new IPAddressName("127.0.0.1"); IPAddressName ipv4Mask = new IPAddressName("127.0.0.0/255.0.0.0"); - IPAddressName ipv6Addr = new IPAddressName("::1"); - IPAddressName ipv6Mask = new IPAddressName("::/0"); + IPAddressName ipv6Addr = new IPAddressName("2001:db8::1"); + IPAddressName ipv6Mask = new IPAddressName("2001:db8::/124"); + + IPAddressName ipv4Addr2 = new IPAddressName("128.0.0.1"); + IPAddressName ipv4NarrowMask = new IPAddressName("127.0.0.0/255.255.0.0"); + IPAddressName ipv4DisjointMask = new IPAddressName("128.0.0.0/255.0.0.0"); + + IPAddressName ipv6Addr2 = new IPAddressName("2001:db8:1::1"); + IPAddressName ipv6NarrowMask = new IPAddressName("2001:db8::/125"); + IPAddressName ipv6DisjointMask = new IPAddressName("2001:db8:1::/124"); public ConstrainsTest() throws IOException { } - @DataProvider(name = "names") - public Object[][] names() { - Object[][] data = { - {ipv4Addr, ipv4Addr, GeneralNameInterface.NAME_MATCH}, - {ipv4Addr, ipv4Mask, GeneralNameInterface.NAME_WIDENS}, - {ipv4Addr, ipv6Addr, GeneralNameInterface.NAME_SAME_TYPE}, - {ipv4Addr, ipv6Mask, GeneralNameInterface.NAME_SAME_TYPE}, - {ipv4Mask, ipv4Addr, GeneralNameInterface.NAME_NARROWS}, - {ipv4Mask, ipv4Mask, GeneralNameInterface.NAME_MATCH}, - {ipv4Mask, ipv6Addr, GeneralNameInterface.NAME_SAME_TYPE}, - {ipv4Mask, ipv6Mask, GeneralNameInterface.NAME_SAME_TYPE}, - {ipv6Addr, ipv4Addr, GeneralNameInterface.NAME_SAME_TYPE}, - {ipv6Addr, ipv4Mask, GeneralNameInterface.NAME_SAME_TYPE}, - {ipv6Addr, ipv6Addr, GeneralNameInterface.NAME_MATCH}, - {ipv6Addr, ipv6Mask, GeneralNameInterface.NAME_WIDENS}, - {ipv6Mask, ipv4Addr, GeneralNameInterface.NAME_SAME_TYPE}, - {ipv6Mask, ipv4Mask, GeneralNameInterface.NAME_SAME_TYPE}, - {ipv6Mask, ipv6Addr, GeneralNameInterface.NAME_NARROWS}, - {ipv6Mask, ipv6Mask, GeneralNameInterface.NAME_MATCH}, - }; - return data; + private Object[][] names() { + return new Object[][]{ + // Basic matching + {ipv4Addr, ipv4Addr, NAME_MATCH}, + {ipv4Addr, ipv4Mask, NAME_WIDENS}, + {ipv4Addr, ipv6Addr, NAME_SAME_TYPE}, + {ipv4Addr, ipv6Mask, NAME_SAME_TYPE}, + {ipv4Mask, ipv4Addr, NAME_NARROWS}, + {ipv4Mask, ipv4Mask, NAME_MATCH}, + {ipv4Mask, ipv6Addr, NAME_SAME_TYPE}, + {ipv4Mask, ipv6Mask, NAME_SAME_TYPE}, + {ipv6Addr, ipv4Addr, NAME_SAME_TYPE}, + {ipv6Addr, ipv4Mask, NAME_SAME_TYPE}, + {ipv6Addr, ipv6Addr, NAME_MATCH}, + {ipv6Addr, ipv6Mask, NAME_WIDENS}, + {ipv6Mask, ipv4Addr, NAME_SAME_TYPE}, + {ipv6Mask, ipv4Mask, NAME_SAME_TYPE}, + {ipv6Mask, ipv6Addr, NAME_NARROWS}, + {ipv6Mask, ipv6Mask, NAME_MATCH}, + + // Same-family host mismatches + {ipv4Addr, ipv4Addr2, NAME_SAME_TYPE}, + {ipv6Addr, ipv6Addr2, NAME_SAME_TYPE}, + + // Host to subnet match, nothing matches + {ipv4Addr2, ipv4Mask, NAME_SAME_TYPE}, + {ipv6Addr2, ipv6Mask, NAME_SAME_TYPE}, + + // Subnet to subnet match: narrow/widen/disjoint + {ipv4Mask, ipv4NarrowMask, NAME_NARROWS}, + {ipv4NarrowMask, ipv4Mask, NAME_WIDENS}, + {ipv4Mask, ipv4DisjointMask, NAME_SAME_TYPE}, + + {ipv6Mask, ipv6NarrowMask, NAME_NARROWS}, + {ipv6NarrowMask, ipv6Mask, NAME_WIDENS}, + {ipv6Mask, ipv6DisjointMask, NAME_SAME_TYPE}, + }; } - @Test(dataProvider = "names") - public void testNameContains(IPAddressName addr1, IPAddressName addr2, int result) throws IOException { - assertEquals(addr1.constrains(addr2), result); + public static void main(String[] args) throws Exception { + List.of(new ConstrainsTest().names()).forEach(v -> testNameContains( + (IPAddressName) v[0], (IPAddressName) v[1], (int) v[2])); } + private static void testNameContains(IPAddressName addr1, + IPAddressName addr2, int result) { + assertEquals(addr1.constrains(addr2), result); + } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcCapacityOutput1.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcCapacityOutput1.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcCapacityOutput1.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcCapacityOutput1.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatGcCapacityOutput1.sh # @summary Test that output of 'jstat -gccapacity 0' has expected line counts diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcMetaCapacityOutput1.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcMetaCapacityOutput1.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcMetaCapacityOutput1.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcMetaCapacityOutput1.sh 2026-10-19 12:10:20.000000000 +0000 @@ -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,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatGcMetaCapacityOutput1.sh # @summary Test that output of 'jstat -gcmetacapacity 0' has expected line counts diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcNewCapacityOutput1.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcNewCapacityOutput1.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcNewCapacityOutput1.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcNewCapacityOutput1.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatGcNewCapacityOutput1.sh # @summary Test that output of 'jstat -gcnewcapacity 0' has expected line counts diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcNewOutput1.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcNewOutput1.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcNewOutput1.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcNewOutput1.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatGcNewOutput1.sh # @summary Test that output of 'jstat -gcnew 0' has expected line counts diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcOldCapacityOutput1.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcOldCapacityOutput1.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcOldCapacityOutput1.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcOldCapacityOutput1.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,9 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatGcOldCapacityOutput1.sh -# @summary Test that output of 'jstat -gcoldcapcaity 0' has expected line counts +# @summary Test that output of 'jstat -gcoldcapacity 0' has expected line counts . ${TESTSRC-.}/../../jvmstat/testlibrary/utils.sh diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcOldOutput1.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcOldOutput1.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcOldOutput1.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcOldOutput1.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatGcOldOutput1.sh # @summary Test that output of 'jstat -gcold 0' has expected line counts diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcOutput1.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcOutput1.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatGcOutput1.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatGcOutput1.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatGcOutput1.sh # @summary Test that output of 'jstat -gc 0' has expected line counts diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatLineCounts1.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts1.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatLineCounts1.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts1.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatLineCounts1.sh # @summary Test that output of 'jstat -gcutil 0 250 5' has expected line counts diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatLineCounts2.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts2.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatLineCounts2.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts2.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatLineCounts2.sh # @summary Test that output of 'jstat -gcutil 0' has expected line counts diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatLineCounts3.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts3.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatLineCounts3.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts3.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatLineCounts3.sh # @summary Test that output of 'jstat -gcutil -h 10 250 10' has expected line counts diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatLineCounts4.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts4.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatLineCounts4.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatLineCounts4.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatLineCounts4.sh # @summary Test that output of 'jstat -gcutil -h 10 250 11' has expected line counts diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatTimeStamp1.sh openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatTimeStamp1.sh --- openjdk-25-25.0.4.1+1/test/jdk/sun/tools/jstat/jstatTimeStamp1.sh 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/tools/jstat/jstatTimeStamp1.sh 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ # @test # @bug 4990825 +# @requires vm.gc.Parallel # @run shell jstatTimeStamp1.sh # @summary Test that output of 'jstat -gcutil -t 0' has expected format diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/util/resources/TimeZone/Bug8139107.java openjdk-25-25.0.5+8/test/jdk/sun/util/resources/TimeZone/Bug8139107.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/util/resources/TimeZone/Bug8139107.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/util/resources/TimeZone/Bug8139107.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -27,11 +27,12 @@ * @summary Test that date parsing with DateTimeFormatter pattern * that contains timezone field doesn't trigger NPE. All supported * locales are tested. - * @run testng Bug8139107 + * @run junit Bug8139107 */ import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.testng.annotations.Test; + +import org.junit.jupiter.api.Test; public class Bug8139107 { diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java openjdk-25-25.0.5+8/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -26,7 +26,7 @@ * @bug 8275721 8174269 * @modules jdk.localedata * @summary Checks Chinese time zone names for `UTC` using CLDR are consistent - * @run testng ChineseTimeZoneNameTest + * @run junit ChineseTimeZoneNameTest */ import java.time.Instant; @@ -35,11 +35,10 @@ import java.time.format.DateTimeFormatter; import java.util.Locale; -import static org.testng.Assert.assertEquals; -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 public class ChineseTimeZoneNameTest { private static final Locale SIMPLIFIED_CHINESE = Locale.forLanguageTag("zh-Hans"); @@ -47,8 +46,7 @@ private static final ZonedDateTime EPOCH_UTC = ZonedDateTime.ofInstant(Instant.ofEpochSecond (0), ZoneId.of ("UTC")); - @DataProvider(name="locales") - Object[][] data() { + private static Object[][] data() { return new Object[][] { {Locale.CHINESE, SIMPLIFIED_CHINESE}, {Locale.SIMPLIFIED_CHINESE, SIMPLIFIED_CHINESE}, @@ -61,11 +59,12 @@ }; } - @Test(dataProvider="locales") + @ParameterizedTest + @MethodSource("data") public void test_ChineseTimeZoneNames(Locale testLoc, Locale resourceLoc) { - assertEquals(DateTimeFormatter.ofPattern("z", testLoc).format(EPOCH_UTC), - DateTimeFormatter.ofPattern("z", resourceLoc).format(EPOCH_UTC)); - assertEquals(DateTimeFormatter.ofPattern("zzzz", testLoc).format(EPOCH_UTC), - DateTimeFormatter.ofPattern("zzzz", resourceLoc).format(EPOCH_UTC)); + assertEquals(DateTimeFormatter.ofPattern("z", resourceLoc).format(EPOCH_UTC), + DateTimeFormatter.ofPattern("z", testLoc).format(EPOCH_UTC)); + assertEquals(DateTimeFormatter.ofPattern("zzzz", resourceLoc).format(EPOCH_UTC), + DateTimeFormatter.ofPattern("zzzz", testLoc).format(EPOCH_UTC)); } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/util/resources/cldr/Bug8202764.java openjdk-25-25.0.5+8/test/jdk/sun/util/resources/cldr/Bug8202764.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/util/resources/cldr/Bug8202764.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/util/resources/cldr/Bug8202764.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -28,11 +28,9 @@ * @summary Checks time zone names are consistent with aliased ids, * between DateFormatSymbols.getZoneStrings() and getDisplayName() * of TimeZone/ZoneId classes - * @run testng/othervm Bug8202764 + * @run junit/othervm Bug8202764 */ -import static org.testng.Assert.assertEquals; - import java.time.ZoneId; import java.time.format.TextStyle; import java.text.DateFormatSymbols; @@ -41,7 +39,8 @@ import java.util.Set; import java.util.TimeZone; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; public class Bug8202764 { @@ -53,15 +52,15 @@ .forEach(zone -> { System.out.println(zone[0]); TimeZone tz = TimeZone.getTimeZone(zone[0]); - assertEquals(zone[1], tz.getDisplayName(false, TimeZone.LONG, Locale.US)); - assertEquals(zone[2], tz.getDisplayName(false, TimeZone.SHORT, Locale.US)); - assertEquals(zone[3], tz.getDisplayName(true, TimeZone.LONG, Locale.US)); - assertEquals(zone[4], tz.getDisplayName(true, TimeZone.SHORT, Locale.US)); + assertEquals(tz.getDisplayName(false, TimeZone.LONG, Locale.US), zone[1]); + assertEquals(tz.getDisplayName(false, TimeZone.SHORT, Locale.US), zone[2]); + assertEquals(tz.getDisplayName(true, TimeZone.LONG, Locale.US), zone[3]); + assertEquals(tz.getDisplayName(true, TimeZone.SHORT, Locale.US), zone[4]); if (zoneIds.contains(zone[0])) { // Some of the ids, e.g. three-letter ids are not supported in ZoneId ZoneId zi = tz.toZoneId(); - assertEquals(zone[5], zi.getDisplayName(TextStyle.FULL, Locale.US)); - assertEquals(zone[6], zi.getDisplayName(TextStyle.SHORT, Locale.US)); + assertEquals(zi.getDisplayName(TextStyle.FULL, Locale.US), zone[5]); + assertEquals(zi.getDisplayName(TextStyle.SHORT, Locale.US), zone[6]); } }); } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java openjdk-25-25.0.5+8/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java --- openjdk-25-25.0.4.1+1/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -24,31 +24,36 @@ /* * @test * @bug 8181157 8202537 8234347 8236548 8261279 8322647 8174269 8346948 - * 8382020 8384043 + * 8381379 8382020 8384043 8390388 8390380 8392519 8392377 8393344 8393337 * @modules jdk.localedata * @summary Checks CLDR time zone names are generated correctly at * either build or runtime - * @run testng TimeZoneNamesTest + * @run junit TimeZoneNamesTest */ import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.time.format.TextStyle; import java.util.Arrays; +import java.util.Date; import java.util.Locale; import java.util.Objects; import java.util.TimeZone; +import java.util.stream.Stream; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; -@Test public class TimeZoneNamesTest { - @DataProvider - Object[][] sampleTZs() { + private static Object[][] sampleTZs() { return new Object[][] { // tzid, locale, style, expected @@ -264,20 +269,35 @@ }; } + private static Stream explicitDstOffsets() { + return Stream.of( + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("Europe/Dublin")), "Irish Standard Time"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("Europe/Dublin")), "Greenwich Mean Time"), + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("Eire")), "Irish Standard Time"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("Eire")), "Greenwich Mean Time"), + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("America/Vancouver")), "Pacific Daylight Time"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("America/Vancouver")), "Pacific Daylight Time"), + Arguments.of(ZonedDateTime.of(2026, 1, 5, 0, 0, 0, 0, ZoneId.of("America/Edmonton")), "Mountain Standard Time"), + Arguments.of(ZonedDateTime.of(2026, 7, 5, 0, 0, 0, 0, ZoneId.of("America/Edmonton")), "Mountain Daylight Time"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("America/Inuvik")), "Mountain Daylight Time"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("America/Winnipeg")), "Central Daylight Time") + ); + } - @Test(dataProvider="sampleTZs") + @ParameterizedTest + @MethodSource("sampleTZs") public void test_tzNames(String tzid, Locale locale, String lstd, String sstd, String ldst, String sdst, String lgen, String sgen) { // Standard time - assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.LONG, locale), lstd); - assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.SHORT, locale), sstd); + assertEquals(lstd, TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.LONG, locale)); + assertEquals(sstd, TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.SHORT, locale)); // daylight saving time - assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(true, TimeZone.LONG, locale), ldst); - assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(true, TimeZone.SHORT, locale), sdst); + assertEquals(ldst, TimeZone.getTimeZone(tzid).getDisplayName(true, TimeZone.LONG, locale)); + assertEquals(sdst, TimeZone.getTimeZone(tzid).getDisplayName(true, TimeZone.SHORT, locale)); // generic name - assertEquals(ZoneId.of(tzid).getDisplayName(TextStyle.FULL, locale), lgen); - assertEquals(ZoneId.of(tzid).getDisplayName(TextStyle.SHORT, locale), sgen); + assertEquals(lgen, ZoneId.of(tzid).getDisplayName(TextStyle.FULL, locale)); + assertEquals(sgen, ZoneId.of(tzid).getDisplayName(TextStyle.SHORT, locale)); } // Make sure getZoneStrings() returns non-empty string array @@ -294,4 +314,19 @@ .anyMatch(name -> Objects.isNull(name) || name.isEmpty()), "getZoneStrings() returned array containing non-empty string element(s)"); } + + // Explicit metazone dst offset test. As of CLDR v48, only Europe/Dublin utilizes + // this attribute, but will be used for America/Vancouver once CLDR adopts the + // explicit offset for that zone, which warrants the test data modification. + @ParameterizedTest + @MethodSource("explicitDstOffsets") + public void test_ExplicitMetazoneOffsets(ZonedDateTime zdt, String expected) { + // java.time + assertEquals(expected, DateTimeFormatter.ofPattern("zzzz").format(zdt)); + + // java.text/util + var sdf = new SimpleDateFormat("zzzz"); + sdf.setTimeZone(TimeZone.getTimeZone(zdt.getZone())); + assertEquals(expected, sdf.format(Date.from(zdt.toInstant()))); + } } diff -Nru openjdk-25-25.0.4.1+1/test/jdk/tools/jar/JarExtractTest.java openjdk-25-25.0.5+8/test/jdk/tools/jar/JarExtractTest.java --- openjdk-25-25.0.4.1+1/test/jdk/tools/jar/JarExtractTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/tools/jar/JarExtractTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, 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 @@ -26,8 +26,11 @@ import java.io.IOException; import java.io.PrintStream; import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -65,12 +68,12 @@ private static final byte[] FILE_CONTENT = "Hello world!!!".getBytes(StandardCharsets.UTF_8); // the jar that will get extracted in the tests private Path testJarPath; - private static Collection filesToDelete = new ArrayList<>(); + private static final Collection filesToDelete = new ArrayList<>(); @BeforeEach public void createTestJar() throws Exception { - final String tmpDir = Files.createTempDirectory("8173970-").toString(); - testJarPath = Path.of(tmpDir, "8173970-test.jar"); + final Path tmpDir = Files.createTempDirectory(Path.of("."), "8173970-"); + testJarPath = tmpDir.resolve("8173970-test.jar"); final JarBuilder builder = new JarBuilder(testJarPath.toString()); // d1 // |--- d2 @@ -273,22 +276,34 @@ * Tests that extracting a jar using {@code -P} flag and without any explicit destination * directory works correctly if the jar contains entries with leading slashes and/or {@code ..} * parts preserved. + * The test creates a JAR file with an entry which has a leading slash in its name and + * another entry that has ".." in its entry name. jar tool is then used to extract that JAR file + * with the "-P" option which is to preserve leading '/' (absolute path) + * and ".." (parent directory) components when extracting those entries. This test then verifies + * that after successfully extracting that JAR file, these entries are present at the expected + * paths on the filesystem. */ @Test public void testExtractNoDestDirWithPFlag() throws Exception { - // run this test only on those systems where "/tmp" directory is available and we - // can write to it + // This test requires that the entry in the JAR file have a leading slash, which + // upon extraction of that JAR file will correspond to a filesystem path. Not all + // environments may have a writable location that starts with "/". "/tmp" is one + // commonly available filesystem directory which is usually writable. Here we check the + // presence of "/tmp" directory and verify that files can be created in that directory. + // If we can't, then we skip this test. Assumptions.assumeTrue(Files.isDirectory(Path.of("/tmp")), "skipping test, since /tmp isn't a directory"); - // try and write into "/tmp" - final Path tmpDir; + final Path tempTestDir; try { - tmpDir = Files.createTempDirectory(Path.of("/tmp"), "8173970-").toAbsolutePath(); + // create a test specific directory in "/tmp" directory + tempTestDir = Files.createTempDirectory(Path.of("/tmp"), "8173970-"); } catch (IOException ioe) { Assumptions.abort("skipping test, since /tmp cannot be written to: " + ioe); + // The above Assumptions.abort(...) call makes this "return" unreachable, but we keep + // the "return" for code clarity. return; } - final String leadingSlashEntryName = tmpDir.toString() + "/foo/f1.txt"; + final String leadingSlashEntryName = tempTestDir.toString() + "/foo/f1.txt"; // create a jar which has leading slash (/) and dot-dot (..) preserved in entry names final Path jarPath = createJarWithPFlagSemantics(leadingSlashEntryName); final List cmdArgs = new ArrayList<>(); @@ -315,8 +330,9 @@ "Unexpected content in file " + f2); } } finally { - // clean up the file that might have been extracted into "/tmp/...." directory - Files.deleteIfExists(Path.of(leadingSlashEntryName)); + // clean up the temp directory created by this test under "/tmp/...." directory + System.err.println("Deleting directory: " + tempTestDir); + deleteRecursively(tempTestDir); } } @@ -514,4 +530,26 @@ private static void printJarCommand(final String[] cmdArgs) { System.out.println("Running 'jar " + String.join(" ", cmdArgs) + "'"); } -} \ No newline at end of file + + private static void deleteRecursively(final Path dir) throws IOException { + Files.walkFileTree(dir, new FileVisitor<>() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + return FileVisitResult.CONTINUE; + } + @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + Files.delete(file); // delete the file + return FileVisitResult.CONTINUE; + } + @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { + return FileVisitResult.CONTINUE; + } + @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) + throws IOException { + Files.delete(dir); // delete the (empty) directory + return FileVisitResult.CONTINUE; + } + }); + } +} diff -Nru openjdk-25-25.0.4.1+1/test/jdk/tools/jlink/plugins/DefaultStripDebugPluginTest.java openjdk-25-25.0.5+8/test/jdk/tools/jlink/plugins/DefaultStripDebugPluginTest.java --- openjdk-25-25.0.4.1+1/test/jdk/tools/jlink/plugins/DefaultStripDebugPluginTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/tools/jlink/plugins/DefaultStripDebugPluginTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -73,10 +73,48 @@ } } + // Disable embedded strip Java plugin, with native plugin present. + public void testOnlyNativePlugin() { + MockStripPlugin javaPlugin = new MockStripPlugin(false); + MockStripPlugin nativePlugin = new MockStripPlugin(true); + TestNativeStripPluginFactory nativeFactory = + new TestNativeStripPluginFactory(nativePlugin); + DefaultStripDebugPlugin plugin = new DefaultStripDebugPlugin(javaPlugin, + nativeFactory); + plugin.enableJavaStripPlugin(false); + + ResourcePoolManager inManager = new ResourcePoolManager(); + ResourcePool pool = plugin.transform(inManager.resourcePool(), + inManager.resourcePoolBuilder()); + if (pool.findEntry(MockStripPlugin.JAVA_PATH).isPresent() || + !pool.findEntry(MockStripPlugin.NATIVE_PATH).isPresent()) { + throw new AssertionError("Expected only native to get called"); + } + } + + // Disable embedded strip Java plugin, and without native plugin present. + public void testNoOperation() { + MockStripPlugin javaPlugin = new MockStripPlugin(false); + TestNativeStripPluginFactory nativeFactory = + new TestNativeStripPluginFactory(null); + DefaultStripDebugPlugin plugin = new DefaultStripDebugPlugin(javaPlugin, + nativeFactory); + plugin.enableJavaStripPlugin(false); + ResourcePoolManager inManager = new ResourcePoolManager(); + ResourcePool pool = plugin.transform(inManager.resourcePool(), + inManager.resourcePoolBuilder()); + if (pool.findEntry(MockStripPlugin.JAVA_PATH).isPresent() || + pool.findEntry(MockStripPlugin.NATIVE_PATH).isPresent()) { + throw new AssertionError("Expected both native and java not called"); + } + } + public static void main(String[] args) { DefaultStripDebugPluginTest test = new DefaultStripDebugPluginTest(); test.testNoNativeStripPluginPresent(); test.testWithNativeStripPresent(); + test.testOnlyNativePlugin(); + test.testNoOperation(); } public static class MockStripPlugin implements Plugin { diff -Nru openjdk-25-25.0.4.1+1/test/jdk/tools/jlink/plugins/StripParameterNamesTest.java openjdk-25-25.0.5+8/test/jdk/tools/jlink/plugins/StripParameterNamesTest.java --- openjdk-25-25.0.4.1+1/test/jdk/tools/jlink/plugins/StripParameterNamesTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/jdk/tools/jlink/plugins/StripParameterNamesTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.FieldSource; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Stream; +import java.util.spi.ToolProvider; + +import jdk.test.lib.util.FileUtils; +import tests.JImageGenerator; +import tests.JImageGenerator.InMemorySourceFile; +import tests.Result; + +/* + * @test + * @summary Test jlink strip debug plugins handle method parameter names. + * @bug 8347007 + * @library ../../lib + * @library /test/lib + * @modules java.base/jdk.internal.jimage + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.plugin + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build jdk.test.lib.util.FileUtils + * tests.* + * @run junit/othervm StripParameterNamesTest + */ +public class StripParameterNamesTest { + private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") + .orElseThrow(() -> new RuntimeException("javac tool not found")); + + private static Path src = Path.of("src").toAbsolutePath(); + private static List testJmods = new ArrayList<>(); + + record Jmod(Path moduleDir, boolean withDebugInfo, boolean withParameterNames) {} + + @BeforeAll + public static void setup() throws IOException { + Files.createDirectory(src); + var mainClassSource = new InMemorySourceFile("test", "InspectParameterNames", """ + package test; + + public class InspectParameterNames { + int add(int a, int b) { + return a + b; + } + + public static boolean hasParameterNames() throws NoSuchMethodException { + // Get add method in the class + var method = InspectParameterNames.class.getDeclaredMethod("add", int.class, int.class); + + // Get method parameters + var parameters = method.getParameters(); + + // validate parameter names + return parameters[0].getName().equals("a") && parameters[1].getName().equals("b"); + } + + public static void main(String[] args) throws NoSuchMethodException { + System.out.println(hasParameterNames()); + } + } + """); + var moduleDir = JImageGenerator.generateSources(src, "bug8347007x", List.of(mainClassSource)); + JImageGenerator.generateModuleInfo(moduleDir, List.of("test")); + testJmods.add(buildJmod(true, true)); + testJmods.add(buildJmod(true, false)); + testJmods.add(buildJmod(false, true)); + testJmods.add(buildJmod(false, false)); + } + + @AfterEach + public void cleanup() throws IOException { + FileUtils.deleteFileTreeWithRetry(Path.of("img")); + } + + static void report(String command, List args) { + System.out.println(command + " " + String.join(" ", args)); + } + + static void javac(List args) { + report("javac", args); + JAVAC_TOOL.run(System.out, System.err, args.toArray(new String[0])); + } + + /** + * Build jmods from the module source path + */ + static Jmod buildJmod(boolean withDebugInfo, boolean withParameterNames) { + String dirName = "jmods"; + List options = new ArrayList<>(); + + if (withDebugInfo) { + options.add("-g"); + dirName += "g"; + } + + if (withParameterNames) { + options.add("-parameters"); + dirName += "p"; + } + + Path moduleDir = Path.of(dirName).toAbsolutePath(); + + options.add("-d"); + options.add(moduleDir.toString()); + options.add("--module-source-path"); + options.add(src.toString()); + options.add("--module"); + options.add("bug8347007x"); + + javac(options); + return new Jmod(moduleDir, withDebugInfo, withParameterNames); + } + + Result buildImage(Path modulePath, Path imageDir, String... options) { + var jlinkTask = JImageGenerator.getJLinkTask() + .modulePath(modulePath.toString()) + .output(imageDir); + + for (var option: options) { + jlinkTask.option(option); + } + + return jlinkTask.addMods("bug8347007x") + .call(); + } + + void assertHasParameterNames(Path imageDir, boolean expected) throws IOException, InterruptedException { + Path binDir = imageDir.resolve("bin").toAbsolutePath(); + Path bin = binDir.resolve("java"); + + ProcessBuilder processBuilder = new ProcessBuilder(bin.toString(), + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+BytecodeVerificationLocal", + "-m", "bug8347007x/test.InspectParameterNames"); + processBuilder.directory(binDir.toFile()); + Process process = processBuilder.start(); + int exitCode = process.waitFor(); + var output = process.inputReader().readLine(); + System.out.println(output); + assertEquals(expected, Boolean.parseBoolean(output)); + } + + Stream provideTestJmods() { + return testJmods.stream(); + } + + @ParameterizedTest + @FieldSource("testJmods") + public void testDefaultBehavior(Jmod jmod) throws Exception { + var imageDir = Path.of("img"); + buildImage(jmod.moduleDir(), imageDir) + .assertSuccess(); + var hasParameter = jmod.withParameterNames(); + assertHasParameterNames(imageDir, hasParameter); + } + + @ParameterizedTest + @FieldSource("testJmods") + public void testStripDebug(Jmod jmod) throws Exception { + var imageDir = Path.of("img"); + buildImage(jmod.moduleDir(), imageDir, + "--strip-debug") + .assertSuccess(); + var hasParameter = jmod.withParameterNames(); + assertHasParameterNames(imageDir, hasParameter); + } + + @Test + public void testBothStripOptions() throws Exception { + var imageDir = Path.of("img"); + var jmod = testJmods.get(0); + buildImage(jmod.moduleDir(), imageDir, + "--strip-debug", "--strip-java-debug-attributes") + .assertSuccess(); + assertHasParameterNames(imageDir, jmod.withParameterNames()); + } + + @ParameterizedTest + @FieldSource("testJmods") + public void testOnlyStripJavaDebugAttributes() throws Exception { + var imageDir = Path.of("img"); + var jmod = testJmods.get(0); + buildImage(jmod.moduleDir(), imageDir, + "--strip-java-debug-attributes") + .assertSuccess(); + assertHasParameterNames(imageDir, jmod.withParameterNames()); + } +} \ No newline at end of file diff -Nru openjdk-25-25.0.4.1+1/test/langtools/TEST.ROOT openjdk-25-25.0.5+8/test/langtools/TEST.ROOT --- openjdk-25-25.0.4.1+1/test/langtools/TEST.ROOT 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/langtools/TEST.ROOT 2026-10-19 12:10:20.000000000 +0000 @@ -15,7 +15,7 @@ groups=TEST.groups # Minimum jtreg version -requiredVersion=8+2 +requiredVersion=8.2.1+1 # Use new module options useNewOptions=true diff -Nru openjdk-25-25.0.4.1+1/test/langtools/jdk/jshell/LocalExecutionInstrumentationCHRTest.java openjdk-25-25.0.5+8/test/langtools/jdk/jshell/LocalExecutionInstrumentationCHRTest.java --- openjdk-25-25.0.4.1+1/test/langtools/jdk/jshell/LocalExecutionInstrumentationCHRTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/langtools/jdk/jshell/LocalExecutionInstrumentationCHRTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8366926 + * @summary Verify the instrumenation class hierarchy resolution works properly in local execution mode + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build KullaTesting + * @run junit/othervm LocalExecutionInstrumentationCHRTest + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class LocalExecutionInstrumentationCHRTest extends ReplToolTesting { + + @Test + public void verifyMyClassFoundOnClassPath() { + test(new String[] { "--execution", "local" }, + a -> assertCommand(a, "public interface TestInterface {}", "| created interface TestInterface"), + a -> assertCommand(a, + "public class TestClass {" + + "public TestInterface foo(boolean b) {" + + "TestInterface test; " + + "if (b) {" + + "test = new TestInterfaceImpl1();" + + "} else {" + + "test = new TestInterfaceImpl2();" + + "}" + + "return test;" + + "}" + + "private class TestInterfaceImpl1 implements TestInterface {}" + + "private class TestInterfaceImpl2 implements TestInterface {}" + + "}", "| created class TestClass"), + a -> assertCommand(a, "new TestClass().foo(true).getClass();", "$3 ==> class TestClass$TestInterfaceImpl1"), + a -> assertCommand(a, "new TestClass().foo(false).getClass();", "$4 ==> class TestClass$TestInterfaceImpl2") + ); + } +} diff -Nru openjdk-25-25.0.4.1+1/test/langtools/jdk/jshell/RemoteAgentHandshakeTest.java openjdk-25-25.0.5+8/test/langtools/jdk/jshell/RemoteAgentHandshakeTest.java --- openjdk-25-25.0.4.1+1/test/langtools/jdk/jshell/RemoteAgentHandshakeTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/langtools/jdk/jshell/RemoteAgentHandshakeTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test 8384736 + * @summary Verify the correct handshake is used for remote agents. + * @run junit RemoteAgentHandshakeTest + */ + +import java.time.Duration; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import jdk.jfr.consumer.RecordingStream; +import jdk.jshell.JShell; +import jdk.jshell.execution.JdiExecutionControlProvider; +import jdk.jshell.execution.RemoteExecutionControl; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class RemoteAgentHandshakeTest { + + @Test + public void testCustomAgentOldHandshake() throws Exception { + assertThrows(IllegalStateException.class, () -> { + try (JShell jshell = + JShell.builder() + .executionEngine(new JdiExecutionControlProvider(), + Map.of(JdiExecutionControlProvider.PARAM_REMOTE_AGENT, + OldHandShake.class.getName())) + .remoteVMOptions("-classpath", System.getProperty("test.classes")) + .build()) { + jshell.eval("1"); + } + }); + } + + @Test + public void testCustomAgentNewHandshake() throws Exception { + try (JShell jshell = + JShell.builder() + .executionEngine(new JdiExecutionControlProvider(), + Map.of(JdiExecutionControlProvider.PARAM_REMOTE_AGENT, + NewHandShake.class.getName())) + .remoteVMOptions("-classpath", System.getProperty("test.classes")) + .build()) { + jshell.eval("1"); + } + } + + @Test + public void testDefaultAgentUsesNewHandshake() throws Exception { + try (var rs = new RecordingStream()) { + rs.enable("jdk.ProcessStart"); + rs.enable("jdk.CPULoad").withPeriod(Duration.ofMillis(10)); + + CompletableFuture command = new CompletableFuture<>(); + + rs.onEvent("jdk.ProcessStart", evt -> { + String commandLine = evt.getValue("command"); + + if (commandLine.contains("RemoteExecutionControl")) { + command.complete(commandLine); + } + }); + + CountDownLatch running = new CountDownLatch(1); + + rs.onEvent("jdk.CPULoad", evt -> { + running.countDown(); + }); + + rs.startAsync(); + + running.await(); + + try (JShell jshell = JShell.create()) { + jshell.eval("1"); + } + + String commandLine = command.get(10, TimeUnit.SECONDS); + if (!commandLine.endsWith(" -1")) { + throw new AssertionError("Does not contain a correct port: '" + commandLine + "'"); + } + } + } + + public static class OldHandShake extends RemoteExecutionControl { + public static void main(String[] args) throws Exception { + if (Integer.parseInt(args[0]) <= 0) { + throw new AssertionError("Unexpected port number!"); + } + + RemoteExecutionControl.main(args); + } + } + + public static class NewHandShake extends RemoteExecutionControl { + public static void main(String[] args) throws Exception { + if (Integer.parseInt(args[0]) != (-1)) { + throw new AssertionError("Unexpected port number!"); + } + + RemoteExecutionControl.main(args); + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java openjdk-25-25.0.5+8/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java --- openjdk-25-25.0.4.1+1/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -37,6 +37,7 @@ import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControl.ExecutionControlException; import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -63,8 +64,8 @@ @Test public void testExtension() throws ExecutionControlException { assertEval("42;"); - Object res = currentEC.extensionCommand("FROG", "test"); - assertEquals("ribbit", res); + Assertions.assertThrows(ExecutionControl.NotImplementedException.class, + () -> currentEC.extensionCommand("FROG", "test")); } @Test diff -Nru openjdk-25-25.0.4.1+1/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.java openjdk-25-25.0.5+8/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.java --- openjdk-25-25.0.4.1+1/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,6 @@ /** * @test /nodynamiccopyright/ + * @bug 8375571 * @summary Verify error reports for erroneous deconstruction patterns are sensible * @compile/fail/ref=DeconstructionPatternErrors.out -XDrawDiagnostics -XDshould-stop.at=FLOW -XDdev DeconstructionPatternErrors.java */ @@ -39,6 +40,10 @@ boolean b = p instanceof P(int i) p; //introducing a variable for the record pattern } + void typeVarTest(T p) { + if (p instanceof T(int i) && i == 0); //T is a type variable + } + public record P(int i) { } diff -Nru openjdk-25-25.0.4.1+1/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.out openjdk-25-25.0.5+8/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.out --- openjdk-25-25.0.4.1+1/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.out 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.out 2026-10-19 12:10:20.000000000 +0000 @@ -1,23 +1,24 @@ -DeconstructionPatternErrors.java:35:37: compiler.err.illegal.start.of.type -DeconstructionPatternErrors.java:37:28: compiler.err.illegal.start.of.type -DeconstructionPatternErrors.java:39:42: compiler.err.expected: ';' -DeconstructionPatternErrors.java:39:43: compiler.err.not.stmt -DeconstructionPatternErrors.java:15:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List, java.util.ArrayList) -DeconstructionPatternErrors.java:16:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, java.util.ArrayList -DeconstructionPatternErrors.java:17:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, int) -DeconstructionPatternErrors.java:18:28: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.String) -DeconstructionPatternErrors.java:19:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, DeconstructionPatternErrors.P) -DeconstructionPatternErrors.java:20:26: compiler.err.incorrect.number.of.nested.patterns: java.lang.Runnable,java.lang.Runnable, java.lang.Runnable +DeconstructionPatternErrors.java:36:37: compiler.err.illegal.start.of.type +DeconstructionPatternErrors.java:38:28: compiler.err.illegal.start.of.type +DeconstructionPatternErrors.java:40:42: compiler.err.expected: ';' +DeconstructionPatternErrors.java:40:43: compiler.err.not.stmt +DeconstructionPatternErrors.java:16:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List, java.util.ArrayList) +DeconstructionPatternErrors.java:17:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, java.util.ArrayList +DeconstructionPatternErrors.java:18:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, int) +DeconstructionPatternErrors.java:19:28: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.String) +DeconstructionPatternErrors.java:20:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, DeconstructionPatternErrors.P) DeconstructionPatternErrors.java:21:26: compiler.err.incorrect.number.of.nested.patterns: java.lang.Runnable,java.lang.Runnable, java.lang.Runnable -DeconstructionPatternErrors.java:22:26: compiler.err.incorrect.number.of.nested.patterns: int, int,compiler.misc.type.none -DeconstructionPatternErrors.java:23:26: compiler.err.incorrect.number.of.nested.patterns: int, int,int -DeconstructionPatternErrors.java:24:36: compiler.err.cant.resolve.location: kindname.class, Unresolvable, , , (compiler.misc.location: kindname.class, DeconstructionPatternErrors, null) -DeconstructionPatternErrors.java:24:26: compiler.err.incorrect.number.of.nested.patterns: int, int,Unresolvable -DeconstructionPatternErrors.java:25:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord -DeconstructionPatternErrors.java:26:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord -DeconstructionPatternErrors.java:27:44: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer) -DeconstructionPatternErrors.java:27:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord -DeconstructionPatternErrors.java:28:40: compiler.err.match.binding.exists -DeconstructionPatternErrors.java:29:56: compiler.err.already.defined: kindname.variable, v1, kindname.method, meth() -DeconstructionPatternErrors.java:29:64: compiler.err.already.defined: kindname.variable, v2, kindname.method, meth() -22 errors \ No newline at end of file +DeconstructionPatternErrors.java:22:26: compiler.err.incorrect.number.of.nested.patterns: java.lang.Runnable,java.lang.Runnable, java.lang.Runnable +DeconstructionPatternErrors.java:23:26: compiler.err.incorrect.number.of.nested.patterns: int, int,compiler.misc.type.none +DeconstructionPatternErrors.java:24:26: compiler.err.incorrect.number.of.nested.patterns: int, int,int +DeconstructionPatternErrors.java:25:36: compiler.err.cant.resolve.location: kindname.class, Unresolvable, , , (compiler.misc.location: kindname.class, DeconstructionPatternErrors, null) +DeconstructionPatternErrors.java:25:26: compiler.err.incorrect.number.of.nested.patterns: int, int,Unresolvable +DeconstructionPatternErrors.java:26:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord +DeconstructionPatternErrors.java:27:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord +DeconstructionPatternErrors.java:28:44: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer) +DeconstructionPatternErrors.java:28:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord +DeconstructionPatternErrors.java:29:40: compiler.err.match.binding.exists +DeconstructionPatternErrors.java:30:56: compiler.err.already.defined: kindname.variable, v1, kindname.method, meth() +DeconstructionPatternErrors.java:30:64: compiler.err.already.defined: kindname.variable, v2, kindname.method, meth() +DeconstructionPatternErrors.java:44:26: compiler.err.deconstruction.pattern.only.records: T +23 errors diff -Nru openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/Utils.java openjdk-25-25.0.5+8/test/lib/jdk/test/lib/Utils.java --- openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/Utils.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib/jdk/test/lib/Utils.java 2026-10-19 12:10:20.000000000 +0000 @@ -44,15 +44,18 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.AclEntry; +import java.nio.file.attribute.AclEntryPermission; import java.nio.file.attribute.AclEntryType; import java.nio.file.attribute.AclFileAttributeView; import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.UserPrincipal; import java.nio.channels.SocketChannel; import java.nio.file.attribute.PosixFilePermissions; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.EnumSet; import java.util.HexFormat; import java.util.Iterator; import java.util.Map; @@ -1026,25 +1029,18 @@ } else if (attr.contains("acl")) { AclFileAttributeView view = Files.getFileAttributeView(file, AclFileAttributeView.class); + UserPrincipal everyone = file.getFileSystem() + .getUserPrincipalLookupService() + .lookupPrincipalByName("Everyone"); + UserPrincipal principal = userOnly ? view.getOwner() : everyone; + EnumSet allPermissions = EnumSet.allOf(AclEntryPermission.class); + List acl = new ArrayList<>(); - for (AclEntry thisEntry : view.getAcl()) { - if (userOnly) { - if (thisEntry.principal().getName() - .equals(view.getOwner().getName())) { - acl.add(allowAccess(thisEntry)); - } else if (thisEntry.type() == AclEntryType.ALLOW) { - acl.add(revokeAccess(thisEntry)); - } else { - acl.add(thisEntry); - } - } else { - if (thisEntry.type() != AclEntryType.ALLOW) { - acl.add(allowAccess(thisEntry)); - } else { - acl.add(thisEntry); - } - } - } + acl.add(AclEntry.newBuilder() + .setType(AclEntryType.ALLOW) + .setPrincipal(principal) + .setPermissions(allPermissions) + .build()); view.setAcl(acl); } else { throw new RuntimeException("Unsupported file attributes: " + attr); diff -Nru openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/cds/CDSAppTester.java openjdk-25-25.0.5+8/test/lib/jdk/test/lib/cds/CDSAppTester.java --- openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/cds/CDSAppTester.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib/jdk/test/lib/cds/CDSAppTester.java 2026-10-19 12:10:20.000000000 +0000 @@ -58,6 +58,10 @@ private String whiteBoxJar = null; private boolean inOneStepTraining = false; + public String aotCacheFile() { + return this.aotCacheFile; + } + /** * All files created in the CDS/AOT workflow will be name + extension. E.g. * - name.aot diff -Nru openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java openjdk-25-25.0.5+8/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java --- openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java 2026-10-19 12:10:20.000000000 +0000 @@ -75,9 +75,14 @@ "ro", // ReadOnly "bm", // relocation bitmaps "hp", // heap + "ac", // aot code }; private static int num_regions = shared_region_name.length; + public static String[] getRegions() { + return shared_region_name; + } + static { WhiteBox wb; try { diff -Nru openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java openjdk-25-25.0.5+8/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java --- openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java 2026-10-19 12:10:20.000000000 +0000 @@ -58,9 +58,11 @@ private String modulepath; private String[] appCommandLine; private String[] vmArgs = new String[] {}; + private Tester tester; private SimpleCDSAppTester(String name) { this.name = name; + this.tester = new Tester(name); } public static SimpleCDSAppTester of(String name) { @@ -181,17 +183,35 @@ } public SimpleCDSAppTester runStaticWorkflow() throws Exception { - (new Tester(name)).runStaticWorkflow(); + tester.runStaticWorkflow(); return this; } public SimpleCDSAppTester runAOTWorkflow() throws Exception { - (new Tester(name)).runAOTWorkflow(); + tester.runAOTWorkflow(); return this; } public SimpleCDSAppTester run(String args[]) throws Exception { - (new Tester(name)).run(args); + tester.run(args); return this; } + + public SimpleCDSAppTester rerunProduction(String... extraVmArgs) throws Exception { + tester.productionRun(extraVmArgs); + return this; + } + + public SimpleCDSAppTester rerunProduction(String[] extraVmArgs, String... extraAppArgs) throws Exception { + tester.productionRun(extraVmArgs, extraAppArgs); + return this; + } + + public String aotCacheFile() { + return tester.aotCacheFile(); + } + + public void setCheckExitValue(boolean b) { + tester.setCheckExitValue(b); + } } diff -Nru openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java openjdk-25-25.0.5+8/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java --- openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.List; +import jdk.internal.platform.Metrics; import jdk.test.lib.Container; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; @@ -47,6 +48,7 @@ public class DockerTestUtils { private static boolean isDockerEngineAvailable = false; private static boolean wasDockerEngineChecked = false; + private static final Metrics metrics = Metrics.systemMetrics(); // Specifies how many lines to copy from child STDOUT to main test output. // Having too many lines in the main test output will result @@ -93,16 +95,12 @@ } /** - * Convenience method, will check if docker engine is available and usable; - * will print the appropriate message when not available. + * Checks if the docker engine is available and usable, throws an exception if not. * - * @return true if docker engine is available * @throws Exception */ - public static boolean canTestDocker() throws Exception { - if (isDockerEngineAvailable()) { - return true; - } else { + public static void checkCanTestDocker() throws Exception { + if (!isDockerEngineAvailable()) { throw new SkippedException("Docker engine is not available on this system"); } } @@ -134,6 +132,17 @@ } /** + * Checks if the engine can use resource limits, throws an exception if not. + * + * @throws Exception + */ + public static void checkCanUseResourceLimits() throws Exception { + if (isRootless() && "cgroupv1".equals(metrics.getProvider())) { + throw new SkippedException("Resource limits are not available on this system"); + } + } + + /** * Determine if the engine is running in root-less mode. * * @return {@code true} when running root-less (podman or docker). {@code false} diff -Nru openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/json/JSONValue.java openjdk-25-25.0.5+8/test/lib/jdk/test/lib/json/JSONValue.java --- openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/json/JSONValue.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib/jdk/test/lib/json/JSONValue.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; public interface JSONValue { @@ -88,9 +89,6 @@ @Override public String toString() { - if (value == null) { - return "null"; - } var builder = new StringBuilder(); builder.append("\""); @@ -172,6 +170,56 @@ public Iterator iterator() { return values.iterator(); } + + @Override + public List elements() { + return List.copyOf(values); + } + } + + public final class JSONBoolean implements JSONValue { + private static JSONBoolean TRUE = new JSONBoolean(true); + private static JSONBoolean FALSE = new JSONBoolean(false); + + private final boolean value; + + private JSONBoolean(boolean value) { + this.value = value; + } + + @Override + public boolean asBoolean() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static JSONBoolean of(boolean value) { + return value ? TRUE : FALSE; + } + } + + public final class JSONNull implements JSONValue { + private static JSONNull NULL = new JSONNull(); + + private JSONNull() {} + + @Override + public Optional valueOrNull() { + return Optional.empty(); + } + + @Override + public String toString() { + return "null"; + } + + public static JSONNull of() { + return NULL; + } } class JSONParser { @@ -181,8 +229,8 @@ JSONParser() { } - private IllegalStateException failure(String message) { - return new IllegalStateException(String.format("[%d]: %s : %s", pos, message, input)); + private IllegalArgumentException failure(String message) { + return new IllegalArgumentException(String.format("[%d]: %s : %s", pos, message, input)); } private char current() { @@ -220,13 +268,13 @@ } } - private JSONString parseBoolean() { + private JSONBoolean parseBoolean() { if (current() == 't') { expect('r'); expect('u'); expect('e'); advance(); - return new JSONString("true"); + return JSONBoolean.of(true); } if (current() == 'f') { @@ -235,7 +283,7 @@ expect('s'); expect('e'); advance(); - return new JSONString("false"); + return JSONBoolean.of(false); } throw failure("a boolean can only be 'true' or 'false'"); } @@ -400,12 +448,12 @@ return new JSONArray(list); } - public JSONString parseNull() { + public JSONNull parseNull() { expect('u'); expect('l'); expect('l'); advance(); - return new JSONString(null); + return JSONNull.of(); } public JSONObject parseObject() { @@ -531,22 +579,38 @@ } default int size() { - throw new IllegalStateException("Size operation unsupported"); + throw new UnsupportedOperationException("Size operation unsupported"); + } + + default List elements() { + throw new UnsupportedOperationException("Unsupported conversion to array"); } default String asString() { - throw new IllegalStateException("Unsupported conversion to String"); + throw new UnsupportedOperationException("Unsupported conversion to String"); } default JSONArray asArray() { - throw new IllegalStateException("Unsupported conversion to array"); + throw new UnsupportedOperationException("Unsupported conversion to array"); } default JSONObject asObject() { - throw new IllegalStateException("Unsupported conversion to object"); + throw new UnsupportedOperationException("Unsupported conversion to object"); + } + + default boolean asBoolean() { + throw new UnsupportedOperationException("Unsupported conversion to boolean"); } default JSONValue get(String field) { return asObject().get(field); } + + default Optional getOrAbsent(String field) { + return Optional.ofNullable(get(field)); + } + + default Optional valueOrNull() { + return Optional.of(this); + } } diff -Nru openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/security/DerUtils.java openjdk-25-25.0.5+8/test/lib/jdk/test/lib/security/DerUtils.java --- openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/security/DerUtils.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib/jdk/test/lib/security/DerUtils.java 2026-10-19 12:10:20.000000000 +0000 @@ -30,6 +30,7 @@ import sun.security.util.ObjectIdentifier; import java.io.IOException; +import java.util.Locale; public class DerUtils { /** @@ -37,9 +38,10 @@ *

    * The location of the inner DerValue is expressed as a string, in which * each character is a step from the outer DerValue into the inner one. - * If it's a number n, the n'th element (starting from 0) of a sequence - * is the next step. If it's 'c', the content of an OctetString parsed - * as a DerValue is the next step. Note that n cannot be bigger than 9. + * If it's a number n (in uppercase HEX, from 0 to F), the n'th element + * of a sequence is the next step. If it's 'c', the content of an OCTET + * STRING parsed as a DerValue is the next step. Note that n cannot be + * bigger than 15 (HEX "F"). *

    * Attention: do not reuse the return value. DerValue is mutable and * reading it advances a pointer inside. @@ -80,7 +82,7 @@ } else { DerInputStream ins = v.getData(); // skip n DerValue in the sequence - for (int i = 0; i < step - '0'; i++) { + for (int i = 0; i < Integer.parseInt(step + "", 16); i++) { ins.getDerValue(); } if (ins.available() > 0) { @@ -183,8 +185,8 @@ } else { for (int i = 0; ; i++) { // We only support locations of one digit now - if (i > 9) throw new IllegalStateException("Too big " + i); - String pos = now + i; + if (i > 15) throw new IllegalStateException("Too big " + i); + String pos = now + Integer.toHexString(i).toUpperCase(Locale.ROOT); var sub = DerUtils.innerDerValue(data, pos); // current value if (sub == null) break; // at the end if (target.equals(pos)) { // the one we want to change diff -Nru openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/threaddump/ThreadDump.java openjdk-25-25.0.5+8/test/lib/jdk/test/lib/threaddump/ThreadDump.java --- openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/threaddump/ThreadDump.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib/jdk/test/lib/threaddump/ThreadDump.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,13 +32,17 @@ import java.util.Optional; import java.util.OptionalLong; import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.test.lib.json.JSONValue; /** * Represents a thread dump that is obtained by parsing JSON text. A thread dump in JSON * format is generated with the {@code com.sun.management.HotSpotDiagnosticMXBean} API or - * using {@code jcmd Thread.dump_to_file -format=json }. + * using {@code jcmd Thread.dump_to_file -format=json }. The thread dump + * format is documented in {@code + * src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json}. * *

    The following is an example thread dump that is parsed by this class. Many of the * objects are collapsed to reduce the size. @@ -128,6 +132,20 @@ } /** + * Assert that a JSONValue is a JSONString and parse the string as an int. + */ + private static int parseStringAsInt(JSONValue valueObj) { + return Integer.parseInt(valueObj.asString()); + } + + /** + * Assert that a JSONValue is a JSONString and parse the string as a long. + */ + private static long parseStringAsLong(JSONValue valueObj) { + return Long.parseLong(valueObj.asString()); + } + + /** * Represents an element in the threadDump/threadContainers array. */ public static class ThreadContainer { @@ -150,14 +168,6 @@ } /** - * Returns the value of a property of this thread container, as a string. - */ - private String getStringProperty(String propertyName) { - JSONValue value = containerObj.get(propertyName); - return (value != null) ? value.asString() : null; - } - - /** * Returns the thread container name. */ public String name() { @@ -168,10 +178,10 @@ * Return the thread identifier of the owner or empty OptionalLong if not owned. */ public OptionalLong owner() { - String owner = getStringProperty("owner"); - return (owner != null) - ? OptionalLong.of(Long.parseLong(owner)) - : OptionalLong.empty(); + return containerObj.get("owner") // string or null + .valueOrNull() + .map(v -> OptionalLong.of(parseStringAsLong(v))) + .orElse(OptionalLong.empty()); } /** @@ -192,12 +202,10 @@ * Returns a stream of {@code ThreadInfo} objects for the threads in this container. */ public Stream threads() { - JSONValue.JSONArray threadsObj = containerObj.get("threads").asArray(); - Set threadInfos = new HashSet<>(); - for (JSONValue threadObj : threadsObj) { - threadInfos.add(new ThreadInfo(threadObj)); - } - return threadInfos.stream(); + return containerObj.get("threads") + .elements() + .stream() + .map(ThreadInfo::new); } /** @@ -237,30 +245,11 @@ private final JSONValue threadObj; ThreadInfo(JSONValue threadObj) { - this.tid = Long.parseLong(threadObj.get("tid").asString()); + this.tid = parseStringAsLong(threadObj.get("tid")); this.threadObj = threadObj; } /** - * Returns the value of a property of this thread object, as a string. - */ - private String getStringProperty(String propertyName) { - JSONValue value = threadObj.get(propertyName); - return (value != null) ? value.asString() : null; - } - - /** - * Returns the value of a property of an object in this thread object, as a string. - */ - private String getStringProperty(String objectName, String propertyName) { - if (threadObj.get(objectName) instanceof JSONValue.JSONObject obj - && obj.get(propertyName) instanceof JSONValue value) { - return value.asString(); - } - return null; - } - - /** * Returns the thread identifier. */ public long tid() { @@ -271,83 +260,92 @@ * Returns the thread name. */ public String name() { - return getStringProperty("name"); + return threadObj.get("name").asString(); } /** * Returns the thread state. */ public String state() { - return getStringProperty("state"); + return threadObj.get("state").asString(); } /** * Returns true if virtual thread. */ public boolean isVirtual() { - String s = getStringProperty("virtual"); - return (s != null) ? Boolean.parseBoolean(s) : false; + return threadObj.getOrAbsent("virtual") + .map(JSONValue::asBoolean) + .orElse(false); } /** - * Returns the thread's parkBlocker. + * Returns the thread's parkBlocker or null. */ public String parkBlocker() { - return getStringProperty("parkBlocker", "object"); + return threadObj.getOrAbsent("parkBlocker") + .map(v -> v.get("object").asString()) + .orElse(null); } /** * Returns the owner of the parkBlocker if the parkBlocker is an AbstractOwnableSynchronizer. */ public OptionalLong parkBlockerOwner() { - String owner = getStringProperty("parkBlocker", "owner"); - return (owner != null) - ? OptionalLong.of(Long.parseLong(owner)) - : OptionalLong.empty(); + return threadObj.getOrAbsent("parkBlocker") + .map(v -> OptionalLong.of(parseStringAsLong(v.get("owner")))) + .orElse(OptionalLong.empty()); } /** - * Returns the object that the thread is blocked entering its monitor. + * Returns the object that the thread is blocked entering its monitor or null. */ public String blockedOn() { - return getStringProperty("blockedOn"); + return threadObj.getOrAbsent("blockedOn") + .map(JSONValue::asString) + .orElse(null); } /** - * Return the object that is the therad is waiting on with Object.wait. + * Return the object that is the thread is waiting on with Object.wait or null. */ public String waitingOn() { - return getStringProperty("waitingOn"); + return threadObj.getOrAbsent("waitingOn") + .map(JSONValue::asString) + .orElse(null); } /** * Returns the thread stack. */ public Stream stack() { - JSONValue.JSONArray stackObj = threadObj.get("stack").asArray(); - List stack = new ArrayList<>(); - for (JSONValue steObject : stackObj) { - stack.add(steObject.asString()); - } - return stack.stream(); + return threadObj.get("stack") + .elements() + .stream() + .map(JSONValue::asString); } /** * Return a map of monitors owned. */ public Map> ownedMonitors() { - Map> ownedMonitors = new HashMap<>(); - JSONValue monitorsOwnedObj = threadObj.get("monitorsOwned"); - if (monitorsOwnedObj != null) { - for (JSONValue obj : monitorsOwnedObj.asArray()) { - int depth = Integer.parseInt(obj.get("depth").asString()); - for (JSONValue lock : obj.get("locks").asArray()) { - ownedMonitors.computeIfAbsent(depth, _ -> new ArrayList<>()) - .add(lock.asString()); - } - } - } - return ownedMonitors; + Map> result = new HashMap<>(); + threadObj.getOrAbsent("monitorsOwned") + .map(JSONValue::elements) + .orElse(List.of()) + .forEach(e -> { + int depth = parseStringAsInt(e.get("depth")); + List locks = e.get("locks") + .elements() + .stream() + .map(v -> v.valueOrNull() // string or null + .map(JSONValue::asString) + .orElse(null)) + .toList(); + result.computeIfAbsent(depth, _ -> new ArrayList<>()).addAll(locks); + }); + + return result; } /** @@ -355,10 +353,9 @@ * its carrier. */ public OptionalLong carrier() { - String s = getStringProperty("carrier"); - return (s != null) - ? OptionalLong.of(Long.parseLong(s)) - : OptionalLong.empty(); + return threadObj.getOrAbsent("carrier") + .map(s -> OptionalLong.of(parseStringAsLong(s))) + .orElse(OptionalLong.empty()); } @Override @@ -389,32 +386,24 @@ } /** - * Returns the value of a property of this thread dump, as a string. - */ - private String getStringProperty(String propertyName) { - JSONValue value = threadDumpObj.get(propertyName); - return (value != null) ? value.asString() : null; - } - - /** * Returns the value of threadDump/processId. */ public long processId() { - return Long.parseLong(getStringProperty("processId")); + return parseStringAsLong(threadDumpObj.get("processId")); } /** * Returns the value of threadDump/time. */ public String time() { - return getStringProperty("time"); + return threadDumpObj.get("time").asString(); } /** * Returns the value of threadDump/runtimeVersion. */ public String runtimeVersion() { - return getStringProperty("runtimeVersion"); + return threadDumpObj.get("runtimeVersion").asString(); } /** @@ -449,24 +438,31 @@ JSONValue threadDumpObj = JSONValue.parse(json).get("threadDump"); // threadContainers array, preserve insertion order (parents are added before children) - Map containerObjs = new LinkedHashMap<>(); - JSONValue threadContainersObj = threadDumpObj.get("threadContainers"); - for (JSONValue containerObj : threadContainersObj.asArray()) { - String name = containerObj.get("container").asString(); - containerObjs.put(name, containerObj); - } + Map containerObjs = threadDumpObj.get("threadContainers") + .elements() + .stream() + .collect(Collectors.toMap( + c -> c.get("container").asString(), + Function.identity(), + (a, b) -> { throw new RuntimeException("Duplicate container"); }, + LinkedHashMap::new + )); // find root and create tree of thread containers ThreadContainer root = null; Map map = new HashMap<>(); for (String name : containerObjs.keySet()) { JSONValue containerObj = containerObjs.get(name); - String parentName = containerObj.get("parent").asString(); - if (parentName == null) { + JSONValue parentObj = containerObj.get("parent"); + if (parentObj instanceof JSONValue.JSONNull) { + if (root != null) { + throw new RuntimeException("More than one root container"); + } root = new ThreadContainer(name, null, containerObj); map.put(name, root); } else { - var parent = map.get(parentName); + String parentName = parentObj.asString(); + ThreadContainer parent = map.get(parentName); if (parent == null) { throw new RuntimeException("Thread container " + name + " found before " + parentName); } @@ -475,7 +471,10 @@ map.put(name, container); } } + if (root == null) { + throw new RuntimeException("No root container"); + } return new ThreadDump(root, map, threadDumpObj); } -} \ No newline at end of file +} diff -Nru openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/util/ZipUtils.java openjdk-25-25.0.5+8/test/lib/jdk/test/lib/util/ZipUtils.java --- openjdk-25-25.0.4.1+1/test/lib/jdk/test/lib/util/ZipUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib/jdk/test/lib/util/ZipUtils.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,247 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.EnumSet; +import java.util.HexFormat; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +/** + * This class consists exclusively of static utility methods that are useful + * for creating and manipulating ZIP files. + */ +public final class ZipUtils { + // Some ZipFile constants for manipulating the 'End of central directory record' (END header) + private static final int ENDHDR = ZipFile.ENDHDR; // End of central directory record size + private static final int ENDSIZ = ZipFile.ENDSIZ; // Offset of CEN size field within ENDHDR + private static final int ENDOFF = ZipFile.ENDOFF; // Offset of CEN offset field within ENDHDR + // Expected message when CEN size does not match file size + public static final String INVALID_CEN_BAD_SIZE = "invalid END header (bad central directory size)"; + // Expected message when CEN offset is too large + public static final String INVALID_CEN_BAD_OFFSET = "invalid END header (bad central directory offset)"; + // Expected message when CEN size is too large + public static final String INVALID_CEN_SIZE_TOO_LARGE = "invalid END header (central directory size too large)"; + // Expected message when total entry count is too large + public static final String INVALID_BAD_ENTRY_COUNT = "invalid END header (total entries count too large)"; + + private ZipUtils() { } + + /** + * Create an ZIP file with a single entry, then modify the CEN size + * in the 'End of central directory record' (END header) to the given size. + * + * The CEN is optionally "inflated" with trailing zero bytes such that + * its actual size matches the one stated in the END header. + * + * The CEN offset is optiontially adjusted by the given amount + * + * The resulting ZIP is technically not valid, but it does allow us + * to test that large or invalid CEN sizes are rejected + * @param cenSize the CEN size to put in the END record + * @param inflateCen if true, zero-pad the CEN to the desired size + * @param cenOffAdjust Adjust the CEN offset field of the END record with this amount + * @throws IOException if an error occurs + */ + public static Path zipWithModifiedEndRecord(int cenSize, + boolean inflateCen, + int cenOffAdjust, + Path zip) throws IOException { + // A byte buffer for reading the END + ByteBuffer buffer = ByteBuffer.wrap(templateZip()).order(ByteOrder.LITTLE_ENDIAN); + + // Offset of the END header + int endOffset = buffer.limit() - ENDHDR; + + // Modify the CEN size + int sizeOffset = endOffset + ENDSIZ; + int currentCenSize = buffer.getInt(sizeOffset); + buffer.putInt(sizeOffset, cenSize); + + // Optionally modify the CEN offset + if (cenOffAdjust != 0) { + int offOffset = endOffset + ENDOFF; + int currentCenOff = buffer.getInt(offOffset); + buffer.putInt(offOffset, currentCenOff + cenOffAdjust); + } + // When creating a sparse file, the file must not already exit + Files.deleteIfExists(zip); + + // Open a FileChannel for writing a sparse file + EnumSet options = EnumSet.of(StandardOpenOption.CREATE_NEW, + StandardOpenOption.WRITE, + StandardOpenOption.SPARSE); + + try (FileChannel channel = FileChannel.open(zip, options)) { + // Write everything up to END + channel.write(buffer.slice(0, buffer.limit() - ENDHDR)); + if (inflateCen) { + // Inject "empty bytes" to make the actual CEN size match the END + int injectBytes = cenSize - currentCenSize; + channel.position(channel.position() + injectBytes); + } + // Write the modified END + channel.write(buffer.slice(buffer.limit() - ENDHDR, ENDHDR)); + } + return zip; + } + + /** + * Create a small Zip64 ZIP file, then modify the Zip64 END header + * with a possibly very large total entry count + * + * @param zip file to write to + * @param totalEntries the number of entries wanted in the Zip64 END header + * @return the modified ZIP file + * @throws IOException if an unexpeced IO error occurs + */ + public static Path zip64WithModifiedTotalEntries(Path zip, long totalEntries) throws IOException { + /** + * A small ZIP using the ZIP64 format. + * + * ZIP created using: "echo -n hello | zip zip64.zip -" + * Hex encoded using: "cat zip64.zip | xxd -ps" + * + * The file has the following structure: + * + * 0000 LOCAL HEADER #1 04034B50 + * 0004 Extract Zip Spec 2D '4.5' + * 0005 Extract OS 00 'MS-DOS' + * 0006 General Purpose Flag 0000 + * 0008 Compression Method 0000 'Stored' + * 000A Last Mod Time 5947AB78 'Mon Oct 7 21:27:48 2024' + * 000E CRC 363A3020 + * 0012 Compressed Length FFFFFFFF + * 0016 Uncompressed Length FFFFFFFF + * 001A Filename Length 0001 + * 001C Extra Length 0014 + * 001E Filename '-' + * 001F Extra ID #0001 0001 'ZIP64' + * 0021 Length 0010 + * 0023 Uncompressed Size 0000000000000006 + * 002B Compressed Size 0000000000000006 + * 0033 PAYLOAD hello. + * + * 0039 CENTRAL HEADER #1 02014B50 + * 003D Created Zip Spec 1E '3.0' + * 003E Created OS 03 'Unix' + * 003F Extract Zip Spec 2D '4.5' + * 0040 Extract OS 00 'MS-DOS' + * 0041 General Purpose Flag 0000 + * 0043 Compression Method 0000 'Stored' + * 0045 Last Mod Time 5947AB78 'Mon Oct 7 21:27:48 2024' + * 0049 CRC 363A3020 + * 004D Compressed Length 00000006 + * 0051 Uncompressed Length FFFFFFFF + * 0055 Filename Length 0001 + * 0057 Extra Length 000C + * 0059 Comment Length 0000 + * 005B Disk Start 0000 + * 005D Int File Attributes 0001 + * [Bit 0] 1 Text Data + * 005F Ext File Attributes 11B00000 + * 0063 Local Header Offset 00000000 + * 0067 Filename '-' + * 0068 Extra ID #0001 0001 'ZIP64' + * 006A Length 0008 + * 006C Uncompressed Size 0000000000000006 + * + * 0074 ZIP64 END CENTRAL DIR 06064B50 + * RECORD + * 0078 Size of record 000000000000002C + * 0080 Created Zip Spec 1E '3.0' + * 0081 Created OS 03 'Unix' + * 0082 Extract Zip Spec 2D '4.5' + * 0083 Extract OS 00 'MS-DOS' + * 0084 Number of this disk 00000000 + * 0088 Central Dir Disk no 00000000 + * 008C Entries in this disk 0000000000000001 + * 0094 Total Entries 0000000000000001 + * 009C Size of Central Dir 000000000000003B + * 00A4 Offset to Central dir 0000000000000039 + * + * 00AC ZIP64 END CENTRAL DIR 07064B50 + * LOCATOR + * 00B0 Central Dir Disk no 00000000 + * 00B4 Offset to Central dir 0000000000000074 + * 00BC Total no of Disks 00000001 + * + * 00C0 END CENTRAL HEADER 06054B50 + * 00C4 Number of this disk 0000 + * 00C6 Central Dir Disk no 0000 + * 00C8 Entries in this disk 0001 + * 00CA Total Entries 0001 + * 00CC Size of Central Dir 0000003B + * 00D0 Offset to Central Dir FFFFFFFF + * 00D4 Comment Length 0000 + */ + + byte[] zipBytes = HexFormat.of().parseHex(""" + 504b03042d000000000078ab475920303a36ffffffffffffffff01001400 + 2d010010000600000000000000060000000000000068656c6c6f0a504b01 + 021e032d000000000078ab475920303a3606000000ffffffff01000c0000 + 00000001000000b011000000002d010008000600000000000000504b0606 + 2c000000000000001e032d00000000000000000001000000000000000100 + 0000000000003b000000000000003900000000000000504b060700000000 + 740000000000000001000000504b050600000000010001003b000000ffff + ffff0000 + """.replaceAll("\n","")); + + // Buffer to manipulate the above ZIP + ByteBuffer buf = ByteBuffer.wrap(zipBytes).order(ByteOrder.LITTLE_ENDIAN); + // Offset of the 'total entries' in the 'ZIP64 END CENTRAL DIR' record + // Update ZIP64 entry count to a value which cannot possibly fit in the small CEN + buf.putLong(0x94, totalEntries); + // The corresponding END field needs the ZIP64 magic value + buf.putShort(0xCA, (short) 0xFFFF); + // Write the ZIP to disk + Files.write(zip, zipBytes); + return zip; + } + + /** + * Produce a byte array of a ZIP with a single entry + * + * @throws IOException if an error occurs + */ + private static byte[] templateZip() throws IOException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + try (ZipOutputStream zo = new ZipOutputStream(bout)) { + ZipEntry entry = new ZipEntry("duke.txt"); + zo.putNextEntry(entry); + zo.write("duke".getBytes(StandardCharsets.UTF_8)); + } + return bout.toByteArray(); + } +} diff -Nru openjdk-25-25.0.4.1+1/test/lib/jdk/test/whitebox/WhiteBox.java openjdk-25-25.0.5+8/test/lib/jdk/test/whitebox/WhiteBox.java --- openjdk-25-25.0.4.1+1/test/lib/jdk/test/whitebox/WhiteBox.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib/jdk/test/whitebox/WhiteBox.java 2026-10-19 12:10:20.000000000 +0000 @@ -66,7 +66,7 @@ // Memory private native long getObjectAddress0(Object o); - public long getObjectAddress(Object o) { + public long getObjectAddress(Object o) { Objects.requireNonNull(o); return getObjectAddress0(o); } @@ -79,7 +79,12 @@ public native long getHeapAlignment(); public native long getMinimumJavaStackSize(); - public native boolean hasExternalSymbolsStripped(); + public native boolean shipsFullDebugInfo(); + public native boolean shipsPublicDebugInfo(); + + public boolean shipsDebugInfo() { + return shipsFullDebugInfo() || shipsPublicDebugInfo(); + } private native boolean isObjectInOldGen0(Object o); public boolean isObjectInOldGen(Object o) { diff -Nru openjdk-25-25.0.4.1+1/test/lib-test/TEST.ROOT openjdk-25-25.0.5+8/test/lib-test/TEST.ROOT --- openjdk-25-25.0.4.1+1/test/lib-test/TEST.ROOT 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/lib-test/TEST.ROOT 2026-10-19 12:10:20.000000000 +0000 @@ -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 @@ -29,7 +29,7 @@ keys=randomness # Minimum jtreg version -requiredVersion=8+2 +requiredVersion=8.2.1+1 # Allow querying of various System properties in @requires clauses requires.extraPropDefns = ../jtreg-ext/requires/VMProps.java diff -Nru openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/java/security/SSLHandshake.java openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/java/security/SSLHandshake.java --- openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/java/security/SSLHandshake.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/java/security/SSLHandshake.java 2026-10-19 12:10:20.000000000 +0000 @@ -44,6 +44,7 @@ import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManagerFactory; @@ -75,8 +76,15 @@ @Param({"true", "false"}) boolean resume; - @Param({"TLSv1.2", "TLS"}) - String tlsVersion; + @Param({ + "TLSv1.2-secp256r1", + "TLSv1.3-x25519", "TLSv1.3-secp256r1", "TLSv1.3-secp384r1", + "TLSv1.3-X25519MLKEM768", "TLSv1.3-SecP256r1MLKEM768", "TLSv1.3-SecP384r1MLKEM1024" + }) + String versionAndGroup; + + private String tlsVersion; + private String namedGroup; private static SSLContext getServerContext() { try { @@ -96,6 +104,10 @@ @Setup(Level.Trial) public void init() throws Exception { + String[] components = versionAndGroup.split("-", 2); + tlsVersion = components[0]; + namedGroup = components[1]; + KeyStore ts = TestCertificates.getTrustStore(); TrustManagerFactory tmf = TrustManagerFactory.getInstance( @@ -195,5 +207,14 @@ */ clientEngine = sslClientCtx.createSSLEngine("client", 80); clientEngine.setUseClientMode(true); + + // Set the key exchange named group in client and server engines + SSLParameters clientParams = clientEngine.getSSLParameters(); + clientParams.setNamedGroups(new String[]{namedGroup}); + clientEngine.setSSLParameters(clientParams); + + SSLParameters serverParams = serverEngine.getSSLParameters(); + serverParams.setNamedGroups(new String[]{namedGroup}); + serverEngine.setSSLParameters(serverParams); } } diff -Nru openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java --- openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java 2026-10-19 12:10:20.000000000 +0000 @@ -23,34 +23,69 @@ package org.openjdk.bench.javax.crypto.full; import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.OperationsPerInvocation; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.infra.Blackhole; import javax.crypto.DecapsulateException; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; import javax.crypto.KEM; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.security.spec.ECGenParameterSpec; -public class KEMBench extends CryptoBase { +public abstract class KEMBench extends CryptoBase { public static final int SET_SIZE = 128; - @Param({"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024" }) + @Param({}) private String algorithm; + @Param({""}) // Used when the KeyPairGenerator Alg != KEM Alg + private String kpgSpec; + private KeyPair[] keys; private byte[][] messages; private KEM kem; @Setup - public void setup() throws NoSuchAlgorithmException, InvalidKeyException { - kem = (prov == null) ? KEM.getInstance(algorithm) : KEM.getInstance(algorithm, prov); - KeyPairGenerator generator = (prov == null) ? KeyPairGenerator.getInstance(algorithm) : KeyPairGenerator.getInstance(algorithm, prov); + public void setup() throws NoSuchAlgorithmException, InvalidKeyException, + InvalidAlgorithmParameterException { + String kpgAlg; + String kpgParams; + kem = (prov == null) ? KEM.getInstance(algorithm) : + KEM.getInstance(algorithm, prov); + + // By default use the same provider for KEM and KPG + Provider kpgProv = prov; + if (kpgSpec.isEmpty()) { + kpgAlg = algorithm; + kpgParams = ""; + } else { + // The key pair generation spec is broken down from a colon- + // delimited string spec into 3 fields: + // [0] - the provider name + // [1] - the algorithm name + // [2] - the parameters (i.e. the name of the curve) + String[] kpgTok = kpgSpec.split(":"); + kpgProv = Security.getProvider(kpgTok[0]); + kpgAlg = kpgTok[1]; + kpgParams = kpgTok[2]; + } + KeyPairGenerator generator = (kpgProv == null) ? + KeyPairGenerator.getInstance(kpgAlg) : + KeyPairGenerator.getInstance(kpgAlg, kpgProv); + if (kpgParams != null && !kpgParams.isEmpty()) { + generator.initialize(new ECGenParameterSpec(kpgParams)); + } keys = new KeyPair[SET_SIZE]; for (int i = 0; i < keys.length; i++) { keys[i] = generator.generateKeyPair(); @@ -63,20 +98,79 @@ } } + private static Provider getInternalJce() { + try { + Class dhClazz = Class.forName("sun.security.ssl.HybridProvider"); + return (Provider) dhClazz.getField("PROVIDER").get(null); + } catch (ReflectiveOperationException exc) { + throw new RuntimeException(exc); + } + } + @Benchmark @OperationsPerInvocation(SET_SIZE) public void encapsulate(Blackhole bh) throws InvalidKeyException { for (KeyPair kp : keys) { - bh.consume(kem.newEncapsulator(kp.getPublic()).encapsulate().encapsulation()); + bh.consume(kem.newEncapsulator(kp.getPublic()).encapsulate(). + encapsulation()); } } @Benchmark @OperationsPerInvocation(SET_SIZE) - public void decapsulate(Blackhole bh) throws InvalidKeyException, DecapsulateException { + public void decapsulate(Blackhole bh) throws InvalidKeyException, + DecapsulateException { for (int i = 0; i < messages.length; i++) { - bh.consume(kem.newDecapsulator(keys[i].getPrivate()).decapsulate(messages[i])); + bh.consume(kem.newDecapsulator(keys[i].getPrivate()). + decapsulate(messages[i])); + } + } + + public static class MLKEM extends KEMBench { + @Param({"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024" }) + private String algorithm; + + @Param({""}) // ML-KEM uses the same alg for KPG and KEM + private String kpgSpec; + } + + @Fork(value = 5, jvmArgs = {"-XX:+AlwaysPreTouch", "--add-opens", + "java.base/sun.security.ssl=ALL-UNNAMED"}) + public static class JSSE_DHasKEM extends KEMBench { + @Setup + public void init() { + try { + prov = getInternalJce(); + super.setup(); + } catch (GeneralSecurityException gse) { + throw new RuntimeException(gse); + } } + + @Param({"DH"}) + private String algorithm; + + @Param({"SunEC:XDH:x25519", "SunEC:EC:secp256r1", "SunEC:EC:secp384r1"}) + private String kpgSpec; } + @Fork(value = 5, jvmArgs = {"-XX:+AlwaysPreTouch", "--add-opens", + "java.base/sun.security.ssl=ALL-UNNAMED"}) + public static class JSSE_Hybrid extends KEMBench { + @Setup + public void init() { + try { + prov = getInternalJce(); + super.setup(); + } catch (GeneralSecurityException gse) { + throw new RuntimeException(gse); + } + } + + @Param({"X25519MLKEM768", "SecP256r1MLKEM768", "SecP384r1MLKEM1024"}) + private String algorithm; + + @Param({""}) // ML-KEM uses the same alg for KPG and KEM + private String kpgSpec; + } } diff -Nru openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java --- openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java 2026-10-19 12:10:20.000000000 +0000 @@ -22,13 +22,16 @@ */ package org.openjdk.bench.javax.crypto.full; +import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Setup; +import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; +import java.security.Provider; public class KeyPairGeneratorBench extends CryptoBase { @@ -45,11 +48,21 @@ setupProvider(); generator = (prov == null) ? KeyPairGenerator.getInstance(algorithm) : KeyPairGenerator.getInstance(algorithm, prov); - if (keyLength > 0) { // not all key pair generators allow the use of key length + // not all key pair generators allow the use of key length + if (keyLength > 0) { generator.initialize(keyLength); } } + private static Provider getInternalJce() { + try { + Class dhClazz = Class.forName("sun.security.ssl.HybridProvider"); + return (Provider) dhClazz.getField("PROVIDER").get(null); + } catch (ReflectiveOperationException exc) { + throw new RuntimeException(exc); + } + } + @Benchmark public KeyPair generateKeyPair() { return generator.generateKeyPair(); @@ -118,4 +131,23 @@ private int keyLength; } + @Fork(value = 5, jvmArgs = {"-XX:+AlwaysPreTouch", "--add-opens", + "java.base/sun.security.ssl=ALL-UNNAMED"}) + public static class JSSE_Hybrid extends KeyPairGeneratorBench { + @Setup + public void init() { + try { + prov = getInternalJce(); + super.setup(); + } catch (GeneralSecurityException gse) { + throw new RuntimeException(gse); + } + } + + @Param({"X25519MLKEM768", "SecP256r1MLKEM768", "SecP384r1MLKEM1024"}) + private String algorithm; + + @Param({"0"}) // Hybrid KPGs don't need key lengths + private int keyLength; + } } diff -Nru openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/jdk/incubator/vector/GatherOperationsBenchmark.java openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/jdk/incubator/vector/GatherOperationsBenchmark.java --- openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/jdk/incubator/vector/GatherOperationsBenchmark.java 2026-08-07 11:31:46.000000000 +0000 +++ openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/jdk/incubator/vector/GatherOperationsBenchmark.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,357 +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. - * - */ - -package org.openjdk.bench.jdk.incubator.vector; - -import jdk.incubator.vector.*; -import java.util.Random; -import java.util.stream.IntStream; -import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.*; - -@OutputTimeUnit(TimeUnit.MILLISECONDS) -@State(Scope.Thread) -@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) -public class GatherOperationsBenchmark { - @Param({"64", "256", "1024", "4096"}) - int SIZE; - byte [] barr; - byte [] bres; - short [] sarr; - short [] sres; - int [] index; - - static final VectorSpecies S64 = ShortVector.SPECIES_64; - static final VectorSpecies S128 = ShortVector.SPECIES_128; - static final VectorSpecies S256 = ShortVector.SPECIES_256; - static final VectorSpecies S512 = ShortVector.SPECIES_512; - static final VectorSpecies B64 = ByteVector.SPECIES_64; - static final VectorSpecies B128 = ByteVector.SPECIES_128; - static final VectorSpecies B256 = ByteVector.SPECIES_256; - static final VectorSpecies B512 = ByteVector.SPECIES_512; - - @Setup(Level.Trial) - public void BmSetup() { - Random r = new Random(1245); - index = new int[SIZE]; - barr = new byte[SIZE]; - bres = new byte[SIZE]; - sarr = new short[SIZE]; - sres = new short[SIZE]; - for (int i = 0; i < SIZE; i++) { - barr[i] = (byte)i; - sarr[i] = (short)i; - index[i] = r.nextInt(SIZE-1); - } - } - - - - @Benchmark - public void microByteGather64() { - for (int i = 0; i < SIZE; i += B64.length()) { - ByteVector.fromArray(B64, barr, 0, index, i) - .intoArray(bres, i); - } - } - - - @Benchmark - public void microByteGather64_NZ_OFF() { - for (int i = 0; i < SIZE; i += B64.length()) { - ByteVector.fromArray(B64, barr, 1, index, i) - .intoArray(bres, i); - } - } - - @Benchmark - public void microByteGather64_MASK() { - VectorMask VMASK = VectorMask.fromLong(B64, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += B64.length()) { - ByteVector.fromArray(B64, barr, 0, index, i, VMASK) - .intoArray(bres, i); - } - } - - @Benchmark - public void microByteGather64_MASK_NZ_OFF() { - VectorMask VMASK = VectorMask.fromLong(B64, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += B64.length()) { - ByteVector.fromArray(B64, barr, 1, index, i, VMASK) - .intoArray(bres, i); - } - } - - - @Benchmark - public void microByteGather128() { - for (int i = 0; i < SIZE; i += B128.length()) { - ByteVector.fromArray(B128, barr, 0, index, i) - .intoArray(bres, i); - } - } - - - @Benchmark - public void microByteGather128_NZ_OFF() { - for (int i = 0; i < SIZE; i += B128.length()) { - ByteVector.fromArray(B128, barr, 1, index, i) - .intoArray(bres, i); - } - } - - @Benchmark - public void microByteGather128_MASK() { - VectorMask VMASK = VectorMask.fromLong(B128, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += B128.length()) { - ByteVector.fromArray(B128, barr, 0, index, i, VMASK) - .intoArray(bres, i); - } - } - - @Benchmark - public void microByteGather128_MASK_NZ_OFF() { - VectorMask VMASK = VectorMask.fromLong(B128, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += B128.length()) { - ByteVector.fromArray(B128, barr, 1, index, i, VMASK) - .intoArray(bres, i); - } - } - - - @Benchmark - public void microByteGather256() { - for (int i = 0; i < SIZE; i += B256.length()) { - ByteVector.fromArray(B256, barr, 0, index, i) - .intoArray(bres, i); - } - } - - - @Benchmark - public void microByteGather256_NZ_OFF() { - for (int i = 0; i < SIZE; i += B256.length()) { - ByteVector.fromArray(B256, barr, 1, index, i) - .intoArray(bres, i); - } - } - - @Benchmark - public void microByteGather256_MASK() { - VectorMask VMASK = VectorMask.fromLong(B256, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += B256.length()) { - ByteVector.fromArray(B256, barr, 0, index, i, VMASK) - .intoArray(bres, i); - } - } - - @Benchmark - public void microByteGather256_MASK_NZ_OFF() { - VectorMask VMASK = VectorMask.fromLong(B256, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += B256.length()) { - ByteVector.fromArray(B256, barr, 1, index, i, VMASK) - .intoArray(bres, i); - } - } - - - @Benchmark - public void microByteGather512() { - for (int i = 0; i < SIZE; i += B512.length()) { - ByteVector.fromArray(B512, barr, 0, index, i) - .intoArray(bres, i); - } - } - - - @Benchmark - public void microByteGather512_NZ_OFF() { - for (int i = 0; i < SIZE; i += B512.length()) { - ByteVector.fromArray(B512, barr, 1, index, i) - .intoArray(bres, i); - } - } - - @Benchmark - public void microByteGather512_MASK() { - VectorMask VMASK = VectorMask.fromLong(B512, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += B512.length()) { - ByteVector.fromArray(B512, barr, 0, index, i, VMASK) - .intoArray(bres, i); - } - } - - @Benchmark - public void microByteGather512_MASK_NZ_OFF() { - VectorMask VMASK = VectorMask.fromLong(B512, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += B512.length()) { - ByteVector.fromArray(B512, barr, 1, index, i, VMASK) - .intoArray(bres, i); - } - } - - - @Benchmark - public void microShortGather64() { - for (int i = 0; i < SIZE; i += S64.length()) { - ShortVector.fromArray(S64, sarr, 0, index, i) - .intoArray(sres, i); - } - } - - - @Benchmark - public void microShortGather64_NZ_OFF() { - for (int i = 0; i < SIZE; i += S64.length()) { - ShortVector.fromArray(S64, sarr, 1, index, i) - .intoArray(sres, i); - } - } - - @Benchmark - public void microShortGather64_MASK() { - VectorMask VMASK = VectorMask.fromLong(S64, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += S64.length()) { - ShortVector.fromArray(S64, sarr, 0, index, i, VMASK) - .intoArray(sres, i); - } - } - - @Benchmark - public void microShortGather64_MASK_NZ_OFF() { - VectorMask VMASK = VectorMask.fromLong(S64, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += S64.length()) { - ShortVector.fromArray(S64, sarr, 1, index, i, VMASK) - .intoArray(sres, i); - } - } - - - @Benchmark - public void microShortGather128() { - for (int i = 0; i < SIZE; i += S128.length()) { - ShortVector.fromArray(S128, sarr, 0, index, i) - .intoArray(sres, i); - } - } - - - @Benchmark - public void microShortGather128_NZ_OFF() { - for (int i = 0; i < SIZE; i += S128.length()) { - ShortVector.fromArray(S128, sarr, 1, index, i) - .intoArray(sres, i); - } - } - - @Benchmark - public void microShortGather128_MASK() { - VectorMask VMASK = VectorMask.fromLong(S128, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += S128.length()) { - ShortVector.fromArray(S128, sarr, 0, index, i, VMASK) - .intoArray(sres, i); - } - } - - @Benchmark - public void microShortGather128_MASK_NZ_OFF() { - VectorMask VMASK = VectorMask.fromLong(S128, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += S128.length()) { - ShortVector.fromArray(S128, sarr, 1, index, i, VMASK) - .intoArray(sres, i); - } - } - - - @Benchmark - public void microShortGather256() { - for (int i = 0; i < SIZE; i += S256.length()) { - ShortVector.fromArray(S256, sarr, 0, index, i) - .intoArray(sres, i); - } - } - - - @Benchmark - public void microShortGather256_NZ_OFF() { - for (int i = 0; i < SIZE; i += S256.length()) { - ShortVector.fromArray(S256, sarr, 1, index, i) - .intoArray(sres, i); - } - } - - @Benchmark - public void microShortGather256_MASK() { - VectorMask VMASK = VectorMask.fromLong(S256, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += S256.length()) { - ShortVector.fromArray(S256, sarr, 0, index, i, VMASK) - .intoArray(sres, i); - } - } - - @Benchmark - public void microShortGather256_MASK_NZ_OFF() { - VectorMask VMASK = VectorMask.fromLong(S256, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += S256.length()) { - ShortVector.fromArray(S256, sarr, 1, index, i, VMASK) - .intoArray(sres, i); - } - } - - - @Benchmark - public void microShortGather512() { - for (int i = 0; i < SIZE; i += S512.length()) { - ShortVector.fromArray(S512, sarr, 0, index, i) - .intoArray(sres, i); - } - } - - - @Benchmark - public void microShortGather512_NZ_OFF() { - for (int i = 0; i < SIZE; i += S512.length()) { - ShortVector.fromArray(S512, sarr, 1, index, i) - .intoArray(sres, i); - } - } - - @Benchmark - public void microShortGather512_MASK() { - VectorMask VMASK = VectorMask.fromLong(S512, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += S512.length()) { - ShortVector.fromArray(S512, sarr, 0, index, i, VMASK) - .intoArray(sres, i); - } - } - - @Benchmark - public void microShortGather512_MASK_NZ_OFF() { - VectorMask VMASK = VectorMask.fromLong(S512, 0x5555555555555555L); - for (int i = 0; i < SIZE; i += S512.length()) { - ShortVector.fromArray(S512, sarr, 1, index, i, VMASK) - .intoArray(sres, i); - } - } -} diff -Nru openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskCompareNotBenchmark.java openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskCompareNotBenchmark.java --- openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskCompareNotBenchmark.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskCompareNotBenchmark.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.jdk.incubator.vector; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import jdk.incubator.vector.*; +import java.lang.invoke.*; +import java.util.concurrent.TimeUnit; +import java.util.Random; + +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 2, jvmArgs = { "--add-modules=jdk.incubator.vector" }) +public abstract class MaskCompareNotBenchmark { + @Param({"4096"}) + protected int ARRAYLEN; + + // Abstract method to get comparison operator from subclasses + protected abstract String getComparisonOperatorName(); + + // To get compile-time constants for comparison operation + static final MutableCallSite MUTABLE_COMPARISON_CONSTANT = new MutableCallSite(MethodType.methodType(VectorOperators.Comparison.class)); + static final MethodHandle MUTABLE_COMPARISON_CONSTANT_HANDLE = MUTABLE_COMPARISON_CONSTANT.dynamicInvoker(); + + private static Random r = new Random(); + + protected static final VectorSpecies B_SPECIES = ByteVector.SPECIES_MAX; + protected static final VectorSpecies S_SPECIES = ShortVector.SPECIES_MAX; + protected static final VectorSpecies I_SPECIES = IntVector.SPECIES_MAX; + protected static final VectorSpecies L_SPECIES = LongVector.SPECIES_MAX; + protected static final VectorSpecies F_SPECIES = FloatVector.SPECIES_MAX; + protected static final VectorSpecies D_SPECIES = DoubleVector.SPECIES_MAX; + + protected boolean[] mr; + protected byte[] ba; + protected byte[] bb; + protected short[] sa; + protected short[] sb; + protected int[] ia; + protected int[] ib; + protected long[] la; + protected long[] lb; + protected float[] fa; + protected float[] fb; + protected double[] da; + protected double[] db; + + @Setup + public void init() throws Throwable { + mr = new boolean[ARRAYLEN]; + ba = new byte[ARRAYLEN]; + bb = new byte[ARRAYLEN]; + sa = new short[ARRAYLEN]; + sb = new short[ARRAYLEN]; + ia = new int[ARRAYLEN]; + ib = new int[ARRAYLEN]; + la = new long[ARRAYLEN]; + lb = new long[ARRAYLEN]; + fa = new float[ARRAYLEN]; + fb = new float[ARRAYLEN]; + da = new double[ARRAYLEN]; + db = new double[ARRAYLEN]; + + for (int i = 0; i < ARRAYLEN; i++) { + mr[i] = r.nextBoolean(); + ba[i] = (byte) r.nextInt(); + bb[i] = (byte) r.nextInt(); + sa[i] = (short) r.nextInt(); + sb[i] = (short) r.nextInt(); + ia[i] = r.nextInt(); + ib[i] = r.nextInt(); + la[i] = r.nextLong(); + lb[i] = r.nextLong(); + fa[i] = r.nextFloat(); + fb[i] = r.nextFloat(); + da[i] = r.nextDouble(); + db[i] = r.nextDouble(); + } + + VectorOperators.Comparison comparisonOp = getComparisonOperator(getComparisonOperatorName()); + MethodHandle constant = MethodHandles.constant(VectorOperators.Comparison.class, comparisonOp); + MUTABLE_COMPARISON_CONSTANT.setTarget(constant); + } + + @CompilerControl(CompilerControl.Mode.INLINE) + private static VectorOperators.Comparison getComparisonOperator(String op) { + switch (op) { + case "EQ": return VectorOperators.EQ; + case "NE": return VectorOperators.NE; + case "LT": return VectorOperators.LT; + case "LE": return VectorOperators.LE; + case "GT": return VectorOperators.GT; + case "GE": return VectorOperators.GE; + case "ULT": return VectorOperators.ULT; + case "ULE": return VectorOperators.ULE; + case "UGT": return VectorOperators.UGT; + case "UGE": return VectorOperators.UGE; + default: throw new IllegalArgumentException("Unknown comparison operator: " + op); + } + } + + @CompilerControl(CompilerControl.Mode.INLINE) + protected VectorOperators.Comparison comparison_con() throws Throwable { + return (VectorOperators.Comparison) MUTABLE_COMPARISON_CONSTANT_HANDLE.invokeExact(); + } + + // Subclasses with different comparison operators + public static class IntegerComparisons extends MaskCompareNotBenchmark { + @Param({"EQ", "NE", "LT", "LE", "GT", "GE", "ULT", "ULE", "UGT", "UGE"}) + public String COMPARISON_OP; + + @Override + protected String getComparisonOperatorName() { + return COMPARISON_OP; + } + + @Benchmark + public void testCompareMaskNotByte() throws Throwable { + VectorOperators.Comparison op = comparison_con(); + ByteVector bv = ByteVector.fromArray(B_SPECIES, bb, 0); + for (int j = 0; j < ARRAYLEN; j += B_SPECIES.length()) { + ByteVector av = ByteVector.fromArray(B_SPECIES, ba, j); + VectorMask m = av.compare(op, bv).not(); + m.intoArray(mr, j); + } + } + + @Benchmark + public void testCompareMaskNotShort() throws Throwable { + VectorOperators.Comparison op = comparison_con(); + ShortVector bv = ShortVector.fromArray(S_SPECIES, sb, 0); + for (int j = 0; j < ARRAYLEN; j += S_SPECIES.length()) { + ShortVector av = ShortVector.fromArray(S_SPECIES, sa, j); + VectorMask m = av.compare(op, bv).not(); + m.intoArray(mr, j); + } + } + + @Benchmark + public void testCompareMaskNotInt() throws Throwable { + VectorOperators.Comparison op = comparison_con(); + IntVector bv = IntVector.fromArray(I_SPECIES, ib, 0); + for (int j = 0; j < ARRAYLEN; j += I_SPECIES.length()) { + IntVector av = IntVector.fromArray(I_SPECIES, ia, j); + VectorMask m = av.compare(op, bv).not(); + m.intoArray(mr, j); + } + } + + @Benchmark + public void testCompareMaskNotLong() throws Throwable { + VectorOperators.Comparison op = comparison_con(); + LongVector bv = LongVector.fromArray(L_SPECIES, lb, 0); + for (int j = 0; j < ARRAYLEN; j += L_SPECIES.length()) { + LongVector av = LongVector.fromArray(L_SPECIES, la, j); + VectorMask m = av.compare(op, bv).not(); + m.intoArray(mr, j); + } + } + } + + public static class FloatingPointComparisons extends MaskCompareNotBenchmark { + // "ULT", "ULE", "UGT", "UGE" are not supported for floating point types + @Param({"EQ", "NE", "LT", "LE", "GT", "GE"}) + public String COMPARISON_OP; + + @Override + protected String getComparisonOperatorName() { + return COMPARISON_OP; + } + + @Benchmark + public void testCompareMaskNotFloat() throws Throwable { + VectorOperators.Comparison op = comparison_con(); + FloatVector bv = FloatVector.fromArray(F_SPECIES, fb, 0); + for (int j = 0; j < ARRAYLEN; j += F_SPECIES.length()) { + FloatVector av = FloatVector.fromArray(F_SPECIES, fa, j); + VectorMask m = av.compare(op, bv).not(); + m.intoArray(mr, j); + } + } + + @Benchmark + public void testCompareMaskNotDouble() throws Throwable { + VectorOperators.Comparison op = comparison_con(); + DoubleVector bv = DoubleVector.fromArray(D_SPECIES, db, 0); + for (int j = 0; j < ARRAYLEN; j += D_SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(D_SPECIES, da, j); + VectorMask m = av.compare(op, bv).not(); + m.intoArray(mr, j); + } + } + } +} diff -Nru openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java --- openjdk-25-25.0.4.1+1/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-25-25.0.5+8/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.vm.runtime; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +@State(Scope.Benchmark) +@Warmup(iterations = 2, time = 5) +@Measurement(iterations = 5, time = 5) +@BenchmarkMode(Mode.SampleTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Threads(1) +@Fork(value = 10) +public class ThreadMXBeanBench { + static final ThreadMXBean mxThreadBean = ManagementFactory.getThreadMXBean(); + static long user; // To avoid dead-code elimination + + @Benchmark + public void getCurrentThreadUserTime() throws Throwable { + user = mxThreadBean.getCurrentThreadUserTime(); + } +}