Version in base suite: 21.0.12.1+1-1~deb13u1 Base version: openjdk-21_21.0.12.1+1-1~deb13u1 Target version: openjdk-21_21.0.13+9-1~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/o/openjdk-21/openjdk-21_21.0.12.1+1-1~deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/o/openjdk-21/openjdk-21_21.0.13+9-1~deb13u1.dsc .jcheck/conf | 2 debian/JB-jre-headless.overrides.in | 5 debian/JB-jre-zero.overrides.in | 4 debian/JB-testsupport.overrides.in | 7 debian/changelog | 83 debian/control | 4 debian/patches/jdk-8334502-proposed.patch | 19 debian/patches/jdk-8359735.patch | 63 debian/patches/jdk-8384505.diff | 39 debian/patches/series | 3 debian/rules | 47 debian/tests/control | 4 debian/tests/problems-loong-hotspot.txt | 554 ++ debian/tests/problems-loong-jdk.txt | 771 +++ debian/tests/problems-loong-other.txt | 134 debian/tests/problems.csv | 14 debian/tests/write-problems.in | 6 debian/tests/write-problems.sh | 6 doc/testing.html | 2 doc/testing.md | 4 make/RunTests.gmk | 11 make/autoconf/flags-ldflags.m4 | 3 make/autoconf/lib-tests.m4 | 4 make/conf/github-actions.conf | 4 make/conf/jib-profiles.js | 8 make/conf/version-numbers.conf | 6 make/data/cldr/common/dtd/ldmlSupplemental.dtd | 6 make/data/cldr/common/supplemental/metaZones.xml | 20 make/data/hotspot-symbols/symbols-unix | 1 make/hotspot/lib/JvmOverrideFiles.gmk | 4 make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java | 37 make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java | 10 make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java | 5 make/modules/java.sql.rowset/Java.gmk | 1 make/modules/jdk.jpackage/Lib.gmk | 3 src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 10 src/hotspot/cpu/aarch64/register_aarch64.hpp | 131 src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp | 2570 +++++++++- src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp | 20 src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp | 6 src/hotspot/cpu/aarch64/vm_version_aarch64.cpp | 22 src/hotspot/cpu/x86/assembler_x86.cpp | 134 src/hotspot/cpu/x86/assembler_x86.hpp | 13 src/hotspot/cpu/x86/macroAssembler_x86.hpp | 9 src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 6 src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 10 src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp | 1030 ++++ src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp | 946 +++ src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp | 500 + src/hotspot/cpu/x86/stubRoutines_x86.hpp | 2 src/hotspot/cpu/x86/vm_version_x86.cpp | 41 src/hotspot/cpu/x86/x86_32.ad | 33 src/hotspot/cpu/x86/x86_64.ad | 20 src/hotspot/os/linux/os_linux.cpp | 95 src/hotspot/os/linux/os_linux.hpp | 1 src/hotspot/os/windows/os_perf_windows.cpp | 155 src/hotspot/share/c1/c1_Compiler.cpp | 2 src/hotspot/share/c1/c1_GraphBuilder.cpp | 2 src/hotspot/share/c1/c1_LIRGenerator.cpp | 6 src/hotspot/share/c1/c1_LIRGenerator.hpp | 2 src/hotspot/share/classfile/classLoader.cpp | 7 src/hotspot/share/classfile/stringTable.cpp | 7 src/hotspot/share/classfile/symbolTable.cpp | 7 src/hotspot/share/classfile/vmIntrinsics.cpp | 21 src/hotspot/share/classfile/vmIntrinsics.hpp | 49 src/hotspot/share/classfile/vmSymbols.hpp | 2 src/hotspot/share/include/jvm.h | 3 src/hotspot/share/interpreter/abstractInterpreter.cpp | 6 src/hotspot/share/interpreter/abstractInterpreter.hpp | 2 src/hotspot/share/interpreter/templateInterpreterGenerator.cpp | 5 src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp | 4 src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 13 src/hotspot/share/opto/c2compiler.cpp | 15 src/hotspot/share/opto/compile.cpp | 16 src/hotspot/share/opto/escape.cpp | 13 src/hotspot/share/opto/library_call.cpp | 479 + src/hotspot/share/opto/library_call.hpp | 15 src/hotspot/share/opto/loopPredicate.cpp | 19 src/hotspot/share/opto/loopTransform.cpp | 475 + src/hotspot/share/opto/loopnode.cpp | 1452 ++++- src/hotspot/share/opto/loopnode.hpp | 12 src/hotspot/share/opto/runtime.cpp | 261 + src/hotspot/share/opto/runtime.hpp | 13 src/hotspot/share/prims/jvm.cpp | 10 src/hotspot/share/runtime/globals.hpp | 6 src/hotspot/share/runtime/os.cpp | 6 src/hotspot/share/runtime/stubRoutines.cpp | 13 src/hotspot/share/runtime/stubRoutines.hpp | 26 src/hotspot/share/runtime/threads.cpp | 16 src/hotspot/share/runtime/vmStructs.cpp | 13 src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c | 5 src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c | 3 src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java | 25 src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java | 7 src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java | 1574 ++++++ src/java.base/share/classes/com/sun/crypto/provider/ML_KEM_Impls.java | 261 + src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java | 38 src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java | 21 src/java.base/share/classes/java/lang/ref/Reference.java | 11 src/java.base/share/classes/java/net/SocksSocketImpl.java | 42 src/java.base/share/classes/java/text/SimpleDateFormat.java | 27 src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java | 8 src/java.base/share/classes/java/util/zip/ZipFile.java | 23 src/java.base/share/classes/javax/crypto/KeyAgreement.java | 2 src/java.base/share/classes/javax/crypto/KeyAgreementSpi.java | 2 src/java.base/share/classes/jdk/internal/jmod/JmodFile.java | 53 src/java.base/share/classes/module-info.java | 2 src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java | 4 src/java.base/share/classes/sun/net/smtp/SmtpClient.java | 6 src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java | 205 src/java.base/share/classes/sun/security/pkcs/PKCS7.java | 4 src/java.base/share/classes/sun/security/pkcs/SignerInfo.java | 2 src/java.base/share/classes/sun/security/provider/DigestBase.java | 4 src/java.base/share/classes/sun/security/provider/ML_DSA.java | 1641 ++++++ src/java.base/share/classes/sun/security/provider/ML_DSA_Impls.java | 272 + src/java.base/share/classes/sun/security/provider/NamedKEM.java | 218 src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java | 319 + src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java | 214 src/java.base/share/classes/sun/security/provider/NamedSignature.java | 217 src/java.base/share/classes/sun/security/provider/SHA3.java | 331 + src/java.base/share/classes/sun/security/provider/SHA3Parallel.java | 108 src/java.base/share/classes/sun/security/provider/SHAKE256.java | 49 src/java.base/share/classes/sun/security/provider/SunEntries.java | 26 src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java | 4 src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java | 2 src/java.base/share/classes/sun/security/ssl/SSLExtension.java | 8 src/java.base/share/classes/sun/security/ssl/SSLExtensions.java | 11 src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java | 4 src/java.base/share/classes/sun/security/util/HostnameChecker.java | 18 src/java.base/share/classes/sun/security/util/KeyChoices.java | 289 + src/java.base/share/classes/sun/security/util/KeyUtil.java | 37 src/java.base/share/classes/sun/security/util/KnownOIDs.java | 14 src/java.base/share/classes/sun/security/util/SignatureUtil.java | 18 src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java | 30 src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java | 33 src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java | 15 src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java | 32 src/java.base/share/classes/sun/security/validator/SymantecTLSPolicy.java | 65 src/java.base/share/classes/sun/security/x509/AlgorithmId.java | 143 src/java.base/share/classes/sun/security/x509/DNSName.java | 108 src/java.base/share/classes/sun/security/x509/IPAddressName.java | 145 src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java | 19 src/java.base/share/classes/sun/security/x509/NamedX509Key.java | 120 src/java.base/share/classes/sun/security/x509/URIName.java | 24 src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java | 13 src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java | 9 src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java | 16 src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java | 4 src/java.base/share/conf/security/java.security | 42 src/java.base/share/data/cacerts/luxtrustglobalrootca | 28 src/java.base/share/data/tzdata/VERSION | 2 src/java.base/share/data/tzdata/africa | 191 src/java.base/share/data/tzdata/asia | 24 src/java.base/share/data/tzdata/australasia | 2 src/java.base/share/data/tzdata/backward | 54 src/java.base/share/data/tzdata/europe | 51 src/java.base/share/data/tzdata/leapseconds | 8 src/java.base/share/data/tzdata/northamerica | 297 - src/java.base/share/data/tzdata/southamerica | 29 src/java.base/share/data/tzdata/tzmappings.override | 44 src/java.base/share/data/tzdata/zone.tab | 8 src/java.base/share/lib/security/default.policy | 1 src/java.base/share/native/libjava/Reference.c | 8 src/java.base/share/native/libjli/java.c | 2 src/java.base/share/native/libjli/jli_util.c | 4 src/java.base/share/native/libverify/check_code.c | 2 src/java.base/unix/native/libjava/TimeZone_md.c | 76 src/java.base/unix/native/libnet/NetworkInterface.c | 4 src/java.base/unix/native/libnio/ch/Net.c | 8 src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java | 17 src/java.desktop/macosx/classes/sun/lwawt/macosx/CImage.java | 29 src/java.desktop/macosx/native/libawt_lwawt/awt/CImage.m | 5 src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m | 5 src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m | 54 src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/shaders.metal | 10 src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java | 17 src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java | 8 src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java | 57 src/java.desktop/share/classes/javax/swing/event/EventListenerList.java | 11 src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c | 4 src/java.desktop/share/native/libfontmanager/freetypeScaler.c | 8 src/java.instrument/share/native/libinstrument/JPLISAgent.c | 4 src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c | 4 src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java | 4 src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java | 14 src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java | 4 src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java | 4 src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java | 10 src/java.naming/share/classes/com/sun/naming/internal/NamingManagerHelper.java | 29 src/java.naming/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java | 140 src/java.naming/share/classes/module-info.java | 24 src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java | 104 src/java.net.http/share/classes/jdk/internal/net/http/CheckFilename.java | 76 src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java | 4 src/java.net.http/share/classes/jdk/internal/net/http/RedirectFilter.java | 47 src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java | 2 src/java.net.http/share/classes/jdk/internal/net/http/ResponseContent.java | 69 src/java.prefs/unix/native/libprefs/FileSystemPreferences.c | 9 src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java | 246 src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java | 132 src/java.security.jgss/share/classes/sun/security/jgss/krb5/MessageToken_v2.java | 34 src/java.security.jgss/share/classes/sun/security/jgss/krb5/WrapToken_v2.java | 4 src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java | 2 src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java | 7 src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java | 6 src/java.security.jgss/share/classes/sun/security/krb5/internal/ETypeInfo2.java | 5 src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java | 2 src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java | 31 src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java | 6 src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java | 6 src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java | 6 src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java | 5 src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java | 11 src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java | 11 src/java.sql.rowset/share/classes/com/sun/rowset/RowSetResourceBundle.properties | 4 src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java | 34 src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java | 189 src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java | 40 src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlErrorHandler.java | 36 src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java | 186 src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlResolver.java | 44 src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java | 10 src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java | 5 src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java | 13 src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/SchemaNamespaceSupport.java | 7 src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java | 185 src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/MultipleScopeNamespaceSupport.java | 52 src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathContext.java | 31 src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java | 28 src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java | 6 src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java | 5 src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java | 9 src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java | 14 src/java.xml/share/classes/jdk/xml/internal/JdkXmlFeatures.java | 35 src/java.xml/share/classes/module-info.java | 56 src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c | 17 src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c | 15 src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c | 15 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java | 48 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java | 10 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java | 4 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java | 67 src/jdk.crypto.ec/share/classes/sun/security/ec/ECDHKeyAgreement.java | 11 src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java | 8 src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAParameters.java | 4 src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp | 6 src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java | 30 src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java | 125 src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java | 8 src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java | 41 src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java | 3 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js | 18 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js | 6 src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c | 6 src/jdk.jpackage/linux/native/applauncher/ExecCommand.c | 313 + src/jdk.jpackage/linux/native/applauncher/ExecCommand.h | 49 src/jdk.jpackage/linux/native/applauncher/LinuxLauncher.c | 36 src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c | 240 src/jdk.jpackage/linux/native/applauncher/LinuxPackage.h | 21 src/jdk.jpackage/linux/native/libapplauncher/Executor.cpp | 63 src/jdk.jpackage/linux/native/libapplauncher/Executor.h | 4 src/jdk.jpackage/linux/native/libapplauncher/LinuxLauncherLib.cpp | 22 src/jdk.jpackage/linux/native/libapplauncher/Package.cpp | 72 src/jdk.jpackage/linux/native/libapplauncher/Package.h | 15 src/jdk.jpackage/share/native/applauncher/JvmLauncher.h | 8 src/jdk.jpackage/share/native/applauncher/JvmLauncherLib.c | 26 src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java | 70 src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java | 3 src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java | 40 src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java | 55 src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java | 7 src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java | 19 src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java | 157 src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java | 107 src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipInfo.java | 6 test/docs/TEST.ROOT | 4 test/hotspot/gtest/aarch64/aarch64-asmtest.py | 5 test/hotspot/gtest/aarch64/asmtest.out.h | 837 +-- test/hotspot/jtreg/TEST.ROOT | 4 test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java | 40 test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java | 22 test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java | 3 test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java | 6 test/hotspot/jtreg/compiler/rangechecks/TestIndexMatching.java | 833 +++ test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheckWithZeroScaling.java | 53 test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java | 6 test/hotspot/jtreg/containers/docker/DockerBasicTest.java | 8 test/hotspot/jtreg/containers/docker/ShareTmpDir.java | 8 test/hotspot/jtreg/containers/docker/TestCPUAwareness.java | 7 test/hotspot/jtreg/containers/docker/TestCPUSets.java | 10 test/hotspot/jtreg/containers/docker/TestContainerInfo.java | 8 test/hotspot/jtreg/containers/docker/TestJFREvents.java | 5 test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java | 8 test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java | 7 test/hotspot/jtreg/containers/docker/TestJcmd.java | 3 test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java | 8 test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java | 27 test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java | 5 test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java | 5 test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java | 7 test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java | 5 test/hotspot/jtreg/containers/docker/TestMisc.java | 16 test/hotspot/jtreg/containers/docker/TestPids.java | 7 test/hotspot/jtreg/gc/TestNativeReferenceGet.java | 181 test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java | 58 test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java | 107 test/hotspot/jtreg/serviceability/dcmd/thread/PrintTest.java | 5 test/hotspot/jtreg/testlibrary/jittester/conf/exclude.methods.lst | 1 test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003.java | 23 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java | 5 test/jaxp/TEST.ROOT | 2 test/jdk/ProblemList.txt | 10 test/jdk/TEST.ROOT | 6 test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java | 24 test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java | 160 test/jdk/com/sun/net/httpserver/Test10.java | 14 test/jdk/com/sun/net/httpserver/Test3.java | 10 test/jdk/com/sun/net/httpserver/Test4.java | 10 test/jdk/com/sun/net/httpserver/Test5.java | 10 test/jdk/com/sun/net/httpserver/bugs/B6361557.java | 12 test/jdk/com/sun/net/httpserver/bugs/B6393710.java | 4 test/jdk/com/sun/net/httpserver/bugs/B6433018.java | 3 test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java | 6 test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestNoRead.policy | 5 test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestRead.policy | 5 test/jdk/java/awt/Graphics2D/ClearPolyLineUsingXORTest.java | 95 test/jdk/java/awt/Graphics2D/CopyAreaOOB.java | 67 test/jdk/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java | 244 test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java | 10 test/jdk/java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java | 8 test/jdk/java/io/Serializable/records/ProhibitedMethods.java | 7 test/jdk/java/lang/ProcessBuilder/Basic.java | 4 test/jdk/java/lang/ProcessHandle/InfoTest.java | 12 test/jdk/java/net/IPSupport/MinimumPermissions.policy | 2 test/jdk/java/net/httpclient/AsFileDownloadTest.policy | 4 test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest1.policy | 4 test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest2.policy | 4 test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest3.policy | 4 test/jdk/java/net/httpclient/FilePublisher/FilePublisherTest.policy | 4 test/jdk/java/net/httpclient/PathSubscriber/ofFile.policy | 4 test/jdk/java/net/httpclient/PathSubscriber/ofFileDownload.policy | 4 test/jdk/java/net/httpclient/RequestBodyTest.policy | 6 test/jdk/java/net/httpclient/dependent.policy | 4 test/jdk/java/net/httpclient/httpclient-localaddr-security.policy | 4 test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java | 34 test/jdk/java/security/KeyAgreement/Generic.java | 79 test/jdk/java/security/SignedJar/spi-calendar-provider/TestSPISigned.java | 9 test/jdk/java/security/spec/TestNamedParameterSpec.java | 67 test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java | 37 test/jdk/java/time/test/java/time/zone/TestZoneRules.java | 14 test/jdk/java/util/TimeZone/AIXTzMappingTest.java | 102 test/jdk/java/util/TimeZone/Bug6329116.java | 20 test/jdk/java/util/TimeZone/CustomTzIDCheckDST.java | 7 test/jdk/java/util/TimeZone/NegativeDSTTest.java | 17 test/jdk/java/util/TimeZone/TimeZoneData/VERSION | 2 test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt | 8 test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java | 183 test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java | 288 + test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml | 32 test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml | 52 test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml | 32 test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml | 56 test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml | 40 test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml | 36 test/jdk/javax/swing/SwingWorker/TestDoneBeforeDoInBackground.java | 20 test/jdk/jdk/internal/platform/docker/TestDockerBasic.java | 9 test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java | 7 test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java | 5 test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java | 5 test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java | 8 test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java | 30 test/jdk/jdk/internal/platform/docker/TestPidsLimit.java | 7 test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java | 5 test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java | 5 test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java | 1 test/jdk/jdk/jfr/event/os/TestCPULoad.java | 72 test/jdk/jdk/nio/zipfs/EndOfCenValidation.java | 150 test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java | 9 test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java | 2 test/jdk/sun/security/ec/ECDHPrimitive.java | 4 test/jdk/sun/security/ec/ed/TestEdOps.java | 4 test/jdk/sun/security/lib/cacerts/VerifyCACerts.java | 10 test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt | 2 test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java | 24 test/jdk/sun/security/provider/MessageDigest/SHAKEhash.java | 58 test/jdk/sun/security/provider/MessageDigest/SHAKEsqueeze.java | 102 test/jdk/sun/security/provider/acvp/Launcher.java | 210 test/jdk/sun/security/provider/acvp/ML_DSA_Test.java | 175 test/jdk/sun/security/provider/acvp/ML_KEM_Test.java | 128 test/jdk/sun/security/provider/acvp/SHA_Test.java | 139 test/jdk/sun/security/provider/all/Deterministic.java | 2 test/jdk/sun/security/provider/named/NamedEdDSA.java | 256 test/jdk/sun/security/provider/named/NamedKeyFactoryTest.java | 296 + test/jdk/sun/security/provider/named/NamedKeys.java | 103 test/jdk/sun/security/provider/named/namedKeyFactoryTest.policy | 11 test/jdk/sun/security/provider/pqc/PrivateKeyEncodings.java | 227 test/jdk/sun/security/provider/pqc/SeedOrExpanded.java | 194 test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Camerfirma.java | 6 test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java | 9 test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java | 6 test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java | 10 test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java | 14 test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java | 8 test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java | 24 test/jdk/sun/security/x509/AlgorithmId/NullParams.java | 10 test/jdk/sun/security/x509/GeneralName/DNSNameTest.java | 184 test/jdk/sun/security/x509/IPAddressName/ConstrainsTest.java | 98 test/jdk/sun/tools/jstat/jstatGcCapacityOutput1.sh | 3 test/jdk/sun/tools/jstat/jstatGcMetaCapacityOutput1.sh | 3 test/jdk/sun/tools/jstat/jstatGcNewCapacityOutput1.sh | 3 test/jdk/sun/tools/jstat/jstatGcNewOutput1.sh | 3 test/jdk/sun/tools/jstat/jstatGcOldCapacityOutput1.sh | 5 test/jdk/sun/tools/jstat/jstatGcOldOutput1.sh | 3 test/jdk/sun/tools/jstat/jstatGcOutput1.sh | 3 test/jdk/sun/tools/jstat/jstatLineCounts1.sh | 3 test/jdk/sun/tools/jstat/jstatLineCounts2.sh | 3 test/jdk/sun/tools/jstat/jstatLineCounts3.sh | 3 test/jdk/sun/tools/jstat/jstatLineCounts4.sh | 3 test/jdk/sun/tools/jstat/jstatTimeStamp1.sh | 3 test/jdk/sun/util/resources/TimeZone/Bug8139107.java | 7 test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java | 27 test/jdk/sun/util/resources/cldr/Bug8202764.java | 21 test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java | 71 test/langtools/TEST.ROOT | 2 test/langtools/jdk/jshell/RemoteAgentHandshakeTest.java | 128 test/langtools/jdk/jshell/UserJdiUserRemoteTest.java | 5 test/lib-test/TEST.ROOT | 4 test/lib-test/jdk/test/lib/AssertsTest.java | 41 test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java | 229 test/lib-test/jdk/test/lib/security/FixedSecureRandomTest.java | 49 test/lib/jdk/test/lib/Asserts.java | 84 test/lib/jdk/test/lib/Utils.java | 32 test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java | 25 test/lib/jdk/test/lib/process/Proc.java | 11 test/lib/jdk/test/lib/security/CertificateBuilder.java | 61 test/lib/jdk/test/lib/security/DerUtils.java | 14 test/lib/jdk/test/lib/security/FixedSecureRandom.java | 72 test/lib/jdk/test/lib/security/RepositoryFileReader.java | 160 test/lib/jdk/test/lib/security/SeededSecureRandom.java | 6 test/lib/jdk/test/lib/security/SimpleOCSPServer.java | 91 test/lib/jdk/test/lib/util/ZipUtils.java | 247 test/micro/org/openjdk/bench/java/security/HSS.java | 388 - test/micro/org/openjdk/bench/javax/crypto/full/HSSBench.java | 363 + test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java | 82 test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java | 25 test/micro/org/openjdk/bench/javax/crypto/full/SignatureBench.java | 15 test/micro/org/openjdk/bench/javax/crypto/small/HSSBench.java | 27 test/micro/org/openjdk/bench/javax/crypto/small/KEMBench.java | 32 test/micro/org/openjdk/bench/javax/crypto/small/KeyPairGeneratorBench.java | 20 test/micro/org/openjdk/bench/javax/crypto/small/SignatureBench.java | 15 450 files changed, 26544 insertions(+), 5208 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp14hipkn_/openjdk-21_21.0.12.1+1-1~deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp14hipkn_/openjdk-21_21.0.13+9-1~deb13u1.dsc: no acceptable signature found diff -Nru openjdk-21-21.0.12.1+1/.jcheck/conf openjdk-21-21.0.13+9/.jcheck/conf --- openjdk-21-21.0.12.1+1/.jcheck/conf 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/.jcheck/conf 2026-10-19 12:10:20.000000000 +0000 @@ -1,7 +1,7 @@ [general] project=jdk-updates jbs=JDK -version=21.0.12.1 +version=21.0.13 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists diff -Nru openjdk-21-21.0.12.1+1/debian/JB-jre-headless.overrides.in openjdk-21-21.0.13+9/debian/JB-jre-headless.overrides.in --- openjdk-21-21.0.12.1+1/debian/JB-jre-headless.overrides.in 2026-08-18 20:47:27.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/JB-jre-headless.overrides.in 2026-10-22 01:18:55.000000000 +0000 @@ -19,3 +19,8 @@ # 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/client/libjvm.so] +@basename@-jre-headless binary: specific-address-in-shared-library [usr/lib/jvm/java-@RELEASE@-openjdk-i386/lib/server/libjvm.so] diff -Nru openjdk-21-21.0.12.1+1/debian/JB-jre-zero.overrides.in openjdk-21-21.0.13+9/debian/JB-jre-zero.overrides.in --- openjdk-21-21.0.12.1+1/debian/JB-jre-zero.overrides.in 2026-08-17 05:08:09.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/JB-jre-zero.overrides.in 2026-10-22 01:18:55.000000000 +0000 @@ -7,3 +7,7 @@ # repeated lib due to upstream implementation directory layout @basename@-jre-zero binary: repeated-path-segment + +# https://bugs.openjdk.org/browse/JDK-6454213 - i386 openjdk libjvm.so includes +# code compiled with -fno-PIC. +@basename@-jre-zero binary: specific-address-in-shared-library [usr/lib/jvm/java-@RELEASE@-openjdk-i386/lib/zero/libjvm.so] diff -Nru openjdk-21-21.0.12.1+1/debian/JB-testsupport.overrides.in openjdk-21-21.0.13+9/debian/JB-testsupport.overrides.in --- openjdk-21-21.0.12.1+1/debian/JB-testsupport.overrides.in 2026-08-18 21:23:33.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/JB-testsupport.overrides.in 2026-10-22 01:18:55.000000000 +0000 @@ -1,2 +1,7 @@ # 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/client/libjvm.so] +@basename@-testsupport binary: specific-address-in-shared-library [usr/lib/jvm/java-@RELEASE@-openjdk-i386/testsuite/hotspot/gtest/server/libjvm.so] diff -Nru openjdk-21-21.0.12.1+1/debian/changelog openjdk-21-21.0.13+9/debian/changelog --- openjdk-21-21.0.12.1+1/debian/changelog 2026-08-19 17:55:58.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/changelog 2026-10-22 20:55:07.000000000 +0000 @@ -1,8 +1,87 @@ -openjdk-21 (21.0.12.1+1-1~deb13u1) trixie-security; urgency=medium +openjdk-21 (21.0.13+9-1~deb13u1) trixie-security; urgency=medium * Rebuild for trixie - -- Moritz Muehlenhoff Wed, 19 Aug 2026 19:55:58 +0200 + -- Moritz Muehlenhoff Thu, 22 Oct 2026 22:55:07 +0200 + +openjdk-21 (21.0.13+9-1) unstable; urgency=medium + + * OpenJDK 21.0.13 release, build 9. + - 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-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/watch: Regenerate. + + -- Vladimir Petko Thu, 22 Oct 2026 14:19:01 +1300 + +openjdk-21 (21.0.13~8ea-1) unstable; urgency=medium + + * OpenJDK 21.0.13 early access, build 8. + + [ Reuben Roessler ] + * d/p/jdk-8384505.diff: Account for all jtreg-based frames in stack + walk test (JDK-8384505). + + [ Vladimir Petko ] + * d/t: Add loong64 specific problemlists. + * 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. + + -- Vladimir Petko Thu, 08 Oct 2026 19:37:43 +1300 + +openjdk-21 (21.0.13~6ea-1) unstable; urgency=medium + + * OpenJDK 21.0.13 early access, build 6. + * d/JB-{jre-headless,jre-zero,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. + * d/p/{jdk-8334502-proposed.patch,debian/patches/jdk-8359735.patch}: + Drop patches applied upstream. + * d/rules: Require jtreg8 package (Closes: #1096195). + * Regenerate control files. + + -- Vladimir Petko Wed, 16 Sep 2026 08:41:53 +1200 openjdk-21 (21.0.12.1+1-1) unstable; urgency=medium diff -Nru openjdk-21-21.0.12.1+1/debian/control openjdk-21-21.0.13+9/debian/control --- openjdk-21-21.0.12.1+1/debian/control 2026-08-19 17:55:42.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/control 2026-10-22 20:55:07.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), - jtreg7 (>= 7.5.2+1~) , libtestng7-java , xvfb , xauth , xfonts-base , libgl1-mesa-dri [!x32] , xfwm4 , x11-xkb-utils , dbus-x11 , libasmtools-java , xvfb , + jtreg8 , libtestng7-java , xvfb , xauth , xfonts-base , libgl1-mesa-dri [!x32] , xfwm4 , x11-xkb-utils , dbus-x11 , libasmtools-java , xvfb , autoconf, automake, ant, ant-optional, g++-14 , openjdk-21-jdk-headless:native | openjdk-20-jdk-headless:native, @@ -179,7 +179,7 @@ Multi-Arch: same Depends: openjdk-21-jdk (= ${binary:Version}), build-essential, xfwm4, xvfb, dbus-x11, libatk-wrapper-java, - libatk-wrapper-java-jni, jtreg7 (>= 7.5.2+1~), 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-21-21.0.12.1+1/debian/patches/jdk-8334502-proposed.patch openjdk-21-21.0.13+9/debian/patches/jdk-8334502-proposed.patch --- openjdk-21-21.0.12.1+1/debian/patches/jdk-8334502-proposed.patch 2026-08-18 21:23:33.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/patches/jdk-8334502-proposed.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -Description: use int instead of time_t to print timezone info - printf() call uses %02d format specifier that requires an int parameter. -Author: Vladimir Petko -Bug: https://bugs.openjdk.org/browse/JDK-8334502 -Last-Update: 2024-06-19 - ---- a/src/hotspot/share/runtime/os.cpp -+++ b/src/hotspot/share/runtime/os.cpp -@@ -198,8 +198,8 @@ char* os::iso8601_time(jlong millisecond - abs_local_to_UTC = -(abs_local_to_UTC); - } - // Convert time zone offset seconds to hours and minutes. -- const time_t zone_hours = (abs_local_to_UTC / seconds_per_hour); -- const time_t zone_min = -+ const int zone_hours = (abs_local_to_UTC / seconds_per_hour); -+ const int zone_min = - ((abs_local_to_UTC % seconds_per_hour) / seconds_per_minute); - - // Print an ISO 8601 date and time stamp into the buffer diff -Nru openjdk-21-21.0.12.1+1/debian/patches/jdk-8359735.patch openjdk-21-21.0.13+9/debian/patches/jdk-8359735.patch --- openjdk-21-21.0.12.1+1/debian/patches/jdk-8359735.patch 2026-08-18 21:23:33.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/patches/jdk-8359735.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -Description: Process tests fail due to rust-coreutils - To accommodate systems like Ubuntu 25.10 that use Rust coreutils, - this PR updates tests that previously assumed busybox was the only - environment to use symlinks for core utilities. - - java/lang/ProcessBuilder/Basic.java: The test is updated to simply - verify that /bin/true and /bin/false are symlinks, - removing the hardcoded check for a /bin/busybox target. - - java/lang/ProcessHandle/InfoTest.java: The test logic is relaxed. - It now confirms that /bin/sleep is a symlink and then uses the - symlink's target as the expected executable name. -Author: Vladimir Petko -Origin: upstream, https://github.com/openjdk/jdk/pull/25838 -Bug: https://bugs.openjdk.org/browse/JDK-8359735 -Reviewed-by: Roger Riggs -Last-Update: 2025-06-19 ---- - ---- a/test/jdk/java/lang/ProcessBuilder/Basic.java -+++ b/test/jdk/java/lang/ProcessBuilder/Basic.java -@@ -699,7 +699,7 @@ public class Basic { - public static String path() { return path; } - private static final String path = path0(); - private static String path0(){ -- if (!Platform.isBusybox("/bin/true")) { -+ if (!Files.isSymbolicLink(Paths.get("/bin/true"))) { - return "/bin/true"; - } else { - File trueExe = new File("true"); -@@ -714,7 +714,7 @@ public class Basic { - public static String path() { return path; } - private static final String path = path0(); - private static String path0(){ -- if (!Platform.isBusybox("/bin/false")) { -+ if (!Files.isSymbolicLink(Paths.get("/bin/false"))) { - return "/bin/false"; - } else { - File falseExe = new File("false"); ---- a/test/jdk/java/lang/ProcessHandle/InfoTest.java -+++ b/test/jdk/java/lang/ProcessHandle/InfoTest.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -294,10 +294,12 @@ public class InfoTest { - String expected = "sleep"; - if (Platform.isWindows()) { - expected = "sleep.exe"; -- } else if (Platform.isBusybox("/bin/sleep")) { -- // With busybox sleep is just a sym link to busybox. -- // The busbox executable is seen as ProcessHandle.Info command. -- expected = "busybox"; -+ } else if (Files.isSymbolicLink(Paths.get("/bin/sleep"))) { -+ // Busybox sleep is a symbolic link to /bin/busybox. -+ // Rust coreutils sleep is a symbolic link to coreutils -+ // The busbox/coreutils executables are seen as ProcessHandle.Info command. -+ Path executable = Files.readSymbolicLink(Paths.get("/bin/sleep")); -+ expected = executable.getFileName().toString(); - } - Assert.assertTrue(command.endsWith(expected), "Command: expected: \'" + - expected + "\', actual: " + command); diff -Nru openjdk-21-21.0.12.1+1/debian/patches/jdk-8384505.diff openjdk-21-21.0.13+9/debian/patches/jdk-8384505.diff --- openjdk-21-21.0.12.1+1/debian/patches/jdk-8384505.diff 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/patches/jdk-8384505.diff 2026-10-22 01:18:55.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 +@@ -58,11 +58,11 @@ + "jdk.internal.reflect.NativeMethodAccessorImpl", + "jdk.internal.reflect.DelegatingMethodAccessorImpl", + "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") +@@ -133,6 +133,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-21-21.0.12.1+1/debian/patches/series openjdk-21-21.0.13+9/debian/patches/series --- openjdk-21-21.0.12.1+1/debian/patches/series 2026-08-18 21:23:33.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/patches/series 2026-10-22 01:18:55.000000000 +0000 @@ -40,13 +40,12 @@ jdk-8295795.patch hsdis-fpic.patch jdk-8329983.patch -jdk-8334502-proposed.patch jdk-8331541.patch jdk-8336529-proposed.patch jdk-8312488.patch # FIXME: which one of these two? zero-alpha-workaround.diff #jdk-8347014-proposed.patch -jdk-8359735.patch jdk-8381555.diff jdk-8387580.diff +jdk-8384505.diff diff -Nru openjdk-21-21.0.12.1+1/debian/rules openjdk-21-21.0.13+9/debian/rules --- openjdk-21-21.0.12.1+1/debian/rules 2026-08-18 21:45:12.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/rules 2026-10-22 01:18:55.000000000 +0000 @@ -84,6 +84,7 @@ is_upstream_release = yes + srcdir = . builddir = build zbuilddir = build-zero @@ -161,13 +162,8 @@ NJOBS = $(subst parallel=,,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) endif -ifneq (,$(filter $(distrel), sid bookworm bullseye)) - jtreg_pkg = jtreg# debian will have jtreg7 in jtreg package - testng_pkg = libtestng7-java -else - jtreg_pkg = jtreg7 - testng_pkg = libtestng7-java -endif +jtreg_pkg = jtreg8 +testng_pkg = libtestng7-java with_check = $(if $(findstring nocheck, $(DEB_BUILD_OPTIONS)$(DEB_BUILD_PROFILES)),,yes) ifneq (,$(filter $(DEB_HOST_ARCH), alpha arc armel ia64 mipsel mips64el powerpc riscv64 x32)) @@ -295,6 +291,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 @@ -304,13 +318,15 @@ 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$(if $(filter $(DEB_HOST_ARCH), armel armhf), -fno-delete-null-pointer-checks)" \ - DEB_CXXFLAGS_MAINT_APPEND="-fno-stack-protector -Wno-deprecated-declarations$(if $(filter $(DEB_HOST_ARCH), armel armhf), -fpermissive -fno-delete-null-pointer-checks)" + DEB_CFLAGS_MAINT_APPEND="$(NO_TREE_SLP_VECTORIZE) -fno-stack-protector -Wno-deprecated-declarations$(if $(filter $(DEB_HOST_ARCH), armel armhf), -fno-delete-null-pointer-checks)" \ + DEB_CXXFLAGS_MAINT_APPEND="$(NO_TREE_SLP_VECTORIZE) -fno-stack-protector -Wno-deprecated-declarations$(if $(filter $(DEB_HOST_ARCH), armel armhf), -fpermissive -fno-delete-null-pointer-checks)" # 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 @@ -325,7 +341,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) @@ -446,6 +462,13 @@ ZERO_CONFIGURE_ARGS += --with-boot-jdk-jvmargs="-XX:ThreadStackSize=2240" 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 @@ -2084,7 +2107,7 @@ dh_builddeb -a $(nodemo) $(nojrez) #$(bd_options) git_project = jdk21u -git_tag = jdk-21.0.12.1+1 +git_tag = jdk-21.0.13+9 package_version = $(shell echo $(PKGVERSION) | sed 's/-[^-][^-]*$$//') ifneq ($(is_upstream_release),yes) package_version := $(subst +,~,$(package_version)) diff -Nru openjdk-21-21.0.12.1+1/debian/tests/control openjdk-21-21.0.13+9/debian/tests/control --- openjdk-21-21.0.12.1+1/debian/tests/control 2026-08-19 17:55:42.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/tests/control 2026-10-22 20:54:43.000000000 +0000 @@ -7,12 +7,12 @@ Restrictions: allow-stderr, superficial Tests: hotspot-autopkgtest.sh -Depends: @, jtreg7 (>= 7.5.2+1~), libtestng7-java, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-x11, libatk-wrapper-java, libatk-wrapper-java-jni +Depends: @, jtreg8 (>= 8.2.1+1~), libtestng7-java, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-x11, libatk-wrapper-java, libatk-wrapper-java-jni Restrictions: allow-stderr, skippable, flaky, rw-build-tree Architecture: amd64 i386 arm64 armhf ppc64 ppc64el riscv64 s390x alpha ia64 powerpc ppc64 sh4 x32 armel loong64 mipsel mips64el riscv64 Tests: jdk-autopkgtest.sh -Depends: @, jtreg7 (>= 7.5.2+1~), libtestng7-java, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-x11, libatk-wrapper-java, libatk-wrapper-java-jni +Depends: @, jtreg8 (>= 8.2.1+1~), libtestng7-java, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-x11, libatk-wrapper-java, libatk-wrapper-java-jni Restrictions: allow-stderr, skippable, flaky, rw-build-tree Architecture: amd64 i386 arm64 armhf ppc64 ppc64el riscv64 s390x alpha ia64 powerpc ppc64 sh4 x32 armel loong64 mipsel mips64el riscv64 diff -Nru openjdk-21-21.0.12.1+1/debian/tests/problems-loong-hotspot.txt openjdk-21-21.0.13+9/debian/tests/problems-loong-hotspot.txt --- openjdk-21-21.0.12.1+1/debian/tests/problems-loong-hotspot.txt 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/tests/problems-loong-hotspot.txt 2026-10-22 01:18:55.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-21-21.0.12.1+1/debian/tests/problems-loong-jdk.txt openjdk-21-21.0.13+9/debian/tests/problems-loong-jdk.txt --- openjdk-21-21.0.12.1+1/debian/tests/problems-loong-jdk.txt 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/tests/problems-loong-jdk.txt 2026-10-22 01:18:55.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-21-21.0.12.1+1/debian/tests/problems-loong-other.txt openjdk-21-21.0.13+9/debian/tests/problems-loong-other.txt --- openjdk-21-21.0.12.1+1/debian/tests/problems-loong-other.txt 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/tests/problems-loong-other.txt 2026-10-22 01:18:55.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-21-21.0.12.1+1/debian/tests/problems.csv openjdk-21-21.0.13+9/debian/tests/problems.csv --- openjdk-21-21.0.12.1+1/debian/tests/problems.csv 2026-08-13 11:28:41.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/tests/problems.csv 2026-10-22 01:18:55.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-21-21.0.12.1+1/debian/tests/write-problems.in openjdk-21-21.0.13+9/debian/tests/write-problems.in --- openjdk-21-21.0.12.1+1/debian/tests/write-problems.in 2026-03-30 08:49:17.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/tests/write-problems.in 2026-10-22 01:18:55.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-21-21.0.12.1+1/debian/tests/write-problems.sh openjdk-21-21.0.13+9/debian/tests/write-problems.sh --- openjdk-21-21.0.12.1+1/debian/tests/write-problems.sh 2026-08-18 21:23:33.000000000 +0000 +++ openjdk-21-21.0.13+9/debian/tests/write-problems.sh 2026-10-22 01:18:55.000000000 +0000 @@ -11,3 +11,9 @@ grep -e ${distrel} -e "release-all" | \ grep -e "openjdk-21" | \ 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-21-21.0.12.1+1/doc/testing.html openjdk-21-21.0.13+9/doc/testing.html --- openjdk-21-21.0.12.1+1/doc/testing.html 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/doc/testing.html 2026-10-19 12:10:20.000000000 +0000 @@ -509,6 +509,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-21-21.0.12.1+1/doc/testing.md openjdk-21-21.0.13+9/doc/testing.md --- openjdk-21-21.0.12.1+1/doc/testing.md 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/doc/testing.md 2026-10-19 12:10:20.000000000 +0000 @@ -498,6 +498,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-21-21.0.12.1+1/make/RunTests.gmk openjdk-21-21.0.13+9/make/RunTests.gmk --- openjdk-21-21.0.12.1+1/make/RunTests.gmk 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 $(CUSTOM_JTREG_SINGLE_KEYWORDS), \ + RETRY_COUNT REPEAT_COUNT MAX_OUTPUT REPORT MANUAL \ + $(CUSTOM_JTREG_SINGLE_KEYWORDS), \ STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS KEYWORDS \ EXTRA_PROBLEM_LISTS LAUNCHER_OPTIONS \ $(CUSTOM_JTREG_STRING_KEYWORDS), \ @@ -793,7 +794,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-21-21.0.12.1+1/make/autoconf/flags-ldflags.m4 openjdk-21-21.0.13+9/make/autoconf/flags-ldflags.m4 --- openjdk-21-21.0.12.1+1/make/autoconf/flags-ldflags.m4 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/make/autoconf/flags-ldflags.m4 2026-10-19 12:10:20.000000000 +0000 @@ -101,6 +101,9 @@ # Setup OS-dependent LDFLAGS if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$TOOLCHAIN_TYPE" = xclang; then + if test x$DEBUG_LEVEL = xrelease; then + BASIC_LDFLAGS_JDK_ONLY="$BASIC_LDFLAGS_JDK_ONLY -Wl,-dead_strip" + fi # FIXME: We should really generalize SET_SHARED_LIBRARY_ORIGIN instead. OS_LDFLAGS_JVM_ONLY="-Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." OS_LDFLAGS="-mmacosx-version-min=$MACOSX_VERSION_MIN" diff -Nru openjdk-21-21.0.12.1+1/make/autoconf/lib-tests.m4 openjdk-21-21.0.13+9/make/autoconf/lib-tests.m4 --- openjdk-21-21.0.12.1+1/make/autoconf/lib-tests.m4 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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=7.5.2 +JTREG_MINIMUM_VERSION=8.2.1 GTEST_MINIMUM_VERSION=1.14.0 ############################################################################### diff -Nru openjdk-21-21.0.12.1+1/make/conf/github-actions.conf openjdk-21-21.0.13+9/make/conf/github-actions.conf --- openjdk-21-21.0.12.1+1/make/conf/github-actions.conf 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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=7.5.2+1 +JTREG_VERSION=8.2.1+1 LINUX_X64_BOOT_JDK_EXT=tar.gz LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.11%2B10/OpenJDK21U-jdk_x64_linux_hotspot_21.0.11_10.tar.gz diff -Nru openjdk-21-21.0.12.1+1/make/conf/jib-profiles.js openjdk-21-21.0.13+9/make/conf/jib-profiles.js --- openjdk-21-21.0.12.1+1/make/conf/jib-profiles.js 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/make/conf/jib-profiles.js 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 @@ -1200,9 +1200,9 @@ jtreg: { server: "jpg", product: "jtreg", - version: "7.5.2", + version: "8.2.1", build_number: "1", - file: "bundles/jtreg-7.5.2+1.zip", + 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"), @@ -1532,7 +1532,7 @@ var isWsl = function (input) { return ( input.build_osenv == "wsl" || (input.build_os == "linux" - && java.lang.System.getProperty("os.version").contains("Microsoft"))); + && java.lang.System.getProperty("os.version").toLowerCase().contains("microsoft"))); } var error = function (s) { diff -Nru openjdk-21-21.0.12.1+1/make/conf/version-numbers.conf openjdk-21-21.0.13+9/make/conf/version-numbers.conf --- openjdk-21-21.0.12.1+1/make/conf/version-numbers.conf 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/make/conf/version-numbers.conf 2026-10-19 12:10:20.000000000 +0000 @@ -28,12 +28,12 @@ DEFAULT_VERSION_FEATURE=21 DEFAULT_VERSION_INTERIM=0 -DEFAULT_VERSION_UPDATE=12 -DEFAULT_VERSION_PATCH=1 +DEFAULT_VERSION_UPDATE=13 +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=65 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 diff -Nru openjdk-21-21.0.12.1+1/make/data/cldr/common/dtd/ldmlSupplemental.dtd openjdk-21-21.0.13+9/make/data/cldr/common/dtd/ldmlSupplemental.dtd --- openjdk-21-21.0.12.1+1/make/data/cldr/common/dtd/ldmlSupplemental.dtd 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/make/data/cldr/common/dtd/ldmlSupplemental.dtd 2026-10-19 12:10:20.000000000 +0000 @@ -953,6 +953,12 @@ + + + + + + diff -Nru openjdk-21-21.0.12.1+1/make/data/cldr/common/supplemental/metaZones.xml openjdk-21-21.0.13+9/make/data/cldr/common/supplemental/metaZones.xml --- openjdk-21-21.0.12.1+1/make/data/cldr/common/supplemental/metaZones.xml 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ - + @@ -381,7 +383,7 @@ - + @@ -477,7 +479,7 @@ - + @@ -654,7 +656,7 @@ - + @@ -747,20 +749,20 @@ - + - + - + @@ -1234,8 +1236,8 @@ - - + + diff -Nru openjdk-21-21.0.12.1+1/make/data/hotspot-symbols/symbols-unix openjdk-21-21.0.13+9/make/data/hotspot-symbols/symbols-unix --- openjdk-21-21.0.12.1+1/make/data/hotspot-symbols/symbols-unix 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/make/data/hotspot-symbols/symbols-unix 2026-10-19 12:10:20.000000000 +0000 @@ -188,6 +188,7 @@ JVM_RawMonitorEnter JVM_RawMonitorExit JVM_ReferenceClear +JVM_ReferenceGet JVM_ReferenceRefersTo JVM_RegisterContinuationMethods JVM_RegisterLambdaProxyClassForArchiving diff -Nru openjdk-21-21.0.12.1+1/make/hotspot/lib/JvmOverrideFiles.gmk openjdk-21-21.0.13+9/make/hotspot/lib/JvmOverrideFiles.gmk --- openjdk-21-21.0.12.1+1/make/hotspot/lib/JvmOverrideFiles.gmk 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/make/hotspot/lib/JvmOverrideFiles.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -37,6 +37,10 @@ # Need extra inlining to collapse shared marking code into the hot marking loop BUILD_LIBJVM_shenandoahMark.cpp_CXXFLAGS := --param inline-unit-growth=1000 endif + # disable lto in g1ParScanThreadState because of special inlining/flattening used there + ifeq ($(call check-jvm-feature, link-time-opt), true) + BUILD_LIBJVM_g1ParScanThreadState.cpp_CXXFLAGS := -fno-lto + endif endif LIBJVM_FDLIBM_COPY_OPT_FLAG := $(CXX_O_FLAG_NONE) diff -Nru openjdk-21-21.0.12.1+1/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java openjdk-21-21.0.13+9/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java --- openjdk-21-21.0.12.1+1/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java 2026-10-19 12:10:20.000000000 +0000 @@ -34,6 +34,7 @@ import java.time.*; import java.util.*; import java.util.ResourceBundle.Control; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -87,6 +88,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 META_EMPTY_ZONE_NAME = "EMPTY_ZONE"; static final String[] EMPTY_ZONE = {"", "", "", "", "", ""}; @@ -122,6 +124,11 @@ static Map pluralRules; static Map dayPeriodRules; + // 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, @@ -772,6 +779,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); @@ -1126,7 +1139,8 @@ private static Stream tzDataLinkEntry() { try { return Files.walk(Paths.get(tzDataDir), 1) - .filter(p -> !Files.isDirectory(p)) + .filter(p -> p.toFile().isFile()) + .filter(p -> p.getFileName().toString().matches("africa|antarctica|asia|australasia|backward|etcetera|europe|northamerica|southamerica")) .flatMap(CLDRConverter::extractLinks) .sorted(); } catch (IOException e) { @@ -1157,10 +1171,31 @@ // Note: the entries are alphabetically sorted, *except* the "world" region // code, i.e., "001". It should be the last entry for the same windows time // zone name entries. (cf. TimeZone_md.c) + // + // The default entries from CLDR's windowsZones.xml file can be modified + // with /tzmappings.override where mapping overrides + // can be specified. + private static Pattern OVERRIDE_PATTERN = Pattern.compile("(?([^:]+:[^:]+)):(?[^:]+):"); private static void generateWindowsTZMappings() throws Exception { Files.createDirectories(Paths.get(DESTINATION_DIR, "windows", "conf")); + var override = Path.of(tzDataDir, "tzmappings.override"); + if (override.toFile().exists()) { + Files.readAllLines(override).stream() + .map(String::trim) + .filter(o -> !o.isBlank() && !o.startsWith("#")) + .forEach(o -> { + var m = OVERRIDE_PATTERN.matcher(o); + if (m.matches()) { + handlerWinZones.put(m.group("win"), m.group("java")); + } else { + System.out.printf("Unrecognized tzmappings override: %s. Ignored%n", o); + } + }); + } Files.write(Paths.get(DESTINATION_DIR, "windows", "conf", "tzmappings"), handlerWinZones.keySet().stream() + .filter(k -> k.endsWith(":001") || + !handlerWinZones.get(k).equals(handlerWinZones.get(k.replaceFirst(":\\w{2,3}$", ":001")))) .map(k -> k + ":" + handlerWinZones.get(k) + ":") .sorted(new Comparator() { public int compare(String t1, String t2) { diff -Nru openjdk-21-21.0.12.1+1/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java openjdk-21-21.0.13+9/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java --- openjdk-21-21.0.12.1+1/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java openjdk-21-21.0.13+9/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java --- openjdk-21-21.0.12.1+1/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, 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 @@ -197,7 +197,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-21-21.0.12.1+1/make/modules/java.sql.rowset/Java.gmk openjdk-21-21.0.13+9/make/modules/java.sql.rowset/Java.gmk --- openjdk-21-21.0.12.1+1/make/modules/java.sql.rowset/Java.gmk 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/make/modules/java.sql.rowset/Java.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -27,6 +27,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-21-21.0.12.1+1/make/modules/jdk.jpackage/Lib.gmk openjdk-21-21.0.13+9/make/modules/jdk.jpackage/Lib.gmk --- openjdk-21-21.0.12.1+1/make/modules/jdk.jpackage/Lib.gmk 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/make/modules/jdk.jpackage/Lib.gmk 2026-10-19 12:10:20.000000000 +0000 @@ -65,7 +65,7 @@ INCLUDE_FILES := $(JPACKAGE_APPLAUNCHER_INCLUDE_FILES), \ TOOLCHAIN := $(JPACKAGE_APPLAUNCHER_TOOLCHAIN), \ OPTIMIZATION := LOW, \ - DISABLED_WARNINGS_clang_LinuxPackage.c := format-nonliteral, \ + DISABLED_WARNINGS_clang_ExecCommand.c := format-nonliteral, \ DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \ CXXFLAGS := $(call JpackageWithStaticCrt, $(CXXFLAGS_JDKEXE)) \ $(JPACKAGE_APPLAUNCHER_INCLUDES), \ @@ -105,6 +105,7 @@ EXCLUDE_FILES := LinuxLauncher.c LinuxPackage.c, \ TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ OPTIMIZATION := LOW, \ + DISABLED_WARNINGS_clang_ExecCommand.c := format-nonliteral, \ DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \ DISABLED_WARNINGS_clang_tstrings.cpp := format-nonliteral, \ CXXFLAGS := $(CXXFLAGS_JDKLIB) $(JPACKAGE_LIBAPPLAUNCHER_INCLUDES), \ diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/assembler_aarch64.hpp openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/assembler_aarch64.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/assembler_aarch64.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/assembler_aarch64.hpp 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. * Copyright (c) 2014, 2024, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2571,6 +2571,11 @@ ldst_sstr(T, index, a, op1, op2, Vt, Vt2, Vt3, Vt4); \ } + INSN1(ld1, 0b001101010, 0b0000); + INSN2(ld2, 0b001101011, 0b0000); + INSN3(ld3, 0b001101010, 0b0010); + INSN4(ld4, 0b001101011, 0b0010); + INSN1(st1, 0b001101000, 0b0000); INSN2(st2, 0b001101001, 0b0000); INSN3(st3, 0b001101000, 0b0010); @@ -2605,6 +2610,7 @@ void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \ guarantee(T != T1Q && T != T1D, "incorrect arrangement"); \ if (!acceptT2D) guarantee(T != T2D, "incorrect arrangement"); \ + if (opc2 == 0b101101) guarantee(T != T8B && T != T16B, "incorrect arrangement"); \ starti; \ f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \ f((int)T >> 1, 23, 22), f(1, 21), rf(Vm, 16), f(opc2, 15, 10); \ @@ -2628,6 +2634,8 @@ INSN(minv, 0, 0b011011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(smaxp, 0, 0b101001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(sminp, 0, 0b101011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S + INSN(sqdmulh,0, 0b101101, false); // accepted arrangements: T4H, T8H, T2S, T4S + INSN(shsubv, 0, 0b001001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S #undef INSN diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/register_aarch64.hpp openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/register_aarch64.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/register_aarch64.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/register_aarch64.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -408,4 +408,135 @@ return as_Register(reg->encoding()); } +// AArch64 Vector Register Sequence management support +// +// VSeq implements an indexable (by operator[]) vector register +// sequence starting from a fixed base register and with a fixed delta +// (defaulted to 1, but sometimes 0 or 2) e.g. VSeq<4>(16) will return +// registers v16, ... v19 for indices 0, ... 3. +// +// Generator methods may iterate across sets of VSeq<4> to schedule an +// operation 4 times using distinct input and output registers, +// profiting from 4-way instruction parallelism. +// +// A VSeq<2> can be used to specify registers loaded with special +// constants e.g. --> . +// +// A VSeq with base n and delta 0 can be used to generate code that +// combines values in another VSeq with the constant in register vn. +// +// A VSeq with base n and delta 2 can be used to select an odd or even +// indexed set of registers. +// +// Methods which accept arguments of type VSeq<8>, may split their +// inputs into front and back halves or odd and even halves (see +// convenience methods below). + +// helper macro for computing register masks +#define VS_MASK_BIT(base, delta, i) (1 << (base + delta * i)) + +template class VSeq { + static_assert(N >= 2, "vector sequence length must be greater than 1"); +private: + int _base; // index of first register in sequence + int _delta; // increment to derive successive indices +public: + VSeq(FloatRegister base_reg, int delta = 1) : VSeq(base_reg->encoding(), delta) { } + VSeq(int base, int delta = 1) : _base(base), _delta(delta) { + assert (_base >= 0 && _base <= 31, "invalid base register"); + assert ((_base + (N - 1) * _delta) >= 0, "register range underflow"); + assert ((_base + (N - 1) * _delta) < 32, "register range overflow"); + } + // indexed access to sequence + FloatRegister operator [](int i) const { + assert (0 <= i && i < N, "index out of bounds"); + return as_FloatRegister(_base + i * _delta); + } + int mask() const { + int m = 0; + for (int i = 0; i < N; i++) { + m |= VS_MASK_BIT(_base, _delta, i); + } + return m; + } + int base() const { return _base; } + int delta() const { return _delta; } + bool is_constant() const { return _delta == 0; } +}; + +// methods for use in asserts to check VSeq inputs and outputs are +// either disjoint or equal + +template bool vs_disjoint(const VSeq& n, const VSeq& m) { return (n.mask() & m.mask()) == 0; } +template bool vs_same(const VSeq& n, const VSeq& m) { return n.mask() == m.mask(); } + +// method for use in asserts to check whether registers appearing in +// an output sequence will be written before they are read from an +// input sequence. + +template bool vs_write_before_read(const VSeq& vout, const VSeq& vin) { + int b_in = vin.base(); + int d_in = vin.delta(); + int b_out = vout.base(); + int d_out = vout.delta(); + int bit_in = 1 << b_in; + int bit_out = 1 << b_out; + int mask_read = vin.mask(); // all pending reads + int mask_write = 0; // no writes as yet + + + for (int i = 0; i < N - 1; i++) { + // check whether a pending read clashes with a write + if ((mask_write & mask_read) != 0) { + return true; + } + // remove the pending input (so long as this is a constant + // sequence) + if (d_in != 0) { + mask_read ^= VS_MASK_BIT(b_in, d_in, i); + } + // record the next write + mask_write |= VS_MASK_BIT(b_out, d_out, i); + } + // no write before read + return false; +} + +// convenience methods for splitting 8-way or 4-way vector register +// sequences in half -- needed because vector operations can normally +// benefit from 4-way instruction parallelism or, occasionally, 2-way +// parallelism + +template +VSeq vs_front(const VSeq& v) { + static_assert(N > 0 && ((N & 1) == 0), "sequence length must be even"); + return VSeq(v.base(), v.delta()); +} + +template +VSeq vs_back(const VSeq& v) { + static_assert(N > 0 && ((N & 1) == 0), "sequence length must be even"); + return VSeq(v.base() + N / 2 * v.delta(), v.delta()); +} + +template +VSeq vs_even(const VSeq& v) { + static_assert(N > 0 && ((N & 1) == 0), "sequence length must be even"); + return VSeq(v.base(), v.delta() * 2); +} + +template +VSeq vs_odd(const VSeq& v) { + static_assert(N > 0 && ((N & 1) == 0), "sequence length must be even"); + return VSeq(v.base() + v.delta(), v.delta() * 2); +} + +// convenience method to construct a vector register sequence that +// indexes its elements in reverse order to the original + +template +VSeq vs_reverse(const VSeq& v) { + return VSeq(v.base() + (N - 1) * v.delta(), -v.delta()); +} + #endif // CPU_AARCH64_REGISTER_AARCH64_HPP diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -3983,6 +3983,95 @@ return start; } + // Execute one round of keccak of two computations in parallel. + // One of the states should be loaded into the lower halves of + // the vector registers v0-v24, the other should be loaded into + // the upper halves of those registers. The ld1r instruction loads + // the round constant into both halves of register v31. + // Intermediate results c0...c5 and d0...d5 are computed + // in registers v25...v30. + // All vector instructions that are used operate on both register + // halves in parallel. + // If only a single computation is needed, one can only load the lower halves. + void keccak_round(Register rscratch1) { + __ eor3(v29, __ T16B, v4, v9, v14); // c4 = a4 ^ a9 ^ a14 + __ eor3(v26, __ T16B, v1, v6, v11); // c1 = a1 ^ a16 ^ a11 + __ eor3(v28, __ T16B, v3, v8, v13); // c3 = a3 ^ a8 ^a13 + __ eor3(v25, __ T16B, v0, v5, v10); // c0 = a0 ^ a5 ^ a10 + __ eor3(v27, __ T16B, v2, v7, v12); // c2 = a2 ^ a7 ^ a12 + __ eor3(v29, __ T16B, v29, v19, v24); // c4 ^= a19 ^ a24 + __ eor3(v26, __ T16B, v26, v16, v21); // c1 ^= a16 ^ a21 + __ eor3(v28, __ T16B, v28, v18, v23); // c3 ^= a18 ^ a23 + __ eor3(v25, __ T16B, v25, v15, v20); // c0 ^= a15 ^ a20 + __ eor3(v27, __ T16B, v27, v17, v22); // c2 ^= a17 ^ a22 + + __ rax1(v30, __ T2D, v29, v26); // d0 = c4 ^ rol(c1, 1) + __ rax1(v26, __ T2D, v26, v28); // d2 = c1 ^ rol(c3, 1) + __ rax1(v28, __ T2D, v28, v25); // d4 = c3 ^ rol(c0, 1) + __ rax1(v25, __ T2D, v25, v27); // d1 = c0 ^ rol(c2, 1) + __ rax1(v27, __ T2D, v27, v29); // d3 = c2 ^ rol(c4, 1) + + __ eor(v0, __ T16B, v0, v30); // a0 = a0 ^ d0 + __ xar(v29, __ T2D, v1, v25, (64 - 1)); // a10' = rol((a1^d1), 1) + __ xar(v1, __ T2D, v6, v25, (64 - 44)); // a1 = rol(a6^d1), 44) + __ xar(v6, __ T2D, v9, v28, (64 - 20)); // a6 = rol((a9^d4), 20) + __ xar(v9, __ T2D, v22, v26, (64 - 61)); // a9 = rol((a22^d2), 61) + __ xar(v22, __ T2D, v14, v28, (64 - 39)); // a22 = rol((a14^d4), 39) + __ xar(v14, __ T2D, v20, v30, (64 - 18)); // a14 = rol((a20^d0), 18) + __ xar(v31, __ T2D, v2, v26, (64 - 62)); // a20' = rol((a2^d2), 62) + __ xar(v2, __ T2D, v12, v26, (64 - 43)); // a2 = rol((a12^d2), 43) + __ xar(v12, __ T2D, v13, v27, (64 - 25)); // a12 = rol((a13^d3), 25) + __ xar(v13, __ T2D, v19, v28, (64 - 8)); // a13 = rol((a19^d4), 8) + __ xar(v19, __ T2D, v23, v27, (64 - 56)); // a19 = rol((a23^d3), 56) + __ xar(v23, __ T2D, v15, v30, (64 - 41)); // a23 = rol((a15^d0), 41) + __ xar(v15, __ T2D, v4, v28, (64 - 27)); // a15 = rol((a4^d4), 27) + __ xar(v28, __ T2D, v24, v28, (64 - 14)); // a4' = rol((a24^d4), 14) + __ xar(v24, __ T2D, v21, v25, (64 - 2)); // a24 = rol((a21^d1), 2) + __ xar(v8, __ T2D, v8, v27, (64 - 55)); // a21' = rol((a8^d3), 55) + __ xar(v4, __ T2D, v16, v25, (64 - 45)); // a8' = rol((a16^d1), 45) + __ xar(v16, __ T2D, v5, v30, (64 - 36)); // a16 = rol((a5^d0), 36) + __ xar(v5, __ T2D, v3, v27, (64 - 28)); // a5 = rol((a3^d3), 28) + __ xar(v27, __ T2D, v18, v27, (64 - 21)); // a3' = rol((a18^d3), 21) + __ xar(v3, __ T2D, v17, v26, (64 - 15)); // a18' = rol((a17^d2), 15) + __ xar(v25, __ T2D, v11, v25, (64 - 10)); // a17' = rol((a11^d1), 10) + __ xar(v26, __ T2D, v7, v26, (64 - 6)); // a11' = rol((a7^d2), 6) + __ xar(v30, __ T2D, v10, v30, (64 - 3)); // a7' = rol((a10^d0), 3) + + __ bcax(v20, __ T16B, v31, v22, v8); // a20 = a20' ^ (~a21 & a22') + __ bcax(v21, __ T16B, v8, v23, v22); // a21 = a21' ^ (~a22 & a23) + __ bcax(v22, __ T16B, v22, v24, v23); // a22 = a22 ^ (~a23 & a24) + __ bcax(v23, __ T16B, v23, v31, v24); // a23 = a23 ^ (~a24 & a20') + __ bcax(v24, __ T16B, v24, v8, v31); // a24 = a24 ^ (~a20' & a21') + + __ ld1r(v31, __ T2D, __ post(rscratch1, 8)); // rc = round_constants[i] + + __ bcax(v17, __ T16B, v25, v19, v3); // a17 = a17' ^ (~a18' & a19) + __ bcax(v18, __ T16B, v3, v15, v19); // a18 = a18' ^ (~a19 & a15') + __ bcax(v19, __ T16B, v19, v16, v15); // a19 = a19 ^ (~a15 & a16) + __ bcax(v15, __ T16B, v15, v25, v16); // a15 = a15 ^ (~a16 & a17') + __ bcax(v16, __ T16B, v16, v3, v25); // a16 = a16 ^ (~a17' & a18') + + __ bcax(v10, __ T16B, v29, v12, v26); // a10 = a10' ^ (~a11' & a12) + __ bcax(v11, __ T16B, v26, v13, v12); // a11 = a11' ^ (~a12 & a13) + __ bcax(v12, __ T16B, v12, v14, v13); // a12 = a12 ^ (~a13 & a14) + __ bcax(v13, __ T16B, v13, v29, v14); // a13 = a13 ^ (~a14 & a10') + __ bcax(v14, __ T16B, v14, v26, v29); // a14 = a14 ^ (~a10' & a11') + + __ bcax(v7, __ T16B, v30, v9, v4); // a7 = a7' ^ (~a8' & a9) + __ bcax(v8, __ T16B, v4, v5, v9); // a8 = a8' ^ (~a9 & a5) + __ bcax(v9, __ T16B, v9, v6, v5); // a9 = a9 ^ (~a5 & a6) + __ bcax(v5, __ T16B, v5, v30, v6); // a5 = a5 ^ (~a6 & a7) + __ bcax(v6, __ T16B, v6, v4, v30); // a6 = a6 ^ (~a7 & a8') + + __ bcax(v3, __ T16B, v27, v0, v28); // a3 = a3' ^ (~a4' & a0) + __ bcax(v4, __ T16B, v28, v1, v0); // a4 = a4' ^ (~a0 & a1) + __ bcax(v0, __ T16B, v0, v2, v1); // a0 = a0 ^ (~a1 & a2) + __ bcax(v1, __ T16B, v1, v27, v2); // a1 = a1 ^ (~a2 & a3) + __ bcax(v2, __ T16B, v2, v28, v27); // a2 = a2 ^ (~a3 & a4') + + __ eor(v0, __ T16B, v0, v31); // a0 = a0 ^ rc + } + // Arguments: // // Inputs: @@ -4074,7 +4163,7 @@ __ cbzw(c_rarg5, rounds24_loop); __ tbnz(block_size, 5, shake128); - // block_size == 144, bit5 == 0, SHA3-244 + // block_size == 144, bit5 == 0, SHA3-224 __ ldrd(v28, __ post(buf, 8)); __ eor(v17, __ T8B, v17, v28); __ b(rounds24_loop); @@ -4103,82 +4192,7 @@ __ BIND(rounds24_loop); __ subw(rscratch2, rscratch2, 1); - __ eor3(v29, __ T16B, v4, v9, v14); - __ eor3(v26, __ T16B, v1, v6, v11); - __ eor3(v28, __ T16B, v3, v8, v13); - __ eor3(v25, __ T16B, v0, v5, v10); - __ eor3(v27, __ T16B, v2, v7, v12); - __ eor3(v29, __ T16B, v29, v19, v24); - __ eor3(v26, __ T16B, v26, v16, v21); - __ eor3(v28, __ T16B, v28, v18, v23); - __ eor3(v25, __ T16B, v25, v15, v20); - __ eor3(v27, __ T16B, v27, v17, v22); - - __ rax1(v30, __ T2D, v29, v26); - __ rax1(v26, __ T2D, v26, v28); - __ rax1(v28, __ T2D, v28, v25); - __ rax1(v25, __ T2D, v25, v27); - __ rax1(v27, __ T2D, v27, v29); - - __ eor(v0, __ T16B, v0, v30); - __ xar(v29, __ T2D, v1, v25, (64 - 1)); - __ xar(v1, __ T2D, v6, v25, (64 - 44)); - __ xar(v6, __ T2D, v9, v28, (64 - 20)); - __ xar(v9, __ T2D, v22, v26, (64 - 61)); - __ xar(v22, __ T2D, v14, v28, (64 - 39)); - __ xar(v14, __ T2D, v20, v30, (64 - 18)); - __ xar(v31, __ T2D, v2, v26, (64 - 62)); - __ xar(v2, __ T2D, v12, v26, (64 - 43)); - __ xar(v12, __ T2D, v13, v27, (64 - 25)); - __ xar(v13, __ T2D, v19, v28, (64 - 8)); - __ xar(v19, __ T2D, v23, v27, (64 - 56)); - __ xar(v23, __ T2D, v15, v30, (64 - 41)); - __ xar(v15, __ T2D, v4, v28, (64 - 27)); - __ xar(v28, __ T2D, v24, v28, (64 - 14)); - __ xar(v24, __ T2D, v21, v25, (64 - 2)); - __ xar(v8, __ T2D, v8, v27, (64 - 55)); - __ xar(v4, __ T2D, v16, v25, (64 - 45)); - __ xar(v16, __ T2D, v5, v30, (64 - 36)); - __ xar(v5, __ T2D, v3, v27, (64 - 28)); - __ xar(v27, __ T2D, v18, v27, (64 - 21)); - __ xar(v3, __ T2D, v17, v26, (64 - 15)); - __ xar(v25, __ T2D, v11, v25, (64 - 10)); - __ xar(v26, __ T2D, v7, v26, (64 - 6)); - __ xar(v30, __ T2D, v10, v30, (64 - 3)); - - __ bcax(v20, __ T16B, v31, v22, v8); - __ bcax(v21, __ T16B, v8, v23, v22); - __ bcax(v22, __ T16B, v22, v24, v23); - __ bcax(v23, __ T16B, v23, v31, v24); - __ bcax(v24, __ T16B, v24, v8, v31); - - __ ld1r(v31, __ T2D, __ post(rscratch1, 8)); - - __ bcax(v17, __ T16B, v25, v19, v3); - __ bcax(v18, __ T16B, v3, v15, v19); - __ bcax(v19, __ T16B, v19, v16, v15); - __ bcax(v15, __ T16B, v15, v25, v16); - __ bcax(v16, __ T16B, v16, v3, v25); - - __ bcax(v10, __ T16B, v29, v12, v26); - __ bcax(v11, __ T16B, v26, v13, v12); - __ bcax(v12, __ T16B, v12, v14, v13); - __ bcax(v13, __ T16B, v13, v29, v14); - __ bcax(v14, __ T16B, v14, v26, v29); - - __ bcax(v7, __ T16B, v30, v9, v4); - __ bcax(v8, __ T16B, v4, v5, v9); - __ bcax(v9, __ T16B, v9, v6, v5); - __ bcax(v5, __ T16B, v5, v30, v6); - __ bcax(v6, __ T16B, v6, v4, v30); - - __ bcax(v3, __ T16B, v27, v0, v28); - __ bcax(v4, __ T16B, v28, v1, v0); - __ bcax(v0, __ T16B, v0, v2, v1); - __ bcax(v1, __ T16B, v1, v27, v2); - __ bcax(v2, __ T16B, v2, v28, v27); - - __ eor(v0, __ T16B, v0, v31); + keccak_round(rscratch1); __ cbnzw(rscratch2, rounds24_loop); @@ -4197,11 +4211,102 @@ __ st1(v20, v21, v22, v23, __ T1D, __ post(state, 32)); __ st1(v24, __ T1D, state); + // restore callee-saved registers + __ ldpd(v14, v15, Address(sp, 48)); + __ ldpd(v12, v13, Address(sp, 32)); + __ ldpd(v10, v11, Address(sp, 16)); + __ ldpd(v8, v9, __ post(sp, 64)); + + __ ret(lr); + + return start; + } + + // Inputs: + // c_rarg0 - long[] state0 + // c_rarg1 - long[] state1 + address generate_double_keccak() { + static const uint64_t round_consts[24] = { + 0x0000000000000001L, 0x0000000000008082L, 0x800000000000808AL, + 0x8000000080008000L, 0x000000000000808BL, 0x0000000080000001L, + 0x8000000080008081L, 0x8000000000008009L, 0x000000000000008AL, + 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000AL, + 0x000000008000808BL, 0x800000000000008BL, 0x8000000000008089L, + 0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L, + 0x000000000000800AL, 0x800000008000000AL, 0x8000000080008081L, + 0x8000000000008080L, 0x0000000080000001L, 0x8000000080008008L + }; + + // Implements the double_keccak() method of the + // sun.secyrity.provider.SHA3Parallel class + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "double_keccak"); + address start = __ pc(); + __ enter(); + + Register state0 = c_rarg0; + Register state1 = c_rarg1; + + Label rounds24_loop; + + // save callee-saved registers + __ stpd(v8, v9, __ pre(sp, -64)); + __ stpd(v10, v11, Address(sp, 16)); + __ stpd(v12, v13, Address(sp, 32)); + __ stpd(v14, v15, Address(sp, 48)); + + // load states + __ add(rscratch1, state0, 32); + __ ld4(v0, v1, v2, v3, __ D, 0, state0); + __ ld4(v4, v5, v6, v7, __ D, 0, __ post(rscratch1, 32)); + __ ld4(v8, v9, v10, v11, __ D, 0, __ post(rscratch1, 32)); + __ ld4(v12, v13, v14, v15, __ D, 0, __ post(rscratch1, 32)); + __ ld4(v16, v17, v18, v19, __ D, 0, __ post(rscratch1, 32)); + __ ld4(v20, v21, v22, v23, __ D, 0, __ post(rscratch1, 32)); + __ ld1(v24, __ D, 0, rscratch1); + __ add(rscratch1, state1, 32); + __ ld4(v0, v1, v2, v3, __ D, 1, state1); + __ ld4(v4, v5, v6, v7, __ D, 1, __ post(rscratch1, 32)); + __ ld4(v8, v9, v10, v11, __ D, 1, __ post(rscratch1, 32)); + __ ld4(v12, v13, v14, v15, __ D, 1, __ post(rscratch1, 32)); + __ ld4(v16, v17, v18, v19, __ D, 1, __ post(rscratch1, 32)); + __ ld4(v20, v21, v22, v23, __ D, 1, __ post(rscratch1, 32)); + __ ld1(v24, __ D, 1, rscratch1); + + // 24 keccak rounds + __ movw(rscratch2, 24); + + // load round_constants base + __ lea(rscratch1, ExternalAddress((address) round_consts)); + + __ BIND(rounds24_loop); + __ subw(rscratch2, rscratch2, 1); + keccak_round(rscratch1); + __ cbnzw(rscratch2, rounds24_loop); + + __ st4(v0, v1, v2, v3, __ D, 0, __ post(state0, 32)); + __ st4(v4, v5, v6, v7, __ D, 0, __ post(state0, 32)); + __ st4(v8, v9, v10, v11, __ D, 0, __ post(state0, 32)); + __ st4(v12, v13, v14, v15, __ D, 0, __ post(state0, 32)); + __ st4(v16, v17, v18, v19, __ D, 0, __ post(state0, 32)); + __ st4(v20, v21, v22, v23, __ D, 0, __ post(state0, 32)); + __ st1(v24, __ D, 0, state0); + __ st4(v0, v1, v2, v3, __ D, 1, __ post(state1, 32)); + __ st4(v4, v5, v6, v7, __ D, 1, __ post(state1, 32)); + __ st4(v8, v9, v10, v11, __ D, 1, __ post(state1, 32)); + __ st4(v12, v13, v14, v15, __ D, 1, __ post(state1, 32)); + __ st4(v16, v17, v18, v19, __ D, 1, __ post(state1, 32)); + __ st4(v20, v21, v22, v23, __ D, 1, __ post(state1, 32)); + __ st1(v24, __ D, 1, state1); + + // restore callee-saved vector registers __ ldpd(v14, v15, Address(sp, 48)); __ ldpd(v12, v13, Address(sp, 32)); __ ldpd(v10, v11, Address(sp, 16)); __ ldpd(v8, v9, __ post(sp, 64)); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 __ ret(lr); return start; @@ -4373,6 +4478,2296 @@ return start; } + // Helpers to schedule parallel operation bundles across vector + // register sequences of size 2, 4 or 8. + + // Implement various primitive computations across vector sequences + + template + void vs_addv(const VSeq& v, Assembler::SIMD_Arrangement T, + const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ addv(v[i], T, v1[i], v2[i]); + } + } + + template + void vs_subv(const VSeq& v, Assembler::SIMD_Arrangement T, + const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ subv(v[i], T, v1[i], v2[i]); + } + } + + template + void vs_mulv(const VSeq& v, Assembler::SIMD_Arrangement T, + const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ mulv(v[i], T, v1[i], v2[i]); + } + } + + template + void vs_negr(const VSeq& v, Assembler::SIMD_Arrangement T, const VSeq& v1) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ negr(v[i], T, v1[i]); + } + } + + template + void vs_sshr(const VSeq& v, Assembler::SIMD_Arrangement T, + const VSeq& v1, int shift) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ sshr(v[i], T, v1[i], shift); + } + } + + template + void vs_andr(const VSeq& v, const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ andr(v[i], __ T16B, v1[i], v2[i]); + } + } + + template + void vs_orr(const VSeq& v, const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ orr(v[i], __ T16B, v1[i], v2[i]); + } + } + + template + void vs_notr(const VSeq& v, const VSeq& v1) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ notr(v[i], __ T16B, v1[i]); + } + } + + template + void vs_sqdmulh(const VSeq& v, Assembler::SIMD_Arrangement T, const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ sqdmulh(v[i], T, v1[i], v2[i]); + } + } + + template + void vs_mlsv(const VSeq& v, Assembler::SIMD_Arrangement T, const VSeq& v1, VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ mlsv(v[i], T, v1[i], v2[i]); + } + } + + // load N/2 successive pairs of quadword values from memory in order + // into N successive vector registers of the sequence via the + // address supplied in base. + template + void vs_ldpq(const VSeq& v, Register base) { + for (int i = 0; i < N; i += 2) { + __ ldpq(v[i], v[i+1], Address(base, 32 * i)); + } + } + + // load N/2 successive pairs of quadword values from memory in order + // into N vector registers of the sequence via the address supplied + // in base using post-increment addressing + template + void vs_ldpq_post(const VSeq& v, Register base) { + static_assert((N & (N - 1)) == 0, "sequence length must be even"); + for (int i = 0; i < N; i += 2) { + __ ldpq(v[i], v[i+1], __ post(base, 32)); + } + } + + // store N successive vector registers of the sequence into N/2 + // successive pairs of quadword memory locations via the address + // supplied in base using post-increment addressing + template + void vs_stpq_post(const VSeq& v, Register base) { + static_assert((N & (N - 1)) == 0, "sequence length must be even"); + for (int i = 0; i < N; i += 2) { + __ stpq(v[i], v[i+1], __ post(base, 32)); + } + } + + // load N/2 pairs of quadword values from memory de-interleaved into + // N vector registers 2 at a time via the address supplied in base + // using post-increment addressing. + template + void vs_ld2_post(const VSeq& v, Assembler::SIMD_Arrangement T, Register base) { + static_assert((N & (N - 1)) == 0, "sequence length must be even"); + for (int i = 0; i < N; i += 2) { + __ ld2(v[i], v[i+1], T, __ post(base, 32)); + } + } + + // store N vector registers interleaved into N/2 pairs of quadword + // memory locations via the address supplied in base using + // post-increment addressing. + template + void vs_st2_post(const VSeq& v, Assembler::SIMD_Arrangement T, Register base) { + static_assert((N & (N - 1)) == 0, "sequence length must be even"); + for (int i = 0; i < N; i += 2) { + __ st2(v[i], v[i+1], T, __ post(base, 32)); + } + } + + // load N quadword values from memory de-interleaved into N vector + // registers 3 elements at a time via the address supplied in base. + template + void vs_ld3(const VSeq& v, Assembler::SIMD_Arrangement T, Register base) { + static_assert(N == ((N / 3) * 3), "sequence length must be multiple of 3"); + for (int i = 0; i < N; i += 3) { + __ ld3(v[i], v[i+1], v[i+2], T, base); + } + } + + // load N quadword values from memory de-interleaved into N vector + // registers 3 elements at a time via the address supplied in base + // using post-increment addressing. + template + void vs_ld3_post(const VSeq& v, Assembler::SIMD_Arrangement T, Register base) { + static_assert(N == ((N / 3) * 3), "sequence length must be multiple of 3"); + for (int i = 0; i < N; i += 3) { + __ ld3(v[i], v[i+1], v[i+2], T, __ post(base, 48)); + } + } + + // load N/2 pairs of quadword values from memory into N vector + // registers via the address supplied in base with each pair indexed + // using the the start offset plus the corresponding entry in the + // offsets array + template + void vs_ldpq_indexed(const VSeq& v, Register base, int start, int (&offsets)[N/2]) { + for (int i = 0; i < N/2; i++) { + __ ldpq(v[2*i], v[2*i+1], Address(base, start + offsets[i])); + } + } + + // store N vector registers into N/2 pairs of quadword memory + // locations via the address supplied in base with each pair indexed + // using the the start offset plus the corresponding entry in the + // offsets array + template + void vs_stpq_indexed(const VSeq& v, Register base, int start, int offsets[N/2]) { + for (int i = 0; i < N/2; i++) { + __ stpq(v[2*i], v[2*i+1], Address(base, start + offsets[i])); + } + } + + // load N single quadword values from memory into N vector registers + // via the address supplied in base with each value indexed using + // the the start offset plus the corresponding entry in the offsets + // array + template + void vs_ldr_indexed(const VSeq& v, Assembler::SIMD_RegVariant T, Register base, + int start, int (&offsets)[N]) { + for (int i = 0; i < N; i++) { + __ ldr(v[i], T, Address(base, start + offsets[i])); + } + } + + // store N vector registers into N single quadword memory locations + // via the address supplied in base with each value indexed using + // the the start offset plus the corresponding entry in the offsets + // array + template + void vs_str_indexed(const VSeq& v, Assembler::SIMD_RegVariant T, Register base, + int start, int (&offsets)[N]) { + for (int i = 0; i < N; i++) { + __ str(v[i], T, Address(base, start + offsets[i])); + } + } + + // load N/2 pairs of quadword values from memory de-interleaved into + // N vector registers 2 at a time via the address supplied in base + // with each pair indexed using the the start offset plus the + // corresponding entry in the offsets array + template + void vs_ld2_indexed(const VSeq& v, Assembler::SIMD_Arrangement T, Register base, + Register tmp, int start, int (&offsets)[N/2]) { + for (int i = 0; i < N/2; i++) { + __ add(tmp, base, start + offsets[i]); + __ ld2(v[2*i], v[2*i+1], T, tmp); + } + } + + // store N vector registers 2 at a time interleaved into N/2 pairs + // of quadword memory locations via the address supplied in base + // with each pair indexed using the the start offset plus the + // corresponding entry in the offsets array + template + void vs_st2_indexed(const VSeq& v, Assembler::SIMD_Arrangement T, Register base, + Register tmp, int start, int (&offsets)[N/2]) { + for (int i = 0; i < N/2; i++) { + __ add(tmp, base, start + offsets[i]); + __ st2(v[2*i], v[2*i+1], T, tmp); + } + } + + // Helper routines for various flavours of Montgomery multiply + + // Perform 16 32-bit (4x4S) or 32 16-bit (4 x 8H) Montgomery + // multiplications in parallel + // + + // See the montMul() method of the sun.security.provider.ML_DSA + // class. + // + // Computes 4x4S results or 8x8H results + // a = b * c * 2^MONT_R_BITS mod MONT_Q + // Inputs: vb, vc - 4x4S or 4x8H vector register sequences + // vq - 2x4S or 2x8H constants + // Temps: vtmp - 4x4S or 4x8H vector sequence trashed after call + // Outputs: va - 4x4S or 4x8H vector register sequences + // vb, vc, vtmp and vq must all be disjoint + // va must be disjoint from all other inputs/temps or must equal vc + // va must have a non-zero delta i.e. it must not be a constant vseq. + // n.b. MONT_R_BITS is 16 or 32, so the right shift by it is implicit. + void vs_montmul4(const VSeq<4>& va, const VSeq<4>& vb, const VSeq<4>& vc, + Assembler::SIMD_Arrangement T, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + assert (T == __ T4S || T == __ T8H, "invalid arrangement for montmul"); + assert(vs_disjoint(vb, vc), "vb and vc overlap"); + assert(vs_disjoint(vb, vq), "vb and vq overlap"); + assert(vs_disjoint(vb, vtmp), "vb and vtmp overlap"); + + assert(vs_disjoint(vc, vq), "vc and vq overlap"); + assert(vs_disjoint(vc, vtmp), "vc and vtmp overlap"); + + assert(vs_disjoint(vq, vtmp), "vq and vtmp overlap"); + + assert(vs_disjoint(va, vc) || vs_same(va, vc), "va and vc neither disjoint nor equal"); + assert(vs_disjoint(va, vb), "va and vb overlap"); + assert(vs_disjoint(va, vq), "va and vq overlap"); + assert(vs_disjoint(va, vtmp), "va and vtmp overlap"); + assert(!va.is_constant(), "output vector must identify 4 different registers"); + + // schedule 4 streams of instructions across the vector sequences + for (int i = 0; i < 4; i++) { + __ sqdmulh(vtmp[i], T, vb[i], vc[i]); // aHigh = hi32(2 * b * c) + __ mulv(va[i], T, vb[i], vc[i]); // aLow = lo32(b * c) + } + + for (int i = 0; i < 4; i++) { + __ mulv(va[i], T, va[i], vq[0]); // m = aLow * qinv + } + + for (int i = 0; i < 4; i++) { + __ sqdmulh(va[i], T, va[i], vq[1]); // n = hi32(2 * m * q) + } + + for (int i = 0; i < 4; i++) { + __ shsubv(va[i], T, vtmp[i], va[i]); // a = (aHigh - n) / 2 + } + } + + // Perform 8 32-bit (4x4S) or 16 16-bit (2 x 8H) Montgomery + // multiplications in parallel + // + + // See the montMul() method of the sun.security.provider.ML_DSA + // class. + // + // Computes 4x4S results or 8x8H results + // a = b * c * 2^MONT_R_BITS mod MONT_Q + // Inputs: vb, vc - 4x4S or 4x8H vector register sequences + // vq - 2x4S or 2x8H constants + // Temps: vtmp - 4x4S or 4x8H vector sequence trashed after call + // Outputs: va - 4x4S or 4x8H vector register sequences + // vb, vc, vtmp and vq must all be disjoint + // va must be disjoint from all other inputs/temps or must equal vc + // va must have a non-zero delta i.e. it must not be a constant vseq. + // n.b. MONT_R_BITS is 16 or 32, so the right shift by it is implicit. + void vs_montmul2(const VSeq<2>& va, const VSeq<2>& vb, const VSeq<2>& vc, + Assembler::SIMD_Arrangement T, + const VSeq<2>& vtmp, const VSeq<2>& vq) { + assert (T == __ T4S || T == __ T8H, "invalid arrangement for montmul"); + assert(vs_disjoint(vb, vc), "vb and vc overlap"); + assert(vs_disjoint(vb, vq), "vb and vq overlap"); + assert(vs_disjoint(vb, vtmp), "vb and vtmp overlap"); + + assert(vs_disjoint(vc, vq), "vc and vq overlap"); + assert(vs_disjoint(vc, vtmp), "vc and vtmp overlap"); + + assert(vs_disjoint(vq, vtmp), "vq and vtmp overlap"); + + assert(vs_disjoint(va, vc) || vs_same(va, vc), "va and vc neither disjoint nor equal"); + assert(vs_disjoint(va, vb), "va and vb overlap"); + assert(vs_disjoint(va, vq), "va and vq overlap"); + assert(vs_disjoint(va, vtmp), "va and vtmp overlap"); + assert(!va.is_constant(), "output vector must identify 2 different registers"); + + // schedule 2 streams of instructions across the vector sequences + for (int i = 0; i < 2; i++) { + __ sqdmulh(vtmp[i], T, vb[i], vc[i]); // aHigh = hi32(2 * b * c) + __ mulv(va[i], T, vb[i], vc[i]); // aLow = lo32(b * c) + } + + for (int i = 0; i < 2; i++) { + __ mulv(va[i], T, va[i], vq[0]); // m = aLow * qinv + } + + for (int i = 0; i < 2; i++) { + __ sqdmulh(va[i], T, va[i], vq[1]); // n = hi32(2 * m * q) + } + + for (int i = 0; i < 2; i++) { + __ shsubv(va[i], T, vtmp[i], va[i]); // a = (aHigh - n) / 2 + } + } + + // Perform 16 16-bit Montgomery multiplications in parallel. + void kyber_montmul16(const VSeq<2>& va, const VSeq<2>& vb, const VSeq<2>& vc, + const VSeq<2>& vtmp, const VSeq<2>& vq) { + // Use the helper routine to schedule a 2x8H Montgomery multiply. + // It will assert that the register use is valid + vs_montmul2(va, vb, vc, __ T8H, vtmp, vq); + } + + // Perform 32 16-bit Montgomery multiplications in parallel. + void kyber_montmul32(const VSeq<4>& va, const VSeq<4>& vb, const VSeq<4>& vc, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + // Use the helper routine to schedule a 4x8H Montgomery multiply. + // It will assert that the register use is valid + vs_montmul4(va, vb, vc, __ T8H, vtmp, vq); + } + + // Perform 64 16-bit Montgomery multiplications in parallel. + void kyber_montmul64(const VSeq<8>& va, const VSeq<8>& vb, const VSeq<8>& vc, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + // Schedule two successive 4x8H multiplies via the montmul helper + // on the front and back halves of va, vb and vc. The helper will + // assert that the register use has no overlap conflicts on each + // individual call but we also need to ensure that the necessary + // disjoint/equality constraints are met across both calls. + + // vb, vc, vtmp and vq must be disjoint. va must either be + // disjoint from all other registers or equal vc + + assert(vs_disjoint(vb, vc), "vb and vc overlap"); + assert(vs_disjoint(vb, vq), "vb and vq overlap"); + assert(vs_disjoint(vb, vtmp), "vb and vtmp overlap"); + + assert(vs_disjoint(vc, vq), "vc and vq overlap"); + assert(vs_disjoint(vc, vtmp), "vc and vtmp overlap"); + + assert(vs_disjoint(vq, vtmp), "vq and vtmp overlap"); + + assert(vs_disjoint(va, vc) || vs_same(va, vc), "va and vc neither disjoint nor equal"); + assert(vs_disjoint(va, vb), "va and vb overlap"); + assert(vs_disjoint(va, vq), "va and vq overlap"); + assert(vs_disjoint(va, vtmp), "va and vtmp overlap"); + + // we multiply the front and back halves of each sequence 4 at a + // time because + // + // 1) we are currently only able to get 4-way instruction + // parallelism at best + // + // 2) we need registers for the constants in vq and temporary + // scratch registers to hold intermediate results so vtmp can only + // be a VSeq<4> which means we only have 4 scratch slots + + vs_montmul4(vs_front(va), vs_front(vb), vs_front(vc), __ T8H, vtmp, vq); + vs_montmul4(vs_back(va), vs_back(vb), vs_back(vc), __ T8H, vtmp, vq); + } + + void kyber_montmul32_sub_add(const VSeq<4>& va0, const VSeq<4>& va1, + const VSeq<4>& vc, + const VSeq<4>& vtmp, + const VSeq<2>& vq) { + // compute a = montmul(a1, c) + kyber_montmul32(vc, va1, vc, vtmp, vq); + // ouptut a1 = a0 - a + vs_subv(va1, __ T8H, va0, vc); + // and a0 = a0 + a + vs_addv(va0, __ T8H, va0, vc); + } + + void kyber_sub_add_montmul32(const VSeq<4>& va0, const VSeq<4>& va1, + const VSeq<4>& vb, + const VSeq<4>& vtmp1, + const VSeq<4>& vtmp2, + const VSeq<2>& vq) { + // compute c = a0 - a1 + vs_subv(vtmp1, __ T8H, va0, va1); + // output a0 = a0 + a1 + vs_addv(va0, __ T8H, va0, va1); + // output a1 = b montmul c + kyber_montmul32(va1, vtmp1, vb, vtmp2, vq); + } + + void load64shorts(const VSeq<8>& v, Register shorts) { + vs_ldpq_post(v, shorts); + } + + void load32shorts(const VSeq<4>& v, Register shorts) { + vs_ldpq_post(v, shorts); + } + + void store64shorts(VSeq<8> v, Register tmpAddr) { + vs_stpq_post(v, tmpAddr); + } + + // Kyber NTT function. + // Implements + // static int implKyberNtt(short[] poly, short[] ntt_zetas) {} + // + // coeffs (short[256]) = c_rarg0 + // ntt_zetas (short[256]) = c_rarg1 + address generate_kyberNtt() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "kyberNtt"); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register kyberConsts = r10; + const Register tmpAddr = r11; + + VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x8H inputs/outputs + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<2> vq(30); // n.b. constants overlap vs3 + + __ lea(kyberConsts, ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + // load the montmul constants + vs_ldpq(vq, kyberConsts); + + // Each level corresponds to an iteration of the outermost loop of the + // Java method seilerNTT(int[] coeffs). There are some differences + // from what is done in the seilerNTT() method, though: + // 1. The computation is using 16-bit signed values, we do not convert them + // to ints here. + // 2. The zetas are delivered in a bigger array, 128 zetas are stored in + // this array for each level, it is easier that way to fill up the vector + // registers. + // 3. In the seilerNTT() method we use R = 2^20 for the Montgomery + // multiplications (this is because that way there should not be any + // overflow during the inverse NTT computation), here we usr R = 2^16 so + // that we can use the 16-bit arithmetic in the vector unit. + // + // On each level, we fill up the vector registers in such a way that the + // array elements that need to be multiplied by the zetas go into one + // set of vector registers while the corresponding ones that don't need to + // be multiplied, go into another set. + // We can do 32 Montgomery multiplications in parallel, using 12 vector + // registers interleaving the steps of 4 identical computations, + // each done on 8 16-bit values per register. + + // At levels 0-3 the coefficients multiplied by or added/subtracted + // to the zetas occur in discrete blocks whose size is some multiple + // of 32. + + // level 0 + __ add(tmpAddr, coeffs, 256); + load64shorts(vs1, tmpAddr); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 0); + load64shorts(vs1, tmpAddr); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 0); + vs_stpq_post(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 256); + vs_stpq_post(vs3, tmpAddr); + // restore montmul constants + vs_ldpq(vq, kyberConsts); + load64shorts(vs1, tmpAddr); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 128); + load64shorts(vs1, tmpAddr); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 128); + store64shorts(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 384); + store64shorts(vs3, tmpAddr); + + // level 1 + // restore montmul constants + vs_ldpq(vq, kyberConsts); + __ add(tmpAddr, coeffs, 128); + load64shorts(vs1, tmpAddr); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 0); + load64shorts(vs1, tmpAddr); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 0); + store64shorts(vs1, tmpAddr); + store64shorts(vs3, tmpAddr); + vs_ldpq(vq, kyberConsts); + __ add(tmpAddr, coeffs, 384); + load64shorts(vs1, tmpAddr); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 256); + load64shorts(vs1, tmpAddr); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 256); + store64shorts(vs1, tmpAddr); + store64shorts(vs3, tmpAddr); + + // level 2 + vs_ldpq(vq, kyberConsts); + int offsets1[4] = { 0, 32, 128, 160 }; + vs_ldpq_indexed(vs1, coeffs, 64, offsets1); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldpq_indexed(vs1, coeffs, 0, offsets1); + // kyber_subv_addv64(); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 0); + vs_stpq_post(vs_front(vs1), tmpAddr); + vs_stpq_post(vs_front(vs3), tmpAddr); + vs_stpq_post(vs_back(vs1), tmpAddr); + vs_stpq_post(vs_back(vs3), tmpAddr); + vs_ldpq(vq, kyberConsts); + vs_ldpq_indexed(vs1, tmpAddr, 64, offsets1); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldpq_indexed(vs1, coeffs, 256, offsets1); + // kyber_subv_addv64(); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 256); + vs_stpq_post(vs_front(vs1), tmpAddr); + vs_stpq_post(vs_front(vs3), tmpAddr); + vs_stpq_post(vs_back(vs1), tmpAddr); + vs_stpq_post(vs_back(vs3), tmpAddr); + + // level 3 + vs_ldpq(vq, kyberConsts); + int offsets2[4] = { 0, 64, 128, 192 }; + vs_ldpq_indexed(vs1, coeffs, 32, offsets2); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldpq_indexed(vs1, coeffs, 0, offsets2); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs1, coeffs, 0, offsets2); + vs_stpq_indexed(vs3, coeffs, 32, offsets2); + + vs_ldpq(vq, kyberConsts); + vs_ldpq_indexed(vs1, coeffs, 256 + 32, offsets2); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldpq_indexed(vs1, coeffs, 256, offsets2); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs1, coeffs, 256, offsets2); + vs_stpq_indexed(vs3, coeffs, 256 + 32, offsets2); + + // level 4 + // At level 4 coefficients occur in 8 discrete blocks of size 16 + // so they are loaded using employing an ldr at 8 distinct offsets. + + vs_ldpq(vq, kyberConsts); + int offsets3[8] = { 0, 32, 64, 96, 128, 160, 192, 224 }; + vs_ldr_indexed(vs1, __ Q, coeffs, 16, offsets3); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldr_indexed(vs1, __ Q, coeffs, 0, offsets3); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + vs_str_indexed(vs1, __ Q, coeffs, 0, offsets3); + vs_str_indexed(vs3, __ Q, coeffs, 16, offsets3); + + vs_ldpq(vq, kyberConsts); + vs_ldr_indexed(vs1, __ Q, coeffs, 256 + 16, offsets3); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldr_indexed(vs1, __ Q, coeffs, 256, offsets3); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + vs_str_indexed(vs1, __ Q, coeffs, 256, offsets3); + vs_str_indexed(vs3, __ Q, coeffs, 256 + 16, offsets3); + + // level 5 + // At level 5 related coefficients occur in discrete blocks of size 8 so + // need to be loaded interleaved using an ld2 operation with arrangement 2D. + + vs_ldpq(vq, kyberConsts); + int offsets4[4] = { 0, 32, 64, 96 }; + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 0, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 0, offsets4); + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 128, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 128, offsets4); + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 256, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 256, offsets4); + + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 384, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 384, offsets4); + + // level 6 + // At level 6 related coefficients occur in discrete blocks of size 4 so + // need to be loaded interleaved using an ld2 operation with arrangement 4S. + + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 0, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 0, offsets4); + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 128, offsets4); + // __ ldpq(v18, v19, __ post(zetas, 32)); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 128, offsets4); + + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 256, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 256, offsets4); + + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 384, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 384, offsets4); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber Inverse NTT function + // Implements + // static int implKyberInverseNtt(short[] poly, short[] zetas) {} + // + // coeffs (short[256]) = c_rarg0 + // ntt_zetas (short[256]) = c_rarg1 + address generate_kyberInverseNtt() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "kyberInverseNtt"); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register kyberConsts = r10; + const Register tmpAddr = r11; + const Register tmpAddr2 = c_rarg2; + + VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x8H inputs/outputs + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<2> vq(30); // n.b. constants overlap vs3 + + __ lea(kyberConsts, + ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + + // level 0 + // At level 0 related coefficients occur in discrete blocks of size 4 so + // need to be loaded interleaved using an ld2 operation with arrangement 4S. + + vs_ldpq(vq, kyberConsts); + int offsets4[4] = { 0, 32, 64, 96 }; + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 0, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 0, offsets4); + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 128, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 128, offsets4); + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 256, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 256, offsets4); + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 384, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 384, offsets4); + + // level 1 + // At level 1 related coefficients occur in discrete blocks of size 8 so + // need to be loaded interleaved using an ld2 operation with arrangement 2D. + + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 0, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 0, offsets4); + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 128, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 128, offsets4); + + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 256, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 256, offsets4); + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 384, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 384, offsets4); + + // level 2 + // At level 2 coefficients occur in 8 discrete blocks of size 16 + // so they are loaded using employing an ldr at 8 distinct offsets. + + int offsets3[8] = { 0, 32, 64, 96, 128, 160, 192, 224 }; + vs_ldr_indexed(vs1, __ Q, coeffs, 0, offsets3); + vs_ldr_indexed(vs2, __ Q, coeffs, 16, offsets3); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_str_indexed(vs3, __ Q, coeffs, 0, offsets3); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_str_indexed(vs2, __ Q, coeffs, 16, offsets3); + + vs_ldr_indexed(vs1, __ Q, coeffs, 256, offsets3); + vs_ldr_indexed(vs2, __ Q, coeffs, 256 + 16, offsets3); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_str_indexed(vs3, __ Q, coeffs, 256, offsets3); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_str_indexed(vs2, __ Q, coeffs, 256 + 16, offsets3); + + // Barrett reduction at indexes where overflow may happen + + // load q and the multiplier for the Barrett reduction + __ add(tmpAddr, kyberConsts, 16); + vs_ldpq(vq, tmpAddr); + + VSeq<8> vq1 = VSeq<8>(vq[0], 0); // 2 constant 8 sequences + VSeq<8> vq2 = VSeq<8>(vq[1], 0); // for above two kyber constants + VSeq<8> vq3 = VSeq<8>(v29, 0); // 3rd sequence for const montmul + vs_ldr_indexed(vs1, __ Q, coeffs, 0, offsets3); + vs_sqdmulh(vs2, __ T8H, vs1, vq2); + vs_sshr(vs2, __ T8H, vs2, 11); + vs_mlsv(vs1, __ T8H, vs2, vq1); + vs_str_indexed(vs1, __ Q, coeffs, 0, offsets3); + vs_ldr_indexed(vs1, __ Q, coeffs, 256, offsets3); + vs_sqdmulh(vs2, __ T8H, vs1, vq2); + vs_sshr(vs2, __ T8H, vs2, 11); + vs_mlsv(vs1, __ T8H, vs2, vq1); + vs_str_indexed(vs1, __ Q, coeffs, 256, offsets3); + + // level 3 + // From level 3 upwards coefficients occur in discrete blocks whose size is + // some multiple of 32 so can be loaded using ldpq and suitable indexes. + + int offsets2[4] = { 0, 64, 128, 192 }; + vs_ldpq_indexed(vs1, coeffs, 0, offsets2); + vs_ldpq_indexed(vs2, coeffs, 32, offsets2); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs3, coeffs, 0, offsets2); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_stpq_indexed(vs2, coeffs, 32, offsets2); + + vs_ldpq_indexed(vs1, coeffs, 256, offsets2); + vs_ldpq_indexed(vs2, coeffs, 256 + 32, offsets2); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs3, coeffs, 256, offsets2); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_stpq_indexed(vs2, coeffs, 256 + 32, offsets2); + + // level 4 + + int offsets1[4] = { 0, 32, 128, 160 }; + vs_ldpq_indexed(vs1, coeffs, 0, offsets1); + vs_ldpq_indexed(vs2, coeffs, 64, offsets1); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs3, coeffs, 0, offsets1); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_stpq_indexed(vs2, coeffs, 64, offsets1); + + vs_ldpq_indexed(vs1, coeffs, 256, offsets1); + vs_ldpq_indexed(vs2, coeffs, 256 + 64, offsets1); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs3, coeffs, 256, offsets1); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_stpq_indexed(vs2, coeffs, 256 + 64, offsets1); + + // level 5 + + __ add(tmpAddr, coeffs, 0); + load64shorts(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 128); + load64shorts(vs2, tmpAddr); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 0); + store64shorts(vs3, tmpAddr); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 128); + store64shorts(vs2, tmpAddr); + + load64shorts(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 384); + load64shorts(vs2, tmpAddr); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 256); + store64shorts(vs3, tmpAddr); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 384); + store64shorts(vs2, tmpAddr); + + // Barrett reduction at indexes where overflow may happen + + // load q and the multiplier for the Barrett reduction + __ add(tmpAddr, kyberConsts, 16); + vs_ldpq(vq, tmpAddr); + + int offsets0[2] = { 0, 256 }; + vs_ldpq_indexed(vs_front(vs1), coeffs, 0, offsets0); + vs_sqdmulh(vs2, __ T8H, vs1, vq2); + vs_sshr(vs2, __ T8H, vs2, 11); + vs_mlsv(vs1, __ T8H, vs2, vq1); + vs_stpq_indexed(vs_front(vs1), coeffs, 0, offsets0); + + // level 6 + + __ add(tmpAddr, coeffs, 0); + load64shorts(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 256); + load64shorts(vs2, tmpAddr); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 0); + store64shorts(vs3, tmpAddr); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 256); + store64shorts(vs2, tmpAddr); + + __ add(tmpAddr, coeffs, 128); + load64shorts(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 384); + load64shorts(vs2, tmpAddr); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 128); + store64shorts(vs3, tmpAddr); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 384); + store64shorts(vs2, tmpAddr); + + // multiply by 2^-n + + // load toMont(2^-n mod q) + __ add(tmpAddr, kyberConsts, 48); + __ ldr(v29, __ Q, tmpAddr); + + vs_ldpq(vq, kyberConsts); + __ add(tmpAddr, coeffs, 0); + load64shorts(vs1, tmpAddr); + kyber_montmul64(vs2, vs1, vq3, vtmp, vq); + __ add(tmpAddr, coeffs, 0); + store64shorts(vs2, tmpAddr); + + // now tmpAddr contains coeffs + 128 because store64shorts adjusted it so + load64shorts(vs1, tmpAddr); + kyber_montmul64(vs2, vs1, vq3, vtmp, vq); + __ add(tmpAddr, coeffs, 128); + store64shorts(vs2, tmpAddr); + + // now tmpAddr contains coeffs + 256 + load64shorts(vs1, tmpAddr); + kyber_montmul64(vs2, vs1, vq3, vtmp, vq); + __ add(tmpAddr, coeffs, 256); + store64shorts(vs2, tmpAddr); + + // now tmpAddr contains coeffs + 384 + load64shorts(vs1, tmpAddr); + kyber_montmul64(vs2, vs1, vq3, vtmp, vq); + __ add(tmpAddr, coeffs, 384); + store64shorts(vs2, tmpAddr); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber multiply polynomials in the NTT domain. + // Implements + // static int implKyberNttMult( + // short[] result, short[] ntta, short[] nttb, short[] zetas) {} + // + // result (short[256]) = c_rarg0 + // ntta (short[256]) = c_rarg1 + // nttb (short[256]) = c_rarg2 + // zetas (short[128]) = c_rarg3 + address generate_kyberNttMult() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "kyberNttMult"); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register ntta = c_rarg1; + const Register nttb = c_rarg2; + const Register zetas = c_rarg3; + + const Register kyberConsts = r10; + const Register limit = r11; + + VSeq<4> vs1(0), vs2(4); // 4 sets of 8x8H inputs/outputs/tmps + VSeq<4> vs3(16), vs4(20); + VSeq<2> vq(30); // pair of constants for montmul: q, qinv + VSeq<2> vz(28); // pair of zetas + VSeq<4> vc(27, 0); // constant sequence for montmul: montRSquareModQ + + __ lea(kyberConsts, + ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + + Label kyberNttMult_loop; + + __ add(limit, result, 512); + + // load q and qinv + vs_ldpq(vq, kyberConsts); + + // load R^2 mod q (to convert back from Montgomery representation) + __ add(kyberConsts, kyberConsts, 64); + __ ldr(v27, __ Q, kyberConsts); + + __ BIND(kyberNttMult_loop); + + // load 16 zetas + vs_ldpq_post(vz, zetas); + + // load 2 sets of 32 coefficients from the two input arrays + // interleaved as shorts. i.e. pairs of shorts adjacent in memory + // are striped across pairs of vector registers + vs_ld2_post(vs_front(vs1), __ T8H, ntta); // x 8H + vs_ld2_post(vs_back(vs1), __ T8H, nttb); // x 8H + vs_ld2_post(vs_front(vs4), __ T8H, ntta); // x 8H + vs_ld2_post(vs_back(vs4), __ T8H, nttb); // x 8H + + // compute 4 montmul cross-products for pairs (a0,a1) and (b0,b1) + // i.e. montmul the first and second halves of vs1 in order and + // then with one sequence reversed storing the two results in vs3 + // + // vs3[0] <- montmul(a0, b0) + // vs3[1] <- montmul(a1, b1) + // vs3[2] <- montmul(a0, b1) + // vs3[3] <- montmul(a1, b0) + kyber_montmul16(vs_front(vs3), vs_front(vs1), vs_back(vs1), vs_front(vs2), vq); + kyber_montmul16(vs_back(vs3), + vs_front(vs1), vs_reverse(vs_back(vs1)), vs_back(vs2), vq); + + // compute 4 montmul cross-products for pairs (a2,a3) and (b2,b3) + // i.e. montmul the first and second halves of vs4 in order and + // then with one sequence reversed storing the two results in vs1 + // + // vs1[0] <- montmul(a2, b2) + // vs1[1] <- montmul(a3, b3) + // vs1[2] <- montmul(a2, b3) + // vs1[3] <- montmul(a3, b2) + kyber_montmul16(vs_front(vs1), vs_front(vs4), vs_back(vs4), vs_front(vs2), vq); + kyber_montmul16(vs_back(vs1), + vs_front(vs4), vs_reverse(vs_back(vs4)), vs_back(vs2), vq); + + // montmul result 2 of each cross-product i.e. (a1*b1, a3*b3) by a zeta. + // We can schedule two montmuls at a time if we use a suitable vector + // sequence . + int delta = vs1[1]->encoding() - vs3[1]->encoding(); + VSeq<2> vs5(vs3[1], delta); + + // vs3[1] <- montmul(montmul(a1, b1), z0) + // vs1[1] <- montmul(montmul(a3, b3), z1) + kyber_montmul16(vs5, vz, vs5, vs_front(vs2), vq); + + // add results in pairs storing in vs3 + // vs3[0] <- montmul(a0, b0) + montmul(montmul(a1, b1), z0); + // vs3[1] <- montmul(a0, b1) + montmul(a1, b0); + vs_addv(vs_front(vs3), __ T8H, vs_even(vs3), vs_odd(vs3)); + + // vs3[2] <- montmul(a2, b2) + montmul(montmul(a3, b3), z1); + // vs3[3] <- montmul(a2, b3) + montmul(a3, b2); + vs_addv(vs_back(vs3), __ T8H, vs_even(vs1), vs_odd(vs1)); + + // vs1 <- montmul(vs3, montRSquareModQ) + kyber_montmul32(vs1, vs3, vc, vs2, vq); + + // store back the two pairs of result vectors de-interleaved as 8H elements + // i.e. storing each pairs of shorts striped across a register pair adjacent + // in memory + vs_st2_post(vs1, __ T8H, result); + + __ cmp(result, limit); + __ br(Assembler::NE, kyberNttMult_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber add 2 polynomials. + // Implements + // static int implKyberAddPoly(short[] result, short[] a, short[] b) {} + // + // result (short[256]) = c_rarg0 + // a (short[256]) = c_rarg1 + // b (short[256]) = c_rarg2 + address generate_kyberAddPoly_2() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "kyberAddPoly_2"); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register a = c_rarg1; + const Register b = c_rarg2; + + const Register kyberConsts = r11; + + // We sum 256 sets of values in total i.e. 32 x 8H quadwords. + // So, we can load, add and store the data in 3 groups of 11, + // 11 and 10 at a time i.e. we need to map sets of 10 or 11 + // registers. A further constraint is that the mapping needs + // to skip callee saves. So, we allocate the register + // sequences using two 8 sequences, two 2 sequences and two + // single registers. + VSeq<8> vs1_1(0); + VSeq<2> vs1_2(16); + FloatRegister vs1_3 = v28; + VSeq<8> vs2_1(18); + VSeq<2> vs2_2(26); + FloatRegister vs2_3 = v29; + + // two constant vector sequences + VSeq<8> vc_1(31, 0); + VSeq<2> vc_2(31, 0); + + FloatRegister vc_3 = v31; + __ lea(kyberConsts, + ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + + __ ldr(vc_3, __ Q, Address(kyberConsts, 16)); // q + for (int i = 0; i < 3; i++) { + // load 80 or 88 values from a into vs1_1/2/3 + vs_ldpq_post(vs1_1, a); + vs_ldpq_post(vs1_2, a); + if (i < 2) { + __ ldr(vs1_3, __ Q, __ post(a, 16)); + } + // load 80 or 88 values from b into vs2_1/2/3 + vs_ldpq_post(vs2_1, b); + vs_ldpq_post(vs2_2, b); + if (i < 2) { + __ ldr(vs2_3, __ Q, __ post(b, 16)); + } + // sum 80 or 88 values across vs1 and vs2 into vs1 + vs_addv(vs1_1, __ T8H, vs1_1, vs2_1); + vs_addv(vs1_2, __ T8H, vs1_2, vs2_2); + if (i < 2) { + __ addv(vs1_3, __ T8H, vs1_3, vs2_3); + } + // add constant to all 80 or 88 results + vs_addv(vs1_1, __ T8H, vs1_1, vc_1); + vs_addv(vs1_2, __ T8H, vs1_2, vc_2); + if (i < 2) { + __ addv(vs1_3, __ T8H, vs1_3, vc_3); + } + // store 80 or 88 values + vs_stpq_post(vs1_1, result); + vs_stpq_post(vs1_2, result); + if (i < 2) { + __ str(vs1_3, __ Q, __ post(result, 16)); + } + } + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber add 3 polynomials. + // Implements + // static int implKyberAddPoly(short[] result, short[] a, short[] b, short[] c) {} + // + // result (short[256]) = c_rarg0 + // a (short[256]) = c_rarg1 + // b (short[256]) = c_rarg2 + // c (short[256]) = c_rarg3 + address generate_kyberAddPoly_3() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "kyberAddPoly_3"); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register a = c_rarg1; + const Register b = c_rarg2; + const Register c = c_rarg3; + + const Register kyberConsts = r11; + + // As above we sum 256 sets of values in total i.e. 32 x 8H + // quadwords. So, we can load, add and store the data in 3 + // groups of 11, 11 and 10 at a time i.e. we need to map sets + // of 10 or 11 registers. A further constraint is that the + // mapping needs to skip callee saves. So, we allocate the + // register sequences using two 8 sequences, two 2 sequences + // and two single registers. + VSeq<8> vs1_1(0); + VSeq<2> vs1_2(16); + FloatRegister vs1_3 = v28; + VSeq<8> vs2_1(18); + VSeq<2> vs2_2(26); + FloatRegister vs2_3 = v29; + + // two constant vector sequences + VSeq<8> vc_1(31, 0); + VSeq<2> vc_2(31, 0); + + FloatRegister vc_3 = v31; + + __ lea(kyberConsts, + ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + + __ ldr(vc_3, __ Q, Address(kyberConsts, 16)); // q + for (int i = 0; i < 3; i++) { + // load 80 or 88 values from a into vs1_1/2/3 + vs_ldpq_post(vs1_1, a); + vs_ldpq_post(vs1_2, a); + if (i < 2) { + __ ldr(vs1_3, __ Q, __ post(a, 16)); + } + // load 80 or 88 values from b into vs2_1/2/3 + vs_ldpq_post(vs2_1, b); + vs_ldpq_post(vs2_2, b); + if (i < 2) { + __ ldr(vs2_3, __ Q, __ post(b, 16)); + } + // sum 80 or 88 values across vs1 and vs2 into vs1 + vs_addv(vs1_1, __ T8H, vs1_1, vs2_1); + vs_addv(vs1_2, __ T8H, vs1_2, vs2_2); + if (i < 2) { + __ addv(vs1_3, __ T8H, vs1_3, vs2_3); + } + // load 80 or 88 values from c into vs2_1/2/3 + vs_ldpq_post(vs2_1, c); + vs_ldpq_post(vs2_2, c); + if (i < 2) { + __ ldr(vs2_3, __ Q, __ post(c, 16)); + } + // sum 80 or 88 values across vs1 and vs2 into vs1 + vs_addv(vs1_1, __ T8H, vs1_1, vs2_1); + vs_addv(vs1_2, __ T8H, vs1_2, vs2_2); + if (i < 2) { + __ addv(vs1_3, __ T8H, vs1_3, vs2_3); + } + // add constant to all 80 or 88 results + vs_addv(vs1_1, __ T8H, vs1_1, vc_1); + vs_addv(vs1_2, __ T8H, vs1_2, vc_2); + if (i < 2) { + __ addv(vs1_3, __ T8H, vs1_3, vc_3); + } + // store 80 or 88 values + vs_stpq_post(vs1_1, result); + vs_stpq_post(vs1_2, result); + if (i < 2) { + __ str(vs1_3, __ Q, __ post(result, 16)); + } + } + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber parse XOF output to polynomial coefficient candidates + // or decodePoly(12, ...). + // Implements + // static int implKyber12To16( + // byte[] condensed, int index, short[] parsed, int parsedLength) {} + // + // 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[]) = c_rarg2 + // parsedLength = c_rarg3 + address generate_kyber12To16() { + Label L_F00, L_loop; + + __ BIND(L_F00); + __ emit_int64(0x0f000f000f000f00); + __ emit_int64(0x0f000f000f000f00); + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "kyber12To16"); + address start = __ pc(); + __ enter(); + + const Register condensed = c_rarg0; + const Register condensedOffs = c_rarg1; + const Register parsed = c_rarg2; + const Register parsedLength = c_rarg3; + + const Register tmpAddr = r11; + + // Data is input 96 bytes at a time i.e. in groups of 6 x 16B + // quadwords so we need a 6 vector sequence for the inputs. + // Parsing produces 64 shorts, employing two 8 vector + // sequences to store and combine the intermediate data. + VSeq<6> vin(24); + VSeq<8> va(0), vb(16); + + __ adr(tmpAddr, L_F00); + __ ldr(v31, __ Q, tmpAddr); // 8H times 0x0f00 + __ add(condensed, condensed, condensedOffs); + + __ BIND(L_loop); + // load 96 (6 x 16B) byte values + vs_ld3_post(vin, __ T16B, condensed); + + // The front half of sequence vin (vin[0], vin[1] and vin[2]) + // holds 48 (16x3) contiguous bytes from memory striped + // horizontally across each of the 16 byte lanes. Equivalently, + // that is 16 pairs of 12-bit integers. Likewise the back half + // holds the next 48 bytes in the same arrangement. + + // Each vector in the front half can also be viewed as a vertical + // strip across the 16 pairs of 12 bit integers. Each byte in + // vin[0] stores the low 8 bits of the first int in a pair. Each + // byte in vin[1] stores the high 4 bits of the first int and the + // low 4 bits of the second int. Each byte in vin[2] stores the + // high 8 bits of the second int. Likewise the vectors in second + // half. + + // Converting the data to 16-bit shorts requires first of all + // expanding each of the 6 x 16B vectors into 6 corresponding + // pairs of 8H vectors. Mask, shift and add operations on the + // resulting vector pairs can be used to combine 4 and 8 bit + // parts of related 8H vector elements. + // + // The middle vectors (vin[2] and vin[5]) are actually expanded + // twice, one copy manipulated to provide the lower 4 bits + // belonging to the first short in a pair and another copy + // manipulated to provide the higher 4 bits belonging to the + // second short in a pair. This is why the the vector sequences va + // and vb used to hold the expanded 8H elements are of length 8. + + // 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 duplicate elements 4 and 5 + __ 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); + + // likewise expand vin[3] into vb[0:1], and vin[4] into vb[2:3] + // and vb[4:5] + __ ushll(vb[0], __ T8H, vin[3], __ T8B, 0); + __ ushll2(vb[1], __ T8H, vin[3], __ T16B, 0); + __ ushll(vb[2], __ T8H, vin[4], __ T8B, 0); + __ ushll2(vb[3], __ T8H, vin[4], __ T16B, 0); + __ ushll(vb[4], __ T8H, vin[4], __ T8B, 0); + __ ushll2(vb[5], __ T8H, vin[4], __ T16B, 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); + __ shl(vb[3], __ T8H, vb[3], 8); + + // expand vin[2] into va[6:7] and vin[5] into vb[6:7] but this + // time pre-shifted by 4 to ensure top bits of 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); + __ ushll2(vb[7], __ T8H, vin[5], __ T16B, 4); + + // mask hi 4 bits of the 1st 12-bit int in a pair from copy1 and + // shift lo 4 bits of the 2nd 12-bit int in a pair to the 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); + __ andr(vb[3], __ T16B, vb[3], v31); + __ ushr(vb[4], __ T8H, vb[4], 4); + __ ushr(vb[5], __ T8H, vb[5], 4); + + // sum hi 4 bits and lo 8 bits of the 1st 12-bit int in each pair and + // hi 8 bits plus lo 4 bits of the 2nd 12-bit int in each pair + // n.b. the ordering ensures: i) inputs are consumed before they + // are overwritten ii) the order of 16-bit results across successive + // pairs of vectors in va and then vb reflects the order of the + // 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[2], __ T8H, vb[1], vb[3]); + __ addv(vb[1], __ T8H, vb[4], vb[6]); + __ addv(vb[3], __ T8H, vb[5], vb[7]); + + // store 64 results interleaved as shorts + vs_st2_post(vs_front(va), __ T8H, parsed); + vs_st2_post(vs_front(vb), __ T8H, parsed); + + __ sub(parsedLength, parsedLength, 64); + __ cmp(parsedLength, (u1)0); + __ br(Assembler::GT, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber Barrett reduce function. + // Implements + // static int implKyberBarrettReduce(short[] coeffs) {} + // + // coeffs (short[256]) = c_rarg0 + address generate_kyberBarrettReduce() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "kyberBarrettReduce"); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + + const Register kyberConsts = r10; + const Register result = r11; + + // As above we process 256 sets of values in total i.e. 32 x + // 8H quadwords. So, we can load, add and store the data in 3 + // groups of 11, 11 and 10 at a time i.e. we need to map sets + // of 10 or 11 registers. A further constraint is that the + // mapping needs to skip callee saves. So, we allocate the + // register sequences using two 8 sequences, two 2 sequences + // and two single registers. + VSeq<8> vs1_1(0); + VSeq<2> vs1_2(16); + FloatRegister vs1_3 = v28; + VSeq<8> vs2_1(18); + VSeq<2> vs2_2(26); + FloatRegister vs2_3 = v29; + + // we also need a pair of corresponding constant sequences + + VSeq<8> vc1_1(30, 0); + VSeq<2> vc1_2(30, 0); + FloatRegister vc1_3 = v30; // for kyber_q + + VSeq<8> vc2_1(31, 0); + VSeq<2> vc2_2(31, 0); + FloatRegister vc2_3 = v31; // for kyberBarrettMultiplier + + __ add(result, coeffs, 0); + __ lea(kyberConsts, + ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + + // load q and the multiplier for the Barrett reduction + __ add(kyberConsts, kyberConsts, 16); + __ ldpq(vc1_3, vc2_3, kyberConsts); + + for (int i = 0; i < 3; i++) { + // load 80 or 88 coefficients + vs_ldpq_post(vs1_1, coeffs); + vs_ldpq_post(vs1_2, coeffs); + if (i < 2) { + __ ldr(vs1_3, __ Q, __ post(coeffs, 16)); + } + + // vs2 <- (2 * vs1 * kyberBarrettMultiplier) >> 16 + vs_sqdmulh(vs2_1, __ T8H, vs1_1, vc2_1); + vs_sqdmulh(vs2_2, __ T8H, vs1_2, vc2_2); + if (i < 2) { + __ sqdmulh(vs2_3, __ T8H, vs1_3, vc2_3); + } + + // vs2 <- (vs1 * kyberBarrettMultiplier) >> 26 + vs_sshr(vs2_1, __ T8H, vs2_1, 11); + vs_sshr(vs2_2, __ T8H, vs2_2, 11); + if (i < 2) { + __ sshr(vs2_3, __ T8H, vs2_3, 11); + } + + // vs1 <- vs1 - vs2 * kyber_q + vs_mlsv(vs1_1, __ T8H, vs2_1, vc1_1); + vs_mlsv(vs1_2, __ T8H, vs2_2, vc1_2); + if (i < 2) { + __ mlsv(vs1_3, __ T8H, vs2_3, vc1_3); + } + + vs_stpq_post(vs1_1, result); + vs_stpq_post(vs1_2, result); + if (i < 2) { + __ str(vs1_3, __ Q, __ post(result, 16)); + } + } + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + + // Dilithium-specific montmul helper routines that generate parallel + // code for, respectively, a single 4x4s vector sequence montmul or + // two such multiplies in a row. + + // Perform 16 32-bit Montgomery multiplications in parallel + void dilithium_montmul16(const VSeq<4>& va, const VSeq<4>& vb, const VSeq<4>& vc, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + // Use the helper routine to schedule a 4x4S Montgomery multiply. + // It will assert that the register use is valid + vs_montmul4(va, vb, vc, __ T4S, vtmp, vq); + } + + // Perform 2x16 32-bit Montgomery multiplications in parallel + void dilithium_montmul32(const VSeq<8>& va, const VSeq<8>& vb, const VSeq<8>& vc, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + // Schedule two successive 4x4S multiplies via the montmul helper + // on the front and back halves of va, vb and vc. The helper will + // assert that the register use has no overlap conflicts on each + // individual call but we also need to ensure that the necessary + // disjoint/equality constraints are met across both calls. + + // vb, vc, vtmp and vq must be disjoint. va must either be + // disjoint from all other registers or equal vc + + assert(vs_disjoint(vb, vc), "vb and vc overlap"); + assert(vs_disjoint(vb, vq), "vb and vq overlap"); + assert(vs_disjoint(vb, vtmp), "vb and vtmp overlap"); + + assert(vs_disjoint(vc, vq), "vc and vq overlap"); + assert(vs_disjoint(vc, vtmp), "vc and vtmp overlap"); + + assert(vs_disjoint(vq, vtmp), "vq and vtmp overlap"); + + assert(vs_disjoint(va, vc) || vs_same(va, vc), "va and vc neither disjoint nor equal"); + assert(vs_disjoint(va, vb), "va and vb overlap"); + assert(vs_disjoint(va, vq), "va and vq overlap"); + assert(vs_disjoint(va, vtmp), "va and vtmp overlap"); + + // We multiply the front and back halves of each sequence 4 at a + // time because + // + // 1) we are currently only able to get 4-way instruction + // parallelism at best + // + // 2) we need registers for the constants in vq and temporary + // scratch registers to hold intermediate results so vtmp can only + // be a VSeq<4> which means we only have 4 scratch slots. + + vs_montmul4(vs_front(va), vs_front(vb), vs_front(vc), __ T4S, vtmp, vq); + vs_montmul4(vs_back(va), vs_back(vb), vs_back(vc), __ T4S, vtmp, vq); + } + + // Perform combined montmul then add/sub on 4x4S vectors. + void dilithium_montmul16_sub_add( + const VSeq<4>& va0, const VSeq<4>& va1, const VSeq<4>& vc, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + // compute a = montmul(a1, c) + dilithium_montmul16(vc, va1, vc, vtmp, vq); + // ouptut a1 = a0 - a + vs_subv(va1, __ T4S, va0, vc); + // and a0 = a0 + a + vs_addv(va0, __ T4S, va0, vc); + } + + // Perform combined add/sub then montul on 4x4S vectors. + void dilithium_sub_add_montmul16( + const VSeq<4>& va0, const VSeq<4>& va1, const VSeq<4>& vb, + const VSeq<4>& vtmp1, const VSeq<4>& vtmp2, const VSeq<2>& vq) { + // compute c = a0 - a1 + vs_subv(vtmp1, __ T4S, va0, va1); + // output a0 = a0 + a1 + vs_addv(va0, __ T4S, va0, va1); + // output a1 = b montmul c + dilithium_montmul16(va1, vtmp1, vb, vtmp2, vq); + } + + // At these levels, the indices that correspond to the 'j's (and 'j+l's) + // in the Java implementation come in sequences of at least 8, so we + // can use ldpq to collect the corresponding data into pairs of vector + // registers. + // We collect the coefficients corresponding to the 'j+l' indexes into + // the vector registers v0-v7, the zetas into the vector registers v16-v23 + // then we do the (Montgomery) multiplications by the zetas in parallel + // into v16-v23, load the coeffs corresponding to the 'j' indexes into + // v0-v7, then do the additions into v24-v31 and the subtractions into + // v0-v7 and finally save the results back to the coeffs array. + void dilithiumNttLevel0_4(const Register dilithiumConsts, + const Register coeffs, const Register zetas) { + int c1 = 0; + int c2 = 512; + int startIncr; + // don't use callee save registers v8 - v15 + VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x4s inputs/outputs + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<2> vq(30); // n.b. constants overlap vs3 + int offsets[4] = { 0, 32, 64, 96 }; + + for (int level = 0; level < 5; level++) { + int c1Start = c1; + int c2Start = c2; + if (level == 3) { + offsets[1] = 32; + offsets[2] = 128; + offsets[3] = 160; + } else if (level == 4) { + offsets[1] = 64; + offsets[2] = 128; + offsets[3] = 192; + } + + // For levels 1 - 4 we simply load 2 x 4 adjacent values at a + // time at 4 different offsets and multiply them in order by the + // next set of input values. So we employ indexed load and store + // pair instructions with arrangement 4S. + for (int i = 0; i < 4; i++) { + // reload q and qinv + vs_ldpq(vq, dilithiumConsts); // qInv, q + // load 8x4S coefficients via second start pos == c2 + vs_ldpq_indexed(vs1, coeffs, c2Start, offsets); + // load next 8x4S inputs == b + vs_ldpq_post(vs2, zetas); + // compute a == c2 * b mod MONT_Q + dilithium_montmul32(vs2, vs1, vs2, vtmp, vq); + // load 8x4s coefficients via first start pos == c1 + vs_ldpq_indexed(vs1, coeffs, c1Start, offsets); + // compute a1 = c1 + a + vs_addv(vs3, __ T4S, vs1, vs2); + // compute a2 = c1 - a + vs_subv(vs1, __ T4S, vs1, vs2); + // output a1 and a2 + vs_stpq_indexed(vs3, coeffs, c1Start, offsets); + vs_stpq_indexed(vs1, coeffs, c2Start, offsets); + + int k = 4 * level + i; + + if (k > 7) { + startIncr = 256; + } else if (k == 5) { + startIncr = 384; + } else { + startIncr = 128; + } + + c1Start += startIncr; + c2Start += startIncr; + } + + c2 /= 2; + } + } + + // Dilithium NTT function except for the final "normalization" to |coeff| < Q. + // Implements the method + // static int implDilithiumAlmostNtt(int[] coeffs, int zetas[]) {} + // of the Java class sun.security.provider + // + // coeffs (int[256]) = c_rarg0 + // zetas (int[256]) = c_rarg1 + address generate_dilithiumAlmostNtt() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "dilithiumAlmostNtt"); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register tmpAddr = r9; + const Register dilithiumConsts = r10; + const Register result = r11; + // don't use callee save registers v8 - v15 + VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x4s inputs/outputs + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<2> vq(30); // n.b. constants overlap vs3 + int offsets[4] = { 0, 32, 64, 96}; + int offsets1[8] = { 16, 48, 80, 112, 144, 176, 208, 240 }; + int offsets2[8] = { 0, 32, 64, 96, 128, 160, 192, 224 }; + __ add(result, coeffs, 0); + __ lea(dilithiumConsts, + ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + + // Each level represents one iteration of the outer for loop of the Java version. + + // level 0-4 + dilithiumNttLevel0_4(dilithiumConsts, coeffs, zetas); + + // level 5 + + // At level 5 the coefficients we need to combine with the zetas + // are grouped in memory in blocks of size 4. So, for both sets of + // coefficients we load 4 adjacent values at 8 different offsets + // using an indexed ldr with register variant Q and multiply them + // in sequence order by the next set of inputs. Likewise we store + // the resuls using an indexed str with register variant Q. + for (int i = 0; i < 1024; i += 256) { + // reload constants q, qinv each iteration as they get clobbered later + vs_ldpq(vq, dilithiumConsts); // qInv, q + // load 32 (8x4S) coefficients via first offsets = c1 + vs_ldr_indexed(vs1, __ Q, coeffs, i, offsets1); + // load next 32 (8x4S) inputs = b + vs_ldpq_post(vs2, zetas); + // a = b montul c1 + dilithium_montmul32(vs2, vs1, vs2, vtmp, vq); + // load 32 (8x4S) coefficients via second offsets = c2 + vs_ldr_indexed(vs1, __ Q, coeffs, i, offsets2); + // add/sub with result of multiply + vs_addv(vs3, __ T4S, vs1, vs2); // a1 = a - c2 + vs_subv(vs1, __ T4S, vs1, vs2); // a0 = a + c1 + // write back new coefficients using same offsets + vs_str_indexed(vs3, __ Q, coeffs, i, offsets2); + vs_str_indexed(vs1, __ Q, coeffs, i, offsets1); + } + + // level 6 + // At level 6 the coefficients we need to combine with the zetas + // are grouped in memory in pairs, the first two being montmul + // inputs and the second add/sub inputs. We can still implement + // the montmul+sub+add using 4-way parallelism but only if we + // combine the coefficients with the zetas 16 at a time. We load 8 + // adjacent values at 4 different offsets using an ld2 load with + // arrangement 2D. That interleaves the lower and upper halves of + // each pair of quadwords into successive vector registers. We + // then need to montmul the 4 even elements of the coefficients + // register sequence by the zetas in order and then add/sub the 4 + // odd elements of the coefficients register sequence. We use an + // equivalent st2 operation to store the results back into memory + // de-interleaved. + for (int i = 0; i < 1024; i += 128) { + // reload constants q, qinv each iteration as they get clobbered later + vs_ldpq(vq, dilithiumConsts); // qInv, q + // load interleaved 16 (4x2D) coefficients via offsets + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, i, offsets); + // load next 16 (4x4S) inputs + vs_ldpq_post(vs_front(vs2), zetas); + // mont multiply odd elements of vs1 by vs2 and add/sub into odds/evens + dilithium_montmul16_sub_add(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vtmp, vq); + // store interleaved 16 (4x2D) coefficients via offsets + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, i, offsets); + } + + // level 7 + // At level 7 the coefficients we need to combine with the zetas + // occur singly with montmul inputs alterating with add/sub + // inputs. Once again we can use 4-way parallelism to combine 16 + // zetas at a time. However, we have to load 8 adjacent values at + // 4 different offsets using an ld2 load with arrangement 4S. That + // interleaves the the odd words of each pair into one + // coefficients vector register and the even words of the pair + // into the next register. We then need to montmul the 4 even + // elements of the coefficients register sequence by the zetas in + // order and then add/sub the 4 odd elements of the coefficients + // register sequence. We use an equivalent st2 operation to store + // the results back into memory de-interleaved. + + for (int i = 0; i < 1024; i += 128) { + // reload constants q, qinv each iteration as they get clobbered later + vs_ldpq(vq, dilithiumConsts); // qInv, q + // load interleaved 16 (4x4S) coefficients via offsets + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, i, offsets); + // load next 16 (4x4S) inputs + vs_ldpq_post(vs_front(vs2), zetas); + // mont multiply odd elements of vs1 by vs2 and add/sub into odds/evens + dilithium_montmul16_sub_add(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vtmp, vq); + // store interleaved 16 (4x4S) coefficients via offsets + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, i, offsets); + } + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // At these levels, the indices that correspond to the 'j's (and 'j+l's) + // in the Java implementation come in sequences of at least 8, so we + // can use ldpq to collect the corresponding data into pairs of vector + // registers + // We collect the coefficients that correspond to the 'j's into vs1 + // the coefficiets that correspond to the 'j+l's into vs2 then + // do the additions into vs3 and the subtractions into vs1 then + // save the result of the additions, load the zetas into vs2 + // do the (Montgomery) multiplications by zeta in parallel into vs2 + // finally save the results back to the coeffs array + void dilithiumInverseNttLevel3_7(const Register dilithiumConsts, + const Register coeffs, const Register zetas) { + int c1 = 0; + int c2 = 32; + int startIncr; + int offsets[4]; + VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x4s inputs/outputs + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<2> vq(30); // n.b. constants overlap vs3 + + offsets[0] = 0; + + for (int level = 3; level < 8; level++) { + int c1Start = c1; + int c2Start = c2; + if (level == 3) { + offsets[1] = 64; + offsets[2] = 128; + offsets[3] = 192; + } else if (level == 4) { + offsets[1] = 32; + offsets[2] = 128; + offsets[3] = 160; + } else { + offsets[1] = 32; + offsets[2] = 64; + offsets[3] = 96; + } + + // For levels 3 - 7 we simply load 2 x 4 adjacent values at a + // time at 4 different offsets and multiply them in order by the + // next set of input values. So we employ indexed load and store + // pair instructions with arrangement 4S. + for (int i = 0; i < 4; i++) { + // load v1 32 (8x4S) coefficients relative to first start index + vs_ldpq_indexed(vs1, coeffs, c1Start, offsets); + // load v2 32 (8x4S) coefficients relative to second start index + vs_ldpq_indexed(vs2, coeffs, c2Start, offsets); + // a0 = v1 + v2 -- n.b. clobbers vqs + vs_addv(vs3, __ T4S, vs1, vs2); + // a1 = v1 - v2 + vs_subv(vs1, __ T4S, vs1, vs2); + // save a1 relative to first start index + vs_stpq_indexed(vs3, coeffs, c1Start, offsets); + // load constants q, qinv each iteration as they get clobbered above + vs_ldpq(vq, dilithiumConsts); // qInv, q + // load b next 32 (8x4S) inputs + vs_ldpq_post(vs2, zetas); + // a = a1 montmul b + dilithium_montmul32(vs2, vs1, vs2, vtmp, vq); + // save a relative to second start index + vs_stpq_indexed(vs2, coeffs, c2Start, offsets); + + int k = 4 * level + i; + + if (k < 24) { + startIncr = 256; + } else if (k == 25) { + startIncr = 384; + } else { + startIncr = 128; + } + + c1Start += startIncr; + c2Start += startIncr; + } + + c2 *= 2; + } + } + + // Dilithium Inverse NTT function except the final mod Q division by 2^256. + // Implements the method + // static int implDilithiumAlmostInverseNtt(int[] coeffs, int[] zetas) {} of + // the sun.security.provider.ML_DSA class. + // + // coeffs (int[256]) = c_rarg0 + // zetas (int[256]) = c_rarg1 + address generate_dilithiumAlmostInverseNtt() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "dilithiumAlmostInverseNtt"); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register tmpAddr = r9; + const Register dilithiumConsts = r10; + const Register result = r11; + VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x4s inputs/outputs + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<2> vq(30); // n.b. constants overlap vs3 + int offsets[4] = { 0, 32, 64, 96 }; + int offsets1[8] = { 0, 32, 64, 96, 128, 160, 192, 224 }; + int offsets2[8] = { 16, 48, 80, 112, 144, 176, 208, 240 }; + + __ add(result, coeffs, 0); + __ lea(dilithiumConsts, + ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + + // Each level represents one iteration of the outer for loop of the Java version + + // level 0 + // At level 0 we need to interleave adjacent quartets of + // coefficients before we multiply and add/sub by the next 16 + // zetas just as we did for level 7 in the multiply code. So we + // load and store the values using an ld2/st2 with arrangement 4S. + for (int i = 0; i < 1024; i += 128) { + // load constants q, qinv + // n.b. this can be moved out of the loop as they do not get + // clobbered by first two loops + vs_ldpq(vq, dilithiumConsts); // qInv, q + // a0/a1 load interleaved 32 (8x4S) coefficients + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, i, offsets); + // b load next 32 (8x4S) inputs + vs_ldpq_post(vs_front(vs2), zetas); + // compute in parallel (a0, a1) = (a0 + a1, (a0 - a1) montmul b) + // n.b. second half of vs2 provides temporary register storage + dilithium_sub_add_montmul16(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + // a0/a1 store interleaved 32 (8x4S) coefficients + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, i, offsets); + } + + // level 1 + // At level 1 we need to interleave pairs of adjacent pairs of + // coefficients before we multiply by the next 16 zetas just as we + // did for level 6 in the multiply code. So we load and store the + // values an ld2/st2 with arrangement 2D. + for (int i = 0; i < 1024; i += 128) { + // a0/a1 load interleaved 32 (8x2D) coefficients + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, i, offsets); + // b load next 16 (4x4S) inputs + vs_ldpq_post(vs_front(vs2), zetas); + // compute in parallel (a0, a1) = (a0 + a1, (a0 - a1) montmul b) + // n.b. second half of vs2 provides temporary register storage + dilithium_sub_add_montmul16(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + // a0/a1 store interleaved 32 (8x2D) coefficients + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, i, offsets); + } + + // level 2 + // At level 2 coefficients come in blocks of 4. So, we load 4 + // adjacent coefficients at 8 distinct offsets for both the first + // and second coefficient sequences, using an ldr with register + // variant Q then combine them with next set of 32 zetas. Likewise + // we store the results using an str with register variant Q. + for (int i = 0; i < 1024; i += 256) { + // c0 load 32 (8x4S) coefficients via first offsets + vs_ldr_indexed(vs1, __ Q, coeffs, i, offsets1); + // c1 load 32 (8x4S) coefficients via second offsets + vs_ldr_indexed(vs2, __ Q,coeffs, i, offsets2); + // a0 = c0 + c1 n.b. clobbers vq which overlaps vs3 + vs_addv(vs3, __ T4S, vs1, vs2); + // c = c0 - c1 + vs_subv(vs1, __ T4S, vs1, vs2); + // store a0 32 (8x4S) coefficients via first offsets + vs_str_indexed(vs3, __ Q, coeffs, i, offsets1); + // b load 32 (8x4S) next inputs + vs_ldpq_post(vs2, zetas); + // reload constants q, qinv -- they were clobbered earlier + vs_ldpq(vq, dilithiumConsts); // qInv, q + // compute a1 = b montmul c + dilithium_montmul32(vs2, vs1, vs2, vtmp, vq); + // store a1 32 (8x4S) coefficients via second offsets + vs_str_indexed(vs2, __ Q, coeffs, i, offsets2); + } + + // level 3-7 + dilithiumInverseNttLevel3_7(dilithiumConsts, coeffs, zetas); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Dilithium multiply polynomials in the NTT domain. + // Straightforward implementation of the method + // static int implDilithiumNttMult( + // int[] result, int[] ntta, int[] nttb {} of + // the sun.security.provider.ML_DSA class. + // + // result (int[256]) = c_rarg0 + // poly1 (int[256]) = c_rarg1 + // poly2 (int[256]) = c_rarg2 + address generate_dilithiumNttMult() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "dilithiumNttMult"); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register result = c_rarg0; + const Register poly1 = c_rarg1; + const Register poly2 = c_rarg2; + + const Register dilithiumConsts = r10; + const Register len = r11; + + VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x4s inputs/outputs + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<2> vq(30); // n.b. constants overlap vs3 + VSeq<8> vrsquare(29, 0); // for montmul by constant RSQUARE + + __ lea(dilithiumConsts, + ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + + // load constants q, qinv + vs_ldpq(vq, dilithiumConsts); // qInv, q + // load constant rSquare into v29 + __ ldr(v29, __ Q, Address(dilithiumConsts, 48)); // rSquare + + __ mov(len, zr); + __ add(len, len, 1024); + + __ BIND(L_loop); + + // b load 32 (8x4S) next inputs from poly1 + vs_ldpq_post(vs1, poly1); + // c load 32 (8x4S) next inputs from poly2 + vs_ldpq_post(vs2, poly2); + // compute a = b montmul c + dilithium_montmul32(vs2, vs1, vs2, vtmp, vq); + // compute a = rsquare montmul a + dilithium_montmul32(vs2, vrsquare, vs2, vtmp, vq); + // save a 32 (8x4S) results + vs_stpq_post(vs2, result); + + __ sub(len, len, 128); + __ cmp(len, (u1)128); + __ br(Assembler::GE, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Dilithium Motgomery multiply an array by a constant. + // A straightforward implementation of the method + // static int implDilithiumMontMulByConstant(int[] coeffs, int constant) {} + // of the sun.security.provider.MLDSA class + // + // coeffs (int[256]) = c_rarg0 + // constant (int) = c_rarg1 + address generate_dilithiumMontMulByConstant() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "dilithiumMontMulByConstant"); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register coeffs = c_rarg0; + const Register constant = c_rarg1; + + const Register dilithiumConsts = r10; + const Register result = r11; + const Register len = r12; + + VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x4s inputs/outputs + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<2> vq(30); // n.b. constants overlap vs3 + VSeq<8> vconst(29, 0); // for montmul by constant + + // results track inputs + __ add(result, coeffs, 0); + __ lea(dilithiumConsts, + ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + + // load constants q, qinv -- they do not get clobbered by first two loops + vs_ldpq(vq, dilithiumConsts); // qInv, q + // copy caller supplied constant across vconst + __ dup(vconst[0], __ T4S, constant); + __ mov(len, zr); + __ add(len, len, 1024); + + __ BIND(L_loop); + + // load next 32 inputs + vs_ldpq_post(vs2, coeffs); + // mont mul by constant + dilithium_montmul32(vs2, vconst, vs2, vtmp, vq); + // write next 32 results + vs_stpq_post(vs2, result); + + __ sub(len, len, 128); + __ cmp(len, (u1)128); + __ br(Assembler::GE, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Dilithium decompose poly. + // Implements the method + // static int implDilithiumDecomposePoly(int[] coeffs, int constant) {} + // of the sun.security.provider.ML_DSA class + // + // input (int[256]) = c_rarg0 + // lowPart (int[256]) = c_rarg1 + // highPart (int[256]) = c_rarg2 + // twoGamma2 (int) = c_rarg3 + // multiplier (int) = c_rarg4 + address generate_dilithiumDecomposePoly() { + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "dilithiumDecomposePoly"); + address start = __ pc(); + Label L_loop; + + const Register input = c_rarg0; + const Register lowPart = c_rarg1; + const Register highPart = c_rarg2; + const Register twoGamma2 = c_rarg3; + const Register multiplier = c_rarg4; + + const Register len = r9; + const Register dilithiumConsts = r10; + const Register tmp = r11; + + // 6 independent sets of 4x4s values + VSeq<4> vs1(0), vs2(4), vs3(8); + VSeq<4> vs4(12), vs5(16), vtmp(20); + + // 7 constants for cross-multiplying + VSeq<4> one(25, 0); + VSeq<4> qminus1(26, 0); + VSeq<4> g2(27, 0); + VSeq<4> twog2(28, 0); + VSeq<4> mult(29, 0); + VSeq<4> q(30, 0); + VSeq<4> qadd(31, 0); + + __ enter(); + + __ lea(dilithiumConsts, + ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + + // save callee-saved registers + __ stpd(v8, v9, __ pre(sp, -64)); + __ stpd(v10, v11, Address(sp, 16)); + __ stpd(v12, v13, Address(sp, 32)); + __ stpd(v14, v15, Address(sp, 48)); + + // populate constant registers + __ mov(tmp, zr); + __ add(tmp, tmp, 1); + __ dup(one[0], __ T4S, tmp); // 1 + __ ldr(q[0], __ Q, Address(dilithiumConsts, 16)); // q + __ ldr(qadd[0], __ Q, Address(dilithiumConsts, 64)); // addend for mod q reduce + __ dup(twog2[0], __ T4S, twoGamma2); // 2 * gamma2 + __ dup(mult[0], __ T4S, multiplier); // multiplier for mod 2 * gamma reduce + __ subv(qminus1[0], __ T4S, v30, v25); // q - 1 + __ sshr(g2[0], __ T4S, v28, 1); // gamma2 + + __ mov(len, zr); + __ add(len, len, 1024); + + __ BIND(L_loop); + + // load next 4x4S inputs interleaved: rplus --> vs1 + __ ld4(vs1[0], vs1[1], vs1[2], vs1[3], __ T4S, __ post(input, 64)); + + // rplus = rplus - ((rplus + qadd) >> 23) * q + vs_addv(vtmp, __ T4S, vs1, qadd); + vs_sshr(vtmp, __ T4S, vtmp, 23); + vs_mulv(vtmp, __ T4S, vtmp, q); + vs_subv(vs1, __ T4S, vs1, vtmp); + + // rplus = rplus + ((rplus >> 31) & dilithium_q); + vs_sshr(vtmp, __ T4S, vs1, 31); + vs_andr(vtmp, vtmp, q); + vs_addv(vs1, __ T4S, vs1, vtmp); + + // quotient --> vs2 + // int quotient = (rplus * multiplier) >> 22; + vs_mulv(vtmp, __ T4S, vs1, mult); + vs_sshr(vs2, __ T4S, vtmp, 22); + + // r0 --> vs3 + // int r0 = rplus - quotient * twoGamma2; + vs_mulv(vtmp, __ T4S, vs2, twog2); + vs_subv(vs3, __ T4S, vs1, vtmp); + + // mask --> vs4 + // int mask = (twoGamma2 - r0) >> 22; + vs_subv(vtmp, __ T4S, twog2, vs3); + vs_sshr(vs4, __ T4S, vtmp, 22); + + // r0 -= (mask & twoGamma2); + vs_andr(vtmp, vs4, twog2); + vs_subv(vs3, __ T4S, vs3, vtmp); + + // quotient += (mask & 1); + vs_andr(vtmp, vs4, one); + vs_addv(vs2, __ T4S, vs2, vtmp); + + // mask = (twoGamma2 / 2 - r0) >> 31; + vs_subv(vtmp, __ T4S, g2, vs3); + vs_sshr(vs4, __ T4S, vtmp, 31); + + // r0 -= (mask & twoGamma2); + vs_andr(vtmp, vs4, twog2); + vs_subv(vs3, __ T4S, vs3, vtmp); + + // quotient += (mask & 1); + vs_andr(vtmp, vs4, one); + vs_addv(vs2, __ T4S, vs2, vtmp); + + // r1 --> vs5 + // int r1 = rplus - r0 - (dilithium_q - 1); + vs_subv(vtmp, __ T4S, vs1, vs3); + vs_subv(vs5, __ T4S, vtmp, qminus1); + + // r1 --> vs1 (overwriting rplus) + // r1 = (r1 | (-r1)) >> 31; // 0 if rplus - r0 == (dilithium_q - 1), -1 otherwise + vs_negr(vtmp, __ T4S, vs5); + vs_orr(vtmp, vs5, vtmp); + vs_sshr(vs1, __ T4S, vtmp, 31); + + // r0 += ~r1; + vs_notr(vtmp, vs1); + vs_addv(vs3, __ T4S, vs3, vtmp); + + // r1 = r1 & quotient; + vs_andr(vs1, vs2, vs1); + + // store results inteleaved + // lowPart[m] = r0; + // highPart[m] = r1; + __ st4(vs3[0], vs3[1], vs3[2], vs3[3], __ T4S, __ post(lowPart, 64)); + __ st4(vs1[0], vs1[1], vs1[2], vs1[3], __ T4S, __ post(highPart, 64)); + + __ sub(len, len, 64); + __ cmp(len, (u1)64); + __ br(Assembler::GE, L_loop); + + // restore callee-saved vector registers + __ ldpd(v14, v15, Address(sp, 48)); + __ ldpd(v12, v13, Address(sp, 32)); + __ ldpd(v10, v11, Address(sp, 16)); + __ ldpd(v8, v9, __ post(sp, 64)); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + /** * Arguments: * @@ -8743,6 +11138,7 @@ #endif // LINUX +#ifdef COMPILER2 if (UseSecondarySupersTable) { StubRoutines::_lookup_secondary_supers_table_slow_path_stub = generate_lookup_secondary_supers_table_slow_path_stub(); if (! InlineSecondarySupersTest) { @@ -8752,6 +11148,7 @@ } } } +#endif StubRoutines::aarch64::set_completed(); // Inidicate that arraycopy and zero_blocks stubs are generated } @@ -8822,6 +11219,24 @@ StubRoutines::_chacha20Block = generate_chacha20Block_blockpar(); } + if (UseKyberIntrinsics) { + StubRoutines::_kyberNtt = generate_kyberNtt(); + StubRoutines::_kyberInverseNtt = generate_kyberInverseNtt(); + StubRoutines::_kyberNttMult = generate_kyberNttMult(); + StubRoutines::_kyberAddPoly_2 = generate_kyberAddPoly_2(); + StubRoutines::_kyberAddPoly_3 = generate_kyberAddPoly_3(); + StubRoutines::_kyber12To16 = generate_kyber12To16(); + StubRoutines::_kyberBarrettReduce = generate_kyberBarrettReduce(); + } + + if (UseDilithiumIntrinsics) { + StubRoutines::_dilithiumAlmostNtt = generate_dilithiumAlmostNtt(); + StubRoutines::_dilithiumAlmostInverseNtt = generate_dilithiumAlmostInverseNtt(); + StubRoutines::_dilithiumNttMult = generate_dilithiumNttMult(); + StubRoutines::_dilithiumMontMulByConstant = generate_dilithiumMontMulByConstant(); + StubRoutines::_dilithiumDecomposePoly = generate_dilithiumDecomposePoly(); + } + if (UseBASE64Intrinsics) { StubRoutines::_base64_encodeBlock = generate_base64_encodeBlock(); StubRoutines::_base64_decodeBlock = generate_base64_decodeBlock(); @@ -8864,6 +11279,7 @@ } if (UseSHA3Intrinsics) { StubRoutines::_sha3_implCompress = generate_sha3_implCompress(false, "sha3_implCompress"); + StubRoutines::_double_keccak = generate_double_keccak(); StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress(true, "sha3_implCompressMB"); } diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -68,6 +68,26 @@ bool StubRoutines::aarch64::_completed = false; +ATTRIBUTE_ALIGNED(64) uint16_t StubRoutines::aarch64::_kyberConsts[] = +{ + // Because we sometimes load these in pairs, montQInvModR, kyber_q + // and kyberBarrettMultiplier should stay together and in this order. + 0xF301, 0xF301, 0xF301, 0xF301, 0xF301, 0xF301, 0xF301, 0xF301, // montQInvModR + 0x0D01, 0x0D01, 0x0D01, 0x0D01, 0x0D01, 0x0D01, 0x0D01, 0x0D01, // kyber_q + 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, // kyberBarrettMultiplier + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, // toMont((kyber_n / 2)^-1 (mod kyber_q)) + 0x0549, 0x0549, 0x0549, 0x0549, 0x0549, 0x0549, 0x0549, 0x0549 // montRSquareModQ +}; + +ATTRIBUTE_ALIGNED(64) uint32_t StubRoutines::aarch64::_dilithiumConsts[] = +{ + 58728449, 58728449, 58728449, 58728449, // montQInvModR + 8380417, 8380417, 8380417, 8380417, // dilithium_q + 16382, 16382, 16382, 16382, // toMont((dilithium_n)^-1 (mod dilithium_q)) + 2365951, 2365951, 2365951, 2365951, // montRSquareModQ + 5373807, 5373807, 5373807, 5373807 // addend for modular reduce +}; + /** * crc_table[] from jdk/src/share/native/java/util/zip/zlib-1.2.5/crc32.h */ diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp 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, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -38,7 +38,7 @@ // simply increase sizes if too small (assembler will crash if too small) _initial_stubs_code_size = 10000, _continuation_stubs_code_size = 2000, - _compiler_stubs_code_size = 30000 ZGC_ONLY(+10000), + _compiler_stubs_code_size = 63000, _final_stubs_code_size = 20000 ZGC_ONLY(+100000) }; @@ -220,6 +220,8 @@ } private: + static uint16_t _kyberConsts[]; + static uint32_t _dilithiumConsts[]; static juint _crc_table[]; static jubyte _adler_table[]; // begin trigonometric tables block. See comments in .cpp file diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -411,6 +411,28 @@ FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); } + if (_features & CPU_ASIMD) { + if (FLAG_IS_DEFAULT(UseKyberIntrinsics)) { + UseKyberIntrinsics = true; + } + } else if (UseKyberIntrinsics) { + if (!FLAG_IS_DEFAULT(UseKyberIntrinsics)) { + warning("Kyber intrinsics require ASIMD instructions"); + } + FLAG_SET_DEFAULT(UseKyberIntrinsics, false); + } + + if (_features & CPU_ASIMD) { + if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { + UseDilithiumIntrinsics = true; + } + } else if (UseDilithiumIntrinsics) { + if (!FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { + warning("Dilithium intrinsics require ASIMD instructions"); + } + FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false); + } + if (FLAG_IS_DEFAULT(UseBASE64Intrinsics)) { UseBASE64Intrinsics = true; } diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/assembler_x86.cpp openjdk-21-21.0.13+9/src/hotspot/cpu/x86/assembler_x86.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/assembler_x86.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/assembler_x86.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -3260,6 +3260,23 @@ emit_operand(src, dst, 0); } +void Assembler::evmovdquw(XMMRegister dst, XMMRegister src, int vector_len) { + // Unmasked instruction + evmovdquw(dst, k0, src, /*merge*/ false, vector_len); +} + +void Assembler::evmovdquw(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { + assert(vector_len <= AVX_256bit ? VM_Version::supports_avx512vlbw() : VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_embedded_opmask_register_specifier(mask); + attributes.set_is_evex_instruction(); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int16(0x6F, (0xC0 | encode)); +} + void Assembler::evmovdquw(XMMRegister dst, Address src, int vector_len) { // Unmasked instruction evmovdquw(dst, k0, src, /*merge*/ false, vector_len); @@ -4299,22 +4316,6 @@ emit_int24(0x01, (0xC0 | encode), imm8); } -void Assembler::evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); - emit_int16(0x76, (0xC0 | encode)); -} - -void Assembler::evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - assert(VM_Version::supports_avx512_vbmi(), ""); - InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); - emit_int16(0x7D, (0xC0 | encode)); -} - void Assembler::evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512_vbmi(), ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -7483,6 +7484,15 @@ emit_int16((unsigned char)0xF4, (0xC0 | encode)); } +void Assembler::vpmuldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + (vector_len == AVX_256bit ? VM_Version::supports_avx2() : VM_Version::supports_evex()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_rex_vex_w_reverted(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x28, (0xC0 | encode)); +} + void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); @@ -9438,6 +9448,18 @@ emit_operand(dst, src, 0); } +void Assembler::evpmulhw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); + 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, &attributes); + emit_int16((unsigned char)0xE5, (0xC0 | encode)); +} + void Assembler::evmulps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); @@ -14067,3 +14089,83 @@ _input_size_in_bits = input_size_in_bits; } } + +void Assembler::evpermt2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(vector_len <= AVX_256bit ? VM_Version::supports_avx512vlbw() : VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x7D, (0xC0 | encode)); +} + +void Assembler::evpermt2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x7E, (0xC0 | encode)); +} + +void Assembler::evpermt2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x7E, (0xC0 | encode)); +} + +void Assembler::evpermi2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_vbmi() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x75, (0xC0 | encode)); +} + +void Assembler::evpermi2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x75, (0xC0 | encode)); +} + +void Assembler::evpermi2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x76, (0xC0 | encode)); +} + +void Assembler::evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x76, (0xC0 | encode)); +} + +void Assembler::evpermi2ps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x77, (0xC0 | encode)); +} + +void Assembler::evpermi2pd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x77, (0xC0 | encode)); +} + +void Assembler::evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_vbmi(), ""); + InstructionAttr attributes(vector_len, /* vex_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(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x7D, (0xC0 | encode)); +} diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/assembler_x86.hpp openjdk-21-21.0.13+9/src/hotspot/cpu/x86/assembler_x86.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/assembler_x86.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/assembler_x86.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -1597,6 +1597,7 @@ void evmovdqub(XMMRegister dst, KRegister mask, Address src, bool merge, int vector_len); void evmovdqub(Address dst, KRegister mask, XMMRegister src, bool merge, int vector_len); + void evmovdquw(XMMRegister dst, XMMRegister src, int vector_len); void evmovdquw(XMMRegister dst, Address src, int vector_len); void evmovdquw(Address dst, XMMRegister src, int vector_len); void evmovdquw(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len); @@ -1775,9 +1776,17 @@ void vpermilps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpermilpd(XMMRegister dst, XMMRegister src, int imm8, int vector_len); void vpermpd(XMMRegister dst, XMMRegister src, int imm8, int vector_len); + void evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len); + void evpermi2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2ps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2pd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); - void evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len); + void evpermt2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermt2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermt2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void pause(); @@ -2420,6 +2429,7 @@ void evsubps(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); void evsubpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); void evsubpd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); + void evpmulhw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); void evpmullw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); void evpmullw(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int vector_len); void evpmulld(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); @@ -2556,6 +2566,7 @@ void vpmulld(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpmullq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpmuludq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpmuldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void vpmulld(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void evpmullq(XMMRegister dst, XMMRegister nds, Address src, int vector_len); diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/macroAssembler_x86.hpp openjdk-21-21.0.13+9/src/hotspot/cpu/x86/macroAssembler_x86.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/macroAssembler_x86.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/macroAssembler_x86.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -1220,6 +1220,7 @@ void evmovdqub(XMMRegister dst, KRegister mask, Address src, bool merge, int vector_len) { Assembler::evmovdqub(dst, mask, src, merge, vector_len); } void evmovdqub(XMMRegister dst, KRegister mask, AddressLiteral src, bool merge, int vector_len, Register rscratch = noreg); + void evmovdquw(XMMRegister dst, XMMRegister src, int vector_len) { Assembler::evmovdquw(dst, src, vector_len); } void evmovdquw(Address dst, XMMRegister src, int vector_len) { Assembler::evmovdquw(dst, src, vector_len); } void evmovdquw(XMMRegister dst, Address src, int vector_len) { Assembler::evmovdquw(dst, src, vector_len); } @@ -1428,6 +1429,8 @@ void vpmulld(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { Assembler::vpmulld(dst, nds, src, vector_len); } void vpmulld(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register rscratch = noreg); + void vpmuldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { Assembler::vpmuldq(dst, nds, src, vector_len); } + void vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector_len); @@ -1437,9 +1440,13 @@ void vpsraw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); void vpsraw(XMMRegister dst, XMMRegister nds, int shift, int vector_len); + void evpsrad(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); + void evpsrad(XMMRegister dst, XMMRegister nds, int shift, int vector_len); + void evpsraq(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); void evpsraq(XMMRegister dst, XMMRegister nds, int shift, int vector_len); + using Assembler::evpsllw; void evpsllw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len, bool is_varshift) { if (!is_varshift) { Assembler::evpsllw(dst, mask, nds, src, merge, vector_len); @@ -1482,6 +1489,7 @@ Assembler::evpsrlvq(dst, mask, nds, src, merge, vector_len); } } + using Assembler::evpsraw; void evpsraw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len, bool is_varshift) { if (!is_varshift) { Assembler::evpsraw(dst, mask, nds, src, merge, vector_len); @@ -1489,6 +1497,7 @@ Assembler::evpsravw(dst, mask, nds, src, merge, vector_len); } } + using Assembler::evpsrad; void evpsrad(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len, bool is_varshift) { if (!is_varshift) { Assembler::evpsrad(dst, mask, nds, src, merge, vector_len); diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -4206,6 +4206,12 @@ StubRoutines::_base64_decodeBlock = generate_base64_decodeBlock(); } + generate_kyber_stubs(); + + generate_dilithium_stubs(); + + generate_sha3_stubs(); + #ifdef COMPILER2 if (UseMultiplyToLenIntrinsic) { StubRoutines::_multiplyToLen = generate_multiplyToLen(); diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -423,8 +423,16 @@ const XMMRegister L0, const XMMRegister L1, const XMMRegister L2, bool padMSG, const XMMRegister TMP, const Register rscratch); - // BASE64 stubs + // SHA3 stubs + void generate_sha3_stubs(); + + // Kyber stubs + void generate_kyber_stubs(); + // Dilithium stubs + void generate_dilithium_stubs(); + + // BASE64 stubs address base64_shuffle_addr(); address base64_avx2_shuffle_addr(); address base64_avx2_input_mask_addr(); diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,1030 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "runtime/stubRoutines.hpp" +#include "macroAssembler_x86.hpp" +#include "stubGenerator_x86_64.hpp" + +#define __ _masm-> + +#define xmm(i) as_XMMRegister(i) + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif // PRODUCT + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +#define XMMBYTES 64 + +// Constants +// +ATTRIBUTE_ALIGNED(64) static const uint32_t dilithiumAvx512Consts[] = { + 58728449, // montQInvModR + 8380417, // dilithium_q + 2365951, // montRSquareModQ + 5373807 // Barrett addend for modular reduction +}; + +const int montQInvModRIdx = 0; +const int dilithium_qIdx = 4; +const int montRSquareModQIdx = 8; +const int barrettAddendIdx = 12; + +static address dilithiumAvx512ConstsAddr(int offset) { + return ((address) dilithiumAvx512Consts) + offset; +} + +const Register scratch = r10; +const XMMRegister montMulPerm = xmm28; +const XMMRegister montQInvModR = xmm30; +const XMMRegister dilithium_q = xmm31; + + +ATTRIBUTE_ALIGNED(64) static const uint32_t dilithiumAvx512Perms[] = { + // collect montmul results into the destination register + 17, 1, 19, 3, 21, 5, 23, 7, 25, 9, 27, 11, 29, 13, 31, 15, + // ntt + // level 4 + 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, + 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31, + // level 5 + 0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27, + 4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31, + // level 6 + 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29, + 2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31, + // level 7 + 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30, + 1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31, + 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23, + 8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31, + + // ntt inverse + // level 0 + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, + 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, + // level 1 + 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30, + 1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31, + // level 2 + 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29, + 2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31, + // level 3 + 0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27, + 4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31, + // level 4 + 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, + 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 +}; + +const int montMulPermsIdx = 0; +const int nttL4PermsIdx = 64; +const int nttL5PermsIdx = 192; +const int nttL6PermsIdx = 320; +const int nttL7PermsIdx = 448; +const int nttInvL0PermsIdx = 704; +const int nttInvL1PermsIdx = 832; +const int nttInvL2PermsIdx = 960; +const int nttInvL3PermsIdx = 1088; +const int nttInvL4PermsIdx = 1216; + +static address dilithiumAvx512PermsAddr() { + return (address) dilithiumAvx512Perms; +} + +// We do Montgomery multiplications of two vectors of 16 ints each in 4 steps: +// 1. Do the multiplications of the corresponding even numbered slots into +// the odd numbered slots of a third register. +// 2. Swap the even and odd numbered slots of the original input registers. +// 3. Similar to step 1, but into a different output register. +// 4. Combine the outputs of step 1 and step 3 into the output of the Montgomery +// multiplication. +// (For levels 0-6 in the Ntt and levels 1-7 of the inverse Ntt we only swap the +// odd-even slots of the first multiplicand as in the second (zetas) the +// odd slots contain the same number as the corresponding even one.) +// The indexes of the registers to be multiplied +// are in inputRegs1[] and inputRegs[2]. +// The results go to the registers whose indexes are in outputRegs. +// scratchRegs should contain 12 different register indexes. +// The set in outputRegs should not overlap with the set of the middle four +// scratch registers. +// The sets in inputRegs1 and inputRegs2 cannot overlap with the set of the +// first eight scratch registers. +// In most of the cases, the odd and the corresponding even slices of the +// registers indexed by the numbers in inputRegs2 will contain the same number, +// this should be indicated by calling this function with +// input2NeedsShuffle=false . +// +static void montMul64(int outputRegs[], int inputRegs1[], int inputRegs2[], + int scratchRegs[], bool input2NeedsShuffle, + MacroAssembler *_masm) { + + for (int i = 0; i < 4; i++) { + __ vpmuldq(xmm(scratchRegs[i]), xmm(inputRegs1[i]), xmm(inputRegs2[i]), + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ vpmulld(xmm(scratchRegs[i + 4]), xmm(scratchRegs[i]), montQInvModR, + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ vpmuldq(xmm(scratchRegs[i + 4]), xmm(scratchRegs[i + 4]), dilithium_q, + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpsubd(xmm(scratchRegs[i + 4]), k0, xmm(scratchRegs[i]), + xmm(scratchRegs[i + 4]), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 4; i++) { + __ vpshufd(xmm(inputRegs1[i]), xmm(inputRegs1[i]), 0xB1, + Assembler::AVX_512bit); + if (input2NeedsShuffle) { + __ vpshufd(xmm(inputRegs2[i]), xmm(inputRegs2[i]), 0xB1, + Assembler::AVX_512bit); + } + } + + for (int i = 0; i < 4; i++) { + __ vpmuldq(xmm(scratchRegs[i]), xmm(inputRegs1[i]), xmm(inputRegs2[i]), + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ vpmulld(xmm(scratchRegs[i + 8]), xmm(scratchRegs[i]), montQInvModR, + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ vpmuldq(xmm(scratchRegs[i + 8]), xmm(scratchRegs[i + 8]), dilithium_q, + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpsubd(xmm(outputRegs[i]), k0, xmm(scratchRegs[i]), + xmm(scratchRegs[i + 8]), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 4; i++) { + __ evpermt2d(xmm(outputRegs[i]), montMulPerm, xmm(scratchRegs[i + 4]), + Assembler::AVX_512bit); + } +} + +static void montMul64(int outputRegs[], int inputRegs1[], int inputRegs2[], + int scratchRegs[], MacroAssembler *_masm) { + montMul64(outputRegs, inputRegs1, inputRegs2, scratchRegs, false, _masm); +} + +static void sub_add(int subResult[], int addResult[], + int input1[], int input2[], MacroAssembler *_masm) { + + for (int i = 0; i < 4; i++) { + __ evpsubd(xmm(subResult[i]), k0, xmm(input1[i]), xmm(input2[i]), false, + Assembler::AVX_512bit); + } + + for (int i = 0; i < 4; i++) { + __ evpaddd(xmm(addResult[i]), k0, xmm(input1[i]), xmm(input2[i]), false, + Assembler::AVX_512bit); + } +} + +static void loadPerm(int destinationRegs[], Register perms, + int offset, MacroAssembler *_masm) { + __ evmovdqul(xmm(destinationRegs[0]), Address(perms, offset), + Assembler::AVX_512bit); + for (int i = 1; i < 4; i++) { + __ evmovdqul(xmm(destinationRegs[i]), xmm(destinationRegs[0]), + Assembler::AVX_512bit); + } +} + +static void load4Xmms(int destinationRegs[], Register source, int offset, + MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evmovdqul(xmm(destinationRegs[i]), Address(source, offset + i * XMMBYTES), + Assembler::AVX_512bit); + } +} + +static void loadXmm29(Register source, int offset, MacroAssembler *_masm) { + __ evmovdqul(xmm29, Address(source, offset), Assembler::AVX_512bit); +} + +static void store4Xmms(Register destination, int offset, int xmmRegs[], + MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evmovdqul(Address(destination, offset + i * XMMBYTES), xmm(xmmRegs[i]), + Assembler::AVX_512bit); + } +} + +static int xmm0_3[] = {0, 1, 2, 3}; +static int xmm0145[] = {0, 1, 4, 5}; +static int xmm0246[] = {0, 2, 4, 6}; +static int xmm0426[] = {0, 4, 2, 6}; +static int xmm1357[] = {1, 3, 5, 7}; +static int xmm1537[] = {1, 5, 3, 7}; +static int xmm2367[] = {2, 3, 6, 7}; +static int xmm4_7[] = {4, 5, 6, 7}; +static int xmm8_11[] = {8, 9, 10, 11}; +static int xmm12_15[] = {12, 13, 14, 15}; +static int xmm16_19[] = {16, 17, 18, 19}; +static int xmm20_23[] = {20, 21, 22, 23}; +static int xmm20222426[] = {20, 22, 24, 26}; +static int xmm21232527[] = {21, 23, 25, 27}; +static int xmm24_27[] = {24, 25, 26, 27}; +static int xmm4_20_24[] = {4, 5, 6, 7, 20, 21, 22, 23, 24, 25, 26, 27}; +static int xmm16_27[] = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27}; +static int xmm29_29[] = {29, 29, 29, 29}; + +// Dilithium NTT function except for the final "normalization" to |coeff| < Q. +// Implements +// static int implDilithiumAlmostNtt(int[] coeffs, int zetas[]) {} +// +// coeffs (int[256]) = c_rarg0 +// zetas (int[256]) = c_rarg1 +// +// +static address generate_dilithiumAlmostNtt_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "dilithiumAlmostNtt"); + address start = __ pc(); + __ enter(); + + Label L_loop, L_end; + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + const Register iterations = c_rarg2; + + const Register perms = r11; + + __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); + + __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); + + // Each level represents one iteration of the outer for loop of the Java version + // In each of these iterations half of the coefficients are (Montgomery) + // multiplied by a zeta corresponding to the coefficient and then these + // products will be added to and subtracted from the other half of the + // coefficients. In each level we just collect the coefficients (using + // evpermi2d() instructions where necessary, i.e. in levels 4-7) that need to + // be multiplied by the zetas in one set, the rest to another set of vector + // registers, then redistribute the addition/substraction results. + + // For levels 0 and 1 the zetas are not different within the 4 xmm registers + // that we would use for them, so we use only one, xmm29. + loadXmm29(zetas, 0, _masm); + __ vpbroadcastd(montQInvModR, + ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), + Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + __ vpbroadcastd(dilithium_q, + ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), + Assembler::AVX_512bit, scratch); // q + + // load all coefficients into the vector registers Zmm_0-Zmm_15, + // 16 coefficients into each + load4Xmms(xmm0_3, coeffs, 0, _masm); + load4Xmms(xmm4_7, coeffs, 4 * XMMBYTES, _masm); + load4Xmms(xmm8_11, coeffs, 8 * XMMBYTES, _masm); + load4Xmms(xmm12_15, coeffs, 12 * XMMBYTES, _masm); + + // level 0 and 1 can be done entirely in registers as the zetas on these + // levels are the same for all the montmuls that we can do in parallel + + // level 0 + montMul64(xmm16_19, xmm8_11, xmm29_29, xmm16_27, _masm); + sub_add(xmm8_11, xmm0_3, xmm0_3, xmm16_19, _masm); + montMul64(xmm16_19, xmm12_15, xmm29_29, xmm16_27, _masm); + loadXmm29(zetas, 512, _masm); // for level 1 + sub_add(xmm12_15, xmm4_7, xmm4_7, xmm16_19, _masm); + + // level 1 + + montMul64(xmm16_19, xmm4_7, xmm29_29, xmm16_27, _masm); + loadXmm29(zetas, 768, _masm); + sub_add(xmm4_7, xmm0_3, xmm0_3, xmm16_19, _masm); + montMul64(xmm16_19, xmm12_15, xmm29_29, xmm16_27, _masm); + sub_add(xmm12_15, xmm8_11, xmm8_11, xmm16_19, _masm); + + // levels 2 to 7 are done in 2 batches, by first saving half of the coefficients + // from level 1 into memory, doing all the level 2 to level 7 computations + // on the remaining half in the vector registers, saving the result to + // memory after level 7, then loading back the coefficients that we saved after + // level 1 and do the same computation with those + + store4Xmms(coeffs, 8 * XMMBYTES, xmm8_11, _masm); + store4Xmms(coeffs, 12 * XMMBYTES, xmm12_15, _masm); + + __ movl(iterations, 2); + + __ align(OptoLoopAlignment); + __ BIND(L_loop); + + __ subl(iterations, 1); + + // level 2 + load4Xmms(xmm12_15, zetas, 2 * 512, _masm); + montMul64(xmm16_19, xmm2367, xmm12_15, xmm16_27, _masm); + load4Xmms(xmm12_15, zetas, 3 * 512, _masm); // for level 3 + sub_add(xmm2367, xmm0145, xmm0145, xmm16_19, _masm); + + // level 3 + + montMul64(xmm16_19, xmm1357, xmm12_15, xmm16_27, _masm); + sub_add(xmm1357, xmm0246, xmm0246, xmm16_19, _masm); + + // level 4 + loadPerm(xmm16_19, perms, nttL4PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttL4PermsIdx + 64, _masm); + load4Xmms(xmm24_27, zetas, 4 * 512, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i/2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + + montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, _masm); + sub_add(xmm1357, xmm0246, xmm16_19, xmm12_15, _masm); + + // level 5 + loadPerm(xmm16_19, perms, nttL5PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttL5PermsIdx + 64, _masm); + load4Xmms(xmm24_27, zetas, 5 * 512, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i/2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + + montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, _masm); + sub_add(xmm1357, xmm0246, xmm16_19, xmm12_15, _masm); + + // level 6 + loadPerm(xmm16_19, perms, nttL6PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttL6PermsIdx + 64, _masm); + load4Xmms(xmm24_27, zetas, 6 * 512, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i/2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + + montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, _masm); + sub_add(xmm1357, xmm0246, xmm16_19, xmm12_15, _masm); + + // level 7 + loadPerm(xmm16_19, perms, nttL7PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttL7PermsIdx + 64, _masm); + load4Xmms(xmm24_27, zetas, 7 * 512, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + + montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, true, _masm); + loadPerm(xmm0246, perms, nttL7PermsIdx + 2 * XMMBYTES, _masm); + loadPerm(xmm1357, perms, nttL7PermsIdx + 3 * XMMBYTES, _masm); + sub_add(xmm21232527, xmm20222426, xmm16_19, xmm12_15, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i), xmm(i + 20), xmm(i + 21), Assembler::AVX_512bit); + __ evpermi2d(xmm(i + 1), xmm(i + 20), xmm(i + 21), Assembler::AVX_512bit); + } + + __ cmpl(iterations, 0); + __ jcc(Assembler::equal, L_end); + + store4Xmms(coeffs, 0, xmm0_3, _masm); + store4Xmms(coeffs, 4 * XMMBYTES, xmm4_7, _masm); + + load4Xmms(xmm0_3, coeffs, 8 * XMMBYTES, _masm); + load4Xmms(xmm4_7, coeffs, 12 * XMMBYTES, _masm); + + __ addptr(zetas, 4 * XMMBYTES); + + __ jmp(L_loop); + + __ BIND(L_end); + + store4Xmms(coeffs, 8 * XMMBYTES, xmm0_3, _masm); + store4Xmms(coeffs, 12 * XMMBYTES, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Dilithium Inverse NTT function except the final mod Q division by 2^256. +// Implements +// static int implDilithiumAlmostInverseNtt(int[] coeffs, int[] zetas) {} +// +// coeffs (int[256]) = c_rarg0 +// zetas (int[256]) = c_rarg1 +static address generate_dilithiumAlmostInverseNtt_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "dilithiumAlmostInverseNtt"); + address start = __ pc(); + __ enter(); + + Label L_loop, L_end; + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register iterations = c_rarg2; + + const Register perms = r11; + + __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); + + __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); + __ vpbroadcastd(montQInvModR, + ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), + Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + __ vpbroadcastd(dilithium_q, + ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), + Assembler::AVX_512bit, scratch); // q + + // Each level represents one iteration of the outer for loop of the + // Java version. + // In each of these iterations half of the coefficients are added to and + // subtracted from the other half of the coefficients then the result of + // the substartion is (Montgomery) multiplied by the corresponding zetas. + // In each level we just collect the coefficients (using evpermi2d() + // instructions where necessary, i.e. on levels 0-4) so that the results of + // the additions and subtractions go to the vector registers so that they + // align with each other and the zetas. + + // We do levels 0-6 in two batches, each batch entirely in the vector registers + load4Xmms(xmm0_3, coeffs, 0, _masm); + load4Xmms(xmm4_7, coeffs, 4 * XMMBYTES, _masm); + + __ movl(iterations, 2); + + __ align(OptoLoopAlignment); + __ BIND(L_loop); + + __ subl(iterations, 1); + + // level 0 + loadPerm(xmm8_11, perms, nttInvL0PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttInvL0PermsIdx + 64, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 8), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + + load4Xmms(xmm4_7, zetas, 0, _masm); + sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); + montMul64(xmm4_7, xmm4_7, xmm24_27, xmm16_27, true, _masm); + + // level 1 + loadPerm(xmm8_11, perms, nttInvL1PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttInvL1PermsIdx + 64, _masm); + + for (int i = 0; i < 4; i++) { + __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + } + + load4Xmms(xmm4_7, zetas, 512, _masm); + sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); + montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); + + // level 2 + loadPerm(xmm8_11, perms, nttInvL2PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttInvL2PermsIdx + 64, _masm); + + for (int i = 0; i < 4; i++) { + __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + } + + load4Xmms(xmm4_7, zetas, 2 * 512, _masm); + sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); + montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); + + // level 3 + loadPerm(xmm8_11, perms, nttInvL3PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttInvL3PermsIdx + 64, _masm); + + for (int i = 0; i < 4; i++) { + __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + } + + load4Xmms(xmm4_7, zetas, 3 * 512, _masm); + sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); + montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); + + // level 4 + loadPerm(xmm8_11, perms, nttInvL4PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttInvL4PermsIdx + 64, _masm); + + for (int i = 0; i < 4; i++) { + __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + } + + load4Xmms(xmm4_7, zetas, 4 * 512, _masm); + sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); + montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); + + // level 5 + load4Xmms(xmm12_15, zetas, 5 * 512, _masm); + sub_add(xmm8_11, xmm0_3, xmm0426, xmm1537, _masm); + montMul64(xmm4_7, xmm8_11, xmm12_15, xmm16_27, _masm); + + // level 6 + load4Xmms(xmm12_15, zetas, 6 * 512, _masm); + sub_add(xmm8_11, xmm0_3, xmm0145, xmm2367, _masm); + montMul64(xmm4_7, xmm8_11, xmm12_15, xmm16_27, _masm); + + __ cmpl(iterations, 0); + __ jcc(Assembler::equal, L_end); + + // save the coefficients of the first batch, adjust the zetas + // and load the second batch of coefficients + store4Xmms(coeffs, 0, xmm0_3, _masm); + store4Xmms(coeffs, 4 * XMMBYTES, xmm4_7, _masm); + + __ addptr(zetas, 4 * XMMBYTES); + + load4Xmms(xmm0_3, coeffs, 8 * XMMBYTES, _masm); + load4Xmms(xmm4_7, coeffs, 12 * XMMBYTES, _masm); + + __ jmp(L_loop); + + __ BIND(L_end); + + // load the coeffs of the first batch of coefficients that were saved after + // level 6 into Zmm_8-Zmm_15 and do the last level entirely in the vector + // registers + load4Xmms(xmm8_11, coeffs, 0, _masm); + load4Xmms(xmm12_15, coeffs, 4 * XMMBYTES, _masm); + + // level 7 + + loadXmm29(zetas, 7 * 512, _masm); + + for (int i = 0; i < 8; i++) { + __ evpaddd(xmm(i + 16), k0, xmm(i), xmm(i + 8), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpsubd(xmm(i), k0, xmm(i + 8), xmm(i), false, Assembler::AVX_512bit); + } + + store4Xmms(coeffs, 0, xmm16_19, _masm); + store4Xmms(coeffs, 4 * XMMBYTES, xmm20_23, _masm); + montMul64(xmm0_3, xmm0_3, xmm29_29, xmm16_27, _masm); + montMul64(xmm4_7, xmm4_7, xmm29_29, xmm16_27, _masm); + store4Xmms(coeffs, 8 * XMMBYTES, xmm0_3, _masm); + store4Xmms(coeffs, 12 * XMMBYTES, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Dilithium multiply polynomials in the NTT domain. +// Implements +// static int implDilithiumNttMult( +// int[] result, int[] ntta, int[] nttb {} +// +// result (int[256]) = c_rarg0 +// poly1 (int[256]) = c_rarg1 +// poly2 (int[256]) = c_rarg2 +static address generate_dilithiumNttMult_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "dilithiumNttMult"); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register result = c_rarg0; + const Register poly1 = c_rarg1; + const Register poly2 = c_rarg2; + + const Register perms = r10; // scratch reused after not needed any more + const Register len = r11; + + const XMMRegister montRSquareModQ = xmm29; + + __ vpbroadcastd(montQInvModR, + ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), + Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + __ vpbroadcastd(dilithium_q, + ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), + Assembler::AVX_512bit, scratch); // q + __ vpbroadcastd(montRSquareModQ, + ExternalAddress(dilithiumAvx512ConstsAddr(montRSquareModQIdx)), + Assembler::AVX_512bit, scratch); // 2^64 mod q + + __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); + __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); + + __ movl(len, 4); + + __ align(OptoLoopAlignment); + __ BIND(L_loop); + + load4Xmms(xmm4_7, poly2, 0, _masm); + load4Xmms(xmm0_3, poly1, 0, _masm); + montMul64(xmm4_7, xmm4_7, xmm29_29, xmm16_27, _masm); + montMul64(xmm0_3, xmm0_3, xmm4_7, xmm16_27, true, _masm); + store4Xmms(result, 0, xmm0_3, _masm); + + __ subl(len, 1); + __ addptr(poly1, 4 * XMMBYTES); + __ addptr(poly2, 4 * XMMBYTES); + __ addptr(result, 4 * XMMBYTES); + __ cmpl(len, 0); + __ jcc(Assembler::notEqual, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Dilithium Motgomery multiply an array by a constant. +// Implements +// static int implDilithiumMontMulByConstant(int[] coeffs, int constant) {} +// +// coeffs (int[256]) = c_rarg0 +// constant (int) = c_rarg1 +static address generate_dilithiumMontMulByConstant_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "dilithiumMontMulByConstant"); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register coeffs = c_rarg0; + const Register rConstant = c_rarg1; + + const Register perms = c_rarg2; // not used for argument + const Register len = r11; + + const XMMRegister constant = xmm29; + + __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); + + // the following four vector registers are used in montMul64 + __ vpbroadcastd(montQInvModR, + ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), + Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + __ vpbroadcastd(dilithium_q, + ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), + Assembler::AVX_512bit, scratch); // q + __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); + __ evpbroadcastd(constant, rConstant, Assembler::AVX_512bit); // constant multiplier + + __ movl(len, 2); + + __ align(OptoLoopAlignment); + __ BIND(L_loop); + + load4Xmms(xmm0_3, coeffs, 0, _masm); + load4Xmms(xmm4_7, coeffs, 4 * XMMBYTES, _masm); + montMul64(xmm0_3, xmm0_3, xmm29_29, xmm16_27, _masm); + montMul64(xmm4_7, xmm4_7, xmm29_29, xmm16_27, _masm); + store4Xmms(coeffs, 0, xmm0_3, _masm); + store4Xmms(coeffs, 4 * XMMBYTES, xmm4_7, _masm); + + __ subl(len, 1); + __ addptr(coeffs, 512); + __ cmpl(len, 0); + __ jcc(Assembler::notEqual, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Dilithium decompose poly. +// Implements +// static int implDilithiumDecomposePoly(int[] coeffs, int constant) {} +// +// input (int[256]) = c_rarg0 +// lowPart (int[256]) = c_rarg1 +// highPart (int[256]) = c_rarg2 +// twoGamma2 (int) = c_rarg3 +// multiplier (int) = c_rarg4 +static address generate_dilithiumDecomposePoly_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "dilithiumDecomposePoly"); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register input = c_rarg0; + const Register lowPart = c_rarg1; + const Register highPart = c_rarg2; + const Register rTwoGamma2 = c_rarg3; + + const Register len = r11; + const XMMRegister zero = xmm24; + const XMMRegister one = xmm25; + const XMMRegister qMinus1 = xmm26; + const XMMRegister gamma2 = xmm27; + const XMMRegister twoGamma2 = xmm28; + const XMMRegister barrettMultiplier = xmm29; + const XMMRegister barrettAddend = xmm30; + + __ vpxor(zero, zero, zero, Assembler::AVX_512bit); // 0 + __ vpternlogd(xmm0, 0xff, xmm0, xmm0, Assembler::AVX_512bit); // -1 + __ vpsubd(one, zero, xmm0, Assembler::AVX_512bit); // 1 + __ vpbroadcastd(dilithium_q, + ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), + Assembler::AVX_512bit, scratch); // q + __ vpbroadcastd(barrettAddend, + ExternalAddress(dilithiumAvx512ConstsAddr(barrettAddendIdx)), + Assembler::AVX_512bit, scratch); // addend for Barrett reduction + + __ evpbroadcastd(twoGamma2, rTwoGamma2, Assembler::AVX_512bit); // 2 * gamma2 + + #ifndef _WIN64 + const Register rMultiplier = c_rarg4; + #else + const Address multiplier_mem(rbp, 6 * wordSize); + const Register rMultiplier = c_rarg3; // arg3 is already consumed, reused here + __ movptr(rMultiplier, multiplier_mem); + #endif + __ evpbroadcastd(barrettMultiplier, rMultiplier, + Assembler::AVX_512bit); // multiplier for mod 2 * gamma2 reduce + + __ evpsubd(qMinus1, k0, dilithium_q, one, false, Assembler::AVX_512bit); // q - 1 + __ evpsrad(gamma2, k0, twoGamma2, 1, false, Assembler::AVX_512bit); // gamma2 + + __ movl(len, 1024); + + __ align(OptoLoopAlignment); + __ BIND(L_loop); + + load4Xmms(xmm0_3, input, 0, _masm); + + __ addptr(input, 4 * XMMBYTES); + + // rplus in xmm0 + // rplus = rplus - ((rplus + 5373807) >> 23) * dilithium_q; + __ evpaddd(xmm4, k0, xmm0, barrettAddend, false, Assembler::AVX_512bit); + __ evpaddd(xmm5, k0, xmm1, barrettAddend, false, Assembler::AVX_512bit); + __ evpaddd(xmm6, k0, xmm2, barrettAddend, false, Assembler::AVX_512bit); + __ evpaddd(xmm7, k0, xmm3, barrettAddend, false, Assembler::AVX_512bit); + + __ evpsrad(xmm4, k0, xmm4, 23, false, Assembler::AVX_512bit); + __ evpsrad(xmm5, k0, xmm5, 23, false, Assembler::AVX_512bit); + __ evpsrad(xmm6, k0, xmm6, 23, false, Assembler::AVX_512bit); + __ evpsrad(xmm7, k0, xmm7, 23, false, Assembler::AVX_512bit); + + __ evpmulld(xmm4, k0, xmm4, dilithium_q, false, Assembler::AVX_512bit); + __ evpmulld(xmm5, k0, xmm5, dilithium_q, false, Assembler::AVX_512bit); + __ evpmulld(xmm6, k0, xmm6, dilithium_q, false, Assembler::AVX_512bit); + __ evpmulld(xmm7, k0, xmm7, dilithium_q, false, Assembler::AVX_512bit); + + __ evpsubd(xmm0, k0, xmm0, xmm4, false, Assembler::AVX_512bit); + __ evpsubd(xmm1, k0, xmm1, xmm5, false, Assembler::AVX_512bit); + __ evpsubd(xmm2, k0, xmm2, xmm6, false, Assembler::AVX_512bit); + __ evpsubd(xmm3, k0, xmm3, xmm7, false, Assembler::AVX_512bit); + // rplus in xmm0 + // rplus = rplus + ((rplus >> 31) & dilithium_q); + __ evpsrad(xmm4, k0, xmm0, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm5, k0, xmm1, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm6, k0, xmm2, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm7, k0, xmm3, 31, false, Assembler::AVX_512bit); + + __ evpandd(xmm4, k0, xmm4, dilithium_q, false, Assembler::AVX_512bit); + __ evpandd(xmm5, k0, xmm5, dilithium_q, false, Assembler::AVX_512bit); + __ evpandd(xmm6, k0, xmm6, dilithium_q, false, Assembler::AVX_512bit); + __ evpandd(xmm7, k0, xmm7, dilithium_q, false, Assembler::AVX_512bit); + + __ evpaddd(xmm0, k0, xmm0, xmm4, false, Assembler::AVX_512bit); + __ evpaddd(xmm1, k0, xmm1, xmm5, false, Assembler::AVX_512bit); + __ evpaddd(xmm2, k0, xmm2, xmm6, false, Assembler::AVX_512bit); + __ evpaddd(xmm3, k0, xmm3, xmm7, false, Assembler::AVX_512bit); + // rplus in xmm0 + // int quotient = (rplus * barrettMultiplier) >> 22; + __ evpmulld(xmm4, k0, xmm0, barrettMultiplier, false, Assembler::AVX_512bit); + __ evpmulld(xmm5, k0, xmm1, barrettMultiplier, false, Assembler::AVX_512bit); + __ evpmulld(xmm6, k0, xmm2, barrettMultiplier, false, Assembler::AVX_512bit); + __ evpmulld(xmm7, k0, xmm3, barrettMultiplier, false, Assembler::AVX_512bit); + + __ evpsrad(xmm4, k0, xmm4, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm5, k0, xmm5, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm6, k0, xmm6, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm7, k0, xmm7, 22, false, Assembler::AVX_512bit); + // quotient in xmm4 + // int r0 = rplus - quotient * twoGamma2; + __ evpmulld(xmm8, k0, xmm4, twoGamma2, false, Assembler::AVX_512bit); + __ evpmulld(xmm9, k0, xmm5, twoGamma2, false, Assembler::AVX_512bit); + __ evpmulld(xmm10, k0, xmm6, twoGamma2, false, Assembler::AVX_512bit); + __ evpmulld(xmm11, k0, xmm7, twoGamma2, false, Assembler::AVX_512bit); + + __ evpsubd(xmm8, k0, xmm0, xmm8, false, Assembler::AVX_512bit); + __ evpsubd(xmm9, k0, xmm1, xmm9, false, Assembler::AVX_512bit); + __ evpsubd(xmm10, k0, xmm2, xmm10, false, Assembler::AVX_512bit); + __ evpsubd(xmm11, k0, xmm3, xmm11, false, Assembler::AVX_512bit); + // r0 in xmm8 + // int mask = (twoGamma2 - r0) >> 22; + __ evpsubd(xmm12, k0, twoGamma2, xmm8, false, Assembler::AVX_512bit); + __ evpsubd(xmm13, k0, twoGamma2, xmm9, false, Assembler::AVX_512bit); + __ evpsubd(xmm14, k0, twoGamma2, xmm10, false, Assembler::AVX_512bit); + __ evpsubd(xmm15, k0, twoGamma2, xmm11, false, Assembler::AVX_512bit); + + __ evpsrad(xmm12, k0, xmm12, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm13, k0, xmm13, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm14, k0, xmm14, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm15, k0, xmm15, 22, false, Assembler::AVX_512bit); + // mask in xmm12 + // r0 -= (mask & twoGamma2); + __ evpandd(xmm16, k0, xmm12, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm17, k0, xmm13, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm18, k0, xmm14, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm19, k0, xmm15, twoGamma2, false, Assembler::AVX_512bit); + + __ evpsubd(xmm8, k0, xmm8, xmm16, false, Assembler::AVX_512bit); + __ evpsubd(xmm9, k0, xmm9, xmm17, false, Assembler::AVX_512bit); + __ evpsubd(xmm10, k0, xmm10, xmm18, false, Assembler::AVX_512bit); + __ evpsubd(xmm11, k0, xmm11, xmm19, false, Assembler::AVX_512bit); + // r0 in xmm8 + // quotient += (mask & 1); + __ evpandd(xmm16, k0, xmm12, one, false, Assembler::AVX_512bit); + __ evpandd(xmm17, k0, xmm13, one, false, Assembler::AVX_512bit); + __ evpandd(xmm18, k0, xmm14, one, false, Assembler::AVX_512bit); + __ evpandd(xmm19, k0, xmm15, one, false, Assembler::AVX_512bit); + + __ evpaddd(xmm4, k0, xmm4, xmm16, false, Assembler::AVX_512bit); + __ evpaddd(xmm5, k0, xmm5, xmm17, false, Assembler::AVX_512bit); + __ evpaddd(xmm6, k0, xmm6, xmm18, false, Assembler::AVX_512bit); + __ evpaddd(xmm7, k0, xmm7, xmm19, false, Assembler::AVX_512bit); + + // mask = (twoGamma2 / 2 - r0) >> 31; + __ evpsubd(xmm12, k0, gamma2, xmm8, false, Assembler::AVX_512bit); + __ evpsubd(xmm13, k0, gamma2, xmm9, false, Assembler::AVX_512bit); + __ evpsubd(xmm14, k0, gamma2, xmm10, false, Assembler::AVX_512bit); + __ evpsubd(xmm15, k0, gamma2, xmm11, false, Assembler::AVX_512bit); + + __ evpsrad(xmm12, k0, xmm12, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm13, k0, xmm13, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm14, k0, xmm14, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm15, k0, xmm15, 31, false, Assembler::AVX_512bit); + + // r0 -= (mask & twoGamma2); + __ evpandd(xmm16, k0, xmm12, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm17, k0, xmm13, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm18, k0, xmm14, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm19, k0, xmm15, twoGamma2, false, Assembler::AVX_512bit); + + __ evpsubd(xmm8, k0, xmm8, xmm16, false, Assembler::AVX_512bit); + __ evpsubd(xmm9, k0, xmm9, xmm17, false, Assembler::AVX_512bit); + __ evpsubd(xmm10, k0, xmm10, xmm18, false, Assembler::AVX_512bit); + __ evpsubd(xmm11, k0, xmm11, xmm19, false, Assembler::AVX_512bit); + // r0 in xmm8 + // quotient += (mask & 1); + __ evpandd(xmm16, k0, xmm12, one, false, Assembler::AVX_512bit); + __ evpandd(xmm17, k0, xmm13, one, false, Assembler::AVX_512bit); + __ evpandd(xmm18, k0, xmm14, one, false, Assembler::AVX_512bit); + __ evpandd(xmm19, k0, xmm15, one, false, Assembler::AVX_512bit); + + __ evpaddd(xmm4, k0, xmm4, xmm16, false, Assembler::AVX_512bit); + __ evpaddd(xmm5, k0, xmm5, xmm17, false, Assembler::AVX_512bit); + __ evpaddd(xmm6, k0, xmm6, xmm18, false, Assembler::AVX_512bit); + __ evpaddd(xmm7, k0, xmm7, xmm19, false, Assembler::AVX_512bit); + // quotient in xmm4 + // int r1 = rplus - r0 - (dilithium_q - 1); + __ evpsubd(xmm16, k0, xmm0, xmm8, false, Assembler::AVX_512bit); + __ evpsubd(xmm17, k0, xmm1, xmm9, false, Assembler::AVX_512bit); + __ evpsubd(xmm18, k0, xmm2, xmm10, false, Assembler::AVX_512bit); + __ evpsubd(xmm19, k0, xmm3, xmm11, false, Assembler::AVX_512bit); + + __ evpsubd(xmm16, k0, xmm16, xmm26, false, Assembler::AVX_512bit); + __ evpsubd(xmm17, k0, xmm17, xmm26, false, Assembler::AVX_512bit); + __ evpsubd(xmm18, k0, xmm18, xmm26, false, Assembler::AVX_512bit); + __ evpsubd(xmm19, k0, xmm19, xmm26, false, Assembler::AVX_512bit); + // r1 in xmm16 + // r1 = (r1 | (-r1)) >> 31; // 0 if rplus - r0 == (dilithium_q - 1), -1 otherwise + __ evpsubd(xmm20, k0, zero, xmm16, false, Assembler::AVX_512bit); + __ evpsubd(xmm21, k0, zero, xmm17, false, Assembler::AVX_512bit); + __ evpsubd(xmm22, k0, zero, xmm18, false, Assembler::AVX_512bit); + __ evpsubd(xmm23, k0, zero, xmm19, false, Assembler::AVX_512bit); + + __ evporq(xmm16, k0, xmm16, xmm20, false, Assembler::AVX_512bit); + __ evporq(xmm17, k0, xmm17, xmm21, false, Assembler::AVX_512bit); + __ evporq(xmm18, k0, xmm18, xmm22, false, Assembler::AVX_512bit); + __ evporq(xmm19, k0, xmm19, xmm23, false, Assembler::AVX_512bit); + + __ evpsubd(xmm12, k0, zero, one, false, Assembler::AVX_512bit); // -1 + + __ evpsrad(xmm0, k0, xmm16, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm1, k0, xmm17, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm2, k0, xmm18, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm3, k0, xmm19, 31, false, Assembler::AVX_512bit); + // r1 in xmm0 + // r0 += ~r1; + __ evpxorq(xmm20, k0, xmm0, xmm12, false, Assembler::AVX_512bit); + __ evpxorq(xmm21, k0, xmm1, xmm12, false, Assembler::AVX_512bit); + __ evpxorq(xmm22, k0, xmm2, xmm12, false, Assembler::AVX_512bit); + __ evpxorq(xmm23, k0, xmm3, xmm12, false, Assembler::AVX_512bit); + + __ evpaddd(xmm8, k0, xmm8, xmm20, false, Assembler::AVX_512bit); + __ evpaddd(xmm9, k0, xmm9, xmm21, false, Assembler::AVX_512bit); + __ evpaddd(xmm10, k0, xmm10, xmm22, false, Assembler::AVX_512bit); + __ evpaddd(xmm11, k0, xmm11, xmm23, false, Assembler::AVX_512bit); + // r0 in xmm8 + // r1 = r1 & quotient; + __ evpandd(xmm0, k0, xmm4, xmm0, false, Assembler::AVX_512bit); + __ evpandd(xmm1, k0, xmm5, xmm1, false, Assembler::AVX_512bit); + __ evpandd(xmm2, k0, xmm6, xmm2, false, Assembler::AVX_512bit); + __ evpandd(xmm3, k0, xmm7, xmm3, false, Assembler::AVX_512bit); + // r1 in xmm0 + // lowPart[m] = r0; + // highPart[m] = r1; + store4Xmms(highPart, 0, xmm0_3, _masm); + store4Xmms(lowPart, 0, xmm8_11, _masm); + + __ addptr(highPart, 4 * XMMBYTES); + __ addptr(lowPart, 4 * XMMBYTES); + __ subl(len, 4 * XMMBYTES); + __ jcc(Assembler::notEqual, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +void StubGenerator::generate_dilithium_stubs() { + // Generate Dilithium intrinsics code + if (UseDilithiumIntrinsics) { + StubRoutines::_dilithiumAlmostNtt = + generate_dilithiumAlmostNtt_avx512(this, _masm); + StubRoutines::_dilithiumAlmostInverseNtt = + generate_dilithiumAlmostInverseNtt_avx512(this, _masm); + StubRoutines::_dilithiumNttMult = + generate_dilithiumNttMult_avx512(this, _masm); + StubRoutines::_dilithiumMontMulByConstant = + generate_dilithiumMontMulByConstant_avx512(this, _masm); + StubRoutines::_dilithiumDecomposePoly = + generate_dilithiumDecomposePoly_avx512(this, _masm); + } +} diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,946 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "runtime/stubRoutines.hpp" +#include "macroAssembler_x86.hpp" +#include "stubGenerator_x86_64.hpp" + +#define __ _masm-> + +#define xmm(i) as_XMMRegister(i) + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif // PRODUCT + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +// Constants +// +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512Consts[] = { + 0xF301, 0xF301, 0xF301, 0xF301, // q^-1 mod montR + 0x0D01, 0x0D01, 0x0D01, 0x0D01, // q + 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, // Barrett multiplier + 0x0200, 0x0200, 0x0200, 0x0200, //(dim/2)^-1 mod q + 0x0549, 0x0549, 0x0549, 0x0549, // montR^2 mod q + 0x0F00, 0x0F00, 0x0F00, 0x0F00 // mask for kyber12to16 + }; + +static int qInvModROffset = 0; +static int qOffset = 8; +static int barretMultiplierOffset = 16; +static int dimHalfInverseOffset = 24; +static int montRSquareModqOffset = 32; +static int f00Offset = 40; + +static address kyberAvx512ConstsAddr(int offset) { + return ((address) kyberAvx512Consts) + offset; +} + +const Register scratch = r10; + +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512NttPerms[] = { +// 0 + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, +// 128 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +// 256 + 0x00, 0x01, 0x02, 0x03, 0x20, 0x21, 0x22, 0x23, + 0x08, 0x09, 0x0A, 0x0B, 0x28, 0x29, 0x2A, 0x2B, + 0x10, 0x11, 0x12, 0x13, 0x30, 0x31, 0x32, 0x33, + 0x18, 0x19, 0x1A, 0x1B, 0x38, 0x39, 0x3A, 0x3B, + 0x04, 0x05, 0x06, 0x07, 0x24, 0x25, 0x26, 0x27, + 0x0C, 0x0D, 0x0E, 0x0F, 0x2C, 0x2D, 0x2E, 0x2F, + 0x14, 0x15, 0x16, 0x17, 0x34, 0x35, 0x36, 0x37, + 0x1C, 0x1D, 0x1E, 0x1F, 0x3C, 0x3D, 0x3E, 0x3F, +// 384 + 0x00, 0x01, 0x20, 0x21, 0x04, 0x05, 0x24, 0x25, + 0x08, 0x09, 0x28, 0x29, 0x0C, 0x0D, 0x2C, 0x2D, + 0x10, 0x11, 0x30, 0x31, 0x14, 0x15, 0x34, 0x35, + 0x18, 0x19, 0x38, 0x39, 0x1C, 0x1D, 0x3C, 0x3D, + 0x02, 0x03, 0x22, 0x23, 0x06, 0x07, 0x26, 0x27, + 0x0A, 0x0B, 0x2A, 0x2B, 0x0E, 0x0F, 0x2E, 0x2F, + 0x12, 0x13, 0x32, 0x33, 0x16, 0x17, 0x36, 0x37, + 0x1A, 0x1B, 0x3A, 0x3B, 0x1E, 0x1F, 0x3E, 0x3F, +// 512 + 0x10, 0x11, 0x30, 0x31, 0x12, 0x13, 0x32, 0x33, + 0x14, 0x15, 0x34, 0x35, 0x16, 0x17, 0x36, 0x37, + 0x18, 0x19, 0x38, 0x39, 0x1A, 0x1B, 0x3A, 0x3B, + 0x1C, 0x1D, 0x3C, 0x3D, 0x1E, 0x1F, 0x3E, 0x3F, + 0x00, 0x01, 0x20, 0x21, 0x02, 0x03, 0x22, 0x23, + 0x04, 0x05, 0x24, 0x25, 0x06, 0x07, 0x26, 0x27, + 0x08, 0x09, 0x28, 0x29, 0x0A, 0x0B, 0x2A, 0x2B, + 0x0C, 0x0D, 0x2C, 0x2D, 0x0E, 0x0F, 0x2E, 0x2F + }; + +static address kyberAvx512NttPermsAddr() { + return (address) kyberAvx512NttPerms; +} + +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512InverseNttPerms[] = { +// 0 + 0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, + 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F, + 0x22, 0x23, 0x26, 0x27, 0x2A, 0x2B, 0x2E, 0x2F, + 0x32, 0x33, 0x36, 0x37, 0x3A, 0x3B, 0x3E, 0x3F, + 0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0C, 0x0D, + 0x10, 0x11, 0x14, 0x15, 0x18, 0x19, 0x1C, 0x1D, + 0x20, 0x21, 0x24, 0x25, 0x28, 0x29, 0x2C, 0x2D, + 0x30, 0x31, 0x34, 0x35, 0x38, 0x39, 0x3C, 0x3D, +// 128 + 0x00, 0x01, 0x20, 0x21, 0x04, 0x05, 0x24, 0x25, + 0x08, 0x09, 0x28, 0x29, 0x0C, 0x0D, 0x2C, 0x2D, + 0x10, 0x11, 0x30, 0x31, 0x14, 0x15, 0x34, 0x35, + 0x18, 0x19, 0x38, 0x39, 0x1C, 0x1D, 0x3C, 0x3D, + 0x02, 0x03, 0x22, 0x23, 0x06, 0x07, 0x26, 0x27, + 0x0A, 0x0B, 0x2A, 0x2B, 0x0E, 0x0F, 0x2E, 0x2F, + 0x12, 0x13, 0x32, 0x33, 0x16, 0x17, 0x36, 0x37, + 0x1A, 0x1B, 0x3A, 0x3B, 0x1E, 0x1F, 0x3E, 0x3F, +// 256 + 0x00, 0x01, 0x02, 0x03, 0x20, 0x21, 0x22, 0x23, + 0x08, 0x09, 0x0A, 0x0B, 0x28, 0x29, 0x2A, 0x2B, + 0x10, 0x11, 0x12, 0x13, 0x30, 0x31, 0x32, 0x33, + 0x18, 0x19, 0x1A, 0x1B, 0x38, 0x39, 0x3A, 0x3B, + 0x04, 0x05, 0x06, 0x07, 0x24, 0x25, 0x26, 0x27, + 0x0C, 0x0D, 0x0E, 0x0F, 0x2C, 0x2D, 0x2E, 0x2F, + 0x14, 0x15, 0x16, 0x17, 0x34, 0x35, 0x36, 0x37, + 0x1C, 0x1D, 0x1E, 0x1F, 0x3C, 0x3D, 0x3E, 0x3F, +// 384 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +// 512 + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F + }; + +static address kyberAvx512InverseNttPermsAddr() { + return (address) kyberAvx512InverseNttPerms; +} + +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512_nttMultPerms[] = { + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, + + 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, + 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F, + 0x21, 0x23, 0x25, 0x27, 0x29, 0x2B, 0x2D, 0x2F, + 0x31, 0x33, 0x35, 0x37, 0x39, 0x3B, 0x3D, 0x3F, + + 0x00, 0x20, 0x01, 0x21, 0x02, 0x22, 0x03, 0x23, + 0x04, 0x24, 0x05, 0x25, 0x06, 0x26, 0x07, 0x27, + 0x08, 0x28, 0x09, 0x29, 0x0A, 0x2A, 0x0B, 0x2B, + 0x0C, 0x2C, 0x0D, 0x2D, 0x0E, 0x2E, 0x0F, 0x2F, + + 0x10, 0x30, 0x11, 0x31, 0x12, 0x32, 0x13, 0x33, + 0x14, 0x34, 0x15, 0x35, 0x16, 0x36, 0x17, 0x37, + 0x18, 0x38, 0x19, 0x39, 0x1A, 0x3A, 0x1B, 0x3B, + 0x1C, 0x3C, 0x1D, 0x3D, 0x1E, 0x3E, 0x1F, 0x3F + }; + +static address kyberAvx512_nttMultPermsAddr() { + return (address) kyberAvx512_nttMultPerms; +} + + ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512_12To16Perms[] = { +// 0 + 0x00, 0x03, 0x06, 0x09, 0x0C, 0x0F, 0x12, 0x15, + 0x18, 0x1B, 0x1E, 0x21, 0x24, 0x27, 0x2A, 0x2D, + 0x30, 0x33, 0x36, 0x39, 0x3C, 0x3F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x07, 0x0A, 0x0D, 0x10, 0x13, 0x16, + 0x19, 0x1C, 0x1F, 0x22, 0x25, 0x28, 0x2B, 0x2E, + 0x31, 0x34, 0x37, 0x3A, 0x3D, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 128 + 0x02, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x17, + 0x1A, 0x1D, 0x20, 0x23, 0x26, 0x29, 0x2C, 0x2F, + 0x32, 0x35, 0x38, 0x3B, 0x3E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x22, 0x25, + 0x28, 0x2B, 0x2E, 0x31, 0x34, 0x37, 0x3A, 0x3D, +// 256 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x20, 0x23, 0x26, + 0x29, 0x2C, 0x2F, 0x32, 0x35, 0x38, 0x3B, 0x3E, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x21, 0x24, 0x27, + 0x2A, 0x2D, 0x30, 0x33, 0x36, 0x39, 0x3C, 0x3F, +// 384 + 0x00, 0x20, 0x01, 0x21, 0x02, 0x22, 0x03, 0x23, + 0x04, 0x24, 0x05, 0x25, 0x06, 0x26, 0x07, 0x27, + 0x08, 0x28, 0x09, 0x29, 0x0A, 0x2A, 0x0B, 0x2B, + 0x0C, 0x2C, 0x0D, 0x2D, 0x0E, 0x2E, 0x0F, 0x2F, + 0x10, 0x30, 0x11, 0x31, 0x12, 0x32, 0x13, 0x33, + 0x14, 0x34, 0x15, 0x35, 0x16, 0x36, 0x17, 0x37, + 0x18, 0x38, 0x19, 0x39, 0x1A, 0x3A, 0x1B, 0x3B, + 0x1C, 0x3C, 0x1D, 0x3D, 0x1E, 0x3E, 0x1F, 0x3F + }; + +static address kyberAvx512_12To16PermsAddr() { + return (address) kyberAvx512_12To16Perms; +} + +static void load4regs(int destRegs[], Register address, int offset, + MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evmovdquw(xmm(destRegs[i]), Address(address, offset + i * 64), + Assembler::AVX_512bit); + } +} + +// For z = montmul(a,b), z will be between -q and q and congruent +// to a * b * R^-1 mod q, where R > 2 * q, R is a power of 2, +// -R/2 * q <= a * b < R/2 * q. +// (See e.g. Algorithm 3 in https://eprint.iacr.org/2018/039.pdf) +// For the Java code, we use R = 2^20 and for the intrinsic, R = 2^16. +// In our computations, b is always c * R mod q, so the montmul() really +// computes a * c mod q. In the Java code, we use 32-bit numbers for the +// computations, and we use R = 2^20 because that way the a * b numbers +// that occur during all computations stay in the required range. +// For the intrinsics, we use R = 2^16, because this way we can do twice +// as much work in parallel, the only drawback is that we should do some Barrett +// reductions in kyberInverseNtt so that the numbers stay in the required range. +static void montmul(int outputRegs[], int inputRegs1[], int inputRegs2[], + int scratchRegs1[], int scratchRegs2[], MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evpmullw(xmm(scratchRegs1[i]), k0, xmm(inputRegs1[i]), + xmm(inputRegs2[i]), false, Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpmulhw(xmm(scratchRegs2[i]), k0, xmm(inputRegs1[i]), + xmm(inputRegs2[i]), false, Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpmullw(xmm(scratchRegs1[i]), k0, xmm(scratchRegs1[i]), + xmm31, false, Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpmulhw(xmm(scratchRegs1[i]), k0, xmm(scratchRegs1[i]), + xmm30, false, Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpsubw(xmm(outputRegs[i]), k0, xmm(scratchRegs2[i]), + xmm(scratchRegs1[i]), false, Assembler::AVX_512bit); + } +} + +static void sub_add(int subResult[], int addResult[], int input1[], int input2[], + MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evpsubw(xmm(subResult[i]), k0, xmm(input1[i]), xmm(input2[i]), + false, Assembler::AVX_512bit); + __ evpaddw(xmm(addResult[i]), k0, xmm(input1[i]), xmm(input2[i]), + false, Assembler::AVX_512bit); + } +} + +// result2 also acts as input1 +// result1 also acts as perm1 +static void permute(int result1[], int result2[], int input2[], int perm2, + MacroAssembler *_masm) { + + for (int i = 1; i < 4; i++) { + __ evmovdquw(xmm(result1[i]), xmm(result1[0]), Assembler::AVX_512bit); + } + + for (int i = 0; i < 4; i++) { + __ evpermi2w(xmm(result1[i]), xmm(result2[i]), xmm(input2[i]), + Assembler::AVX_512bit); + __ evpermt2w(xmm(result2[i]), xmm(perm2), xmm(input2[i]), + Assembler::AVX_512bit); + } +} + +static void store4regs(Register address, int offset, int sourceRegs[], + MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evmovdquw(Address(address, offset + i * 64), xmm(sourceRegs[i]), + Assembler::AVX_512bit); + } +} + +// In all 3 invocations of this function we use the same registers: +// xmm0-xmm7 for the input and the result, +// xmm8-xmm15 as scratch registers and +// xmm16-xmm17 for the constants, +// so we don't pass register arguments. +static void barrettReduce(MacroAssembler *_masm) { + for (int i = 0; i < 8; i++) { + __ evpmulhw(xmm(i + 8), k0, xmm(i), xmm16, false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpsraw(xmm(i + 8), k0, xmm(i + 8), 10, false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpmullw(xmm(i + 8), k0, xmm(i + 8), xmm17, false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpsubw(xmm(i), k0, xmm(i), xmm(i + 8), false, Assembler::AVX_512bit); + } +} + +static int xmm0_3[] = {0, 1, 2, 3}; +static int xmm0145[] = {0, 1, 4, 5}; +static int xmm0246[] = {0, 2, 4, 6}; +static int xmm0829[] = {0, 8, 2, 9}; +static int xmm1001[] = {1, 0, 0, 1}; +static int xmm1357[] = {1, 3, 5, 7}; +static int xmm2367[] = {2, 3, 6, 7}; +static int xmm2_0_10_8[] = {2, 0, 10, 8}; +static int xmm3223[] = {3, 2, 2, 3}; +static int xmm4_7[] = {4, 5, 6, 7}; +static int xmm5454[] = {5, 4, 5, 4}; +static int xmm7676[] = {7, 6, 7, 6}; +static int xmm8_11[] = {8, 9, 10, 11}; +static int xmm12_15[] = {12, 13, 14, 15}; +static int xmm16_19[] = {16, 17, 18, 19}; +static int xmm20_23[] = {20, 21, 22, 23}; +static int xmm23_23[] = {23, 23, 23, 23}; +static int xmm24_27[] = {24, 25, 26, 27}; +static int xmm26_29[] = {26, 27, 28, 29}; +static int xmm28_31[] = {28, 29, 30, 31}; +static int xmm29_29[] = {29, 29, 29, 29}; + +// Kyber NTT function. +// +// coeffs (short[256]) = c_rarg0 +// ntt_zetas (short[256]) = c_rarg1 +address generate_kyberNtt_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "kyberNtt"); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register perms = r11; + + __ lea(perms, ExternalAddress(kyberAvx512NttPermsAddr())); + + load4regs(xmm4_7, coeffs, 256, _masm); + load4regs(xmm20_23, zetas, 0, _masm); + + __ vpbroadcastq(xmm30, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + __ vpbroadcastq(xmm31, + ExternalAddress(kyberAvx512ConstsAddr(qInvModROffset)), + Assembler::AVX_512bit, scratch); // q^-1 mod montR + + load4regs(xmm0_3, coeffs, 0, _masm); + + // Each level represents one iteration of the outer for loop of the Java version. + // level 0 + montmul(xmm8_11, xmm4_7, xmm20_23, xmm8_11, xmm4_7, _masm); + load4regs(xmm20_23, zetas, 256, _masm); + sub_add(xmm4_7, xmm0_3, xmm0_3, xmm8_11, _masm); + + //level 1 + montmul(xmm12_15, xmm2367, xmm20_23, xmm12_15, xmm8_11, _masm); + load4regs(xmm20_23, zetas, 512, _masm); + sub_add(xmm2367, xmm0145, xmm0145, xmm12_15, _masm); + + // level 2 + montmul(xmm8_11, xmm1357, xmm20_23, xmm12_15, xmm8_11, _masm); + __ evmovdquw(xmm12, Address(perms, 0), Assembler::AVX_512bit); + __ evmovdquw(xmm16, Address(perms, 64), Assembler::AVX_512bit); + load4regs(xmm20_23, zetas, 768, _masm); + sub_add(xmm1357, xmm0246, xmm0246, xmm8_11, _masm); + + //level 3 + permute(xmm12_15, xmm0246, xmm1357, 16, _masm); + montmul(xmm8_11, xmm12_15, xmm20_23, xmm16_19, xmm8_11, _masm); + __ evmovdquw(xmm16, Address(perms, 128), Assembler::AVX_512bit); + __ evmovdquw(xmm24, Address(perms, 192), Assembler::AVX_512bit); + load4regs(xmm20_23, zetas, 1024, _masm); + sub_add(xmm1357, xmm0246, xmm0246, xmm8_11, _masm); + + // level 4 + permute(xmm16_19, xmm0246, xmm1357, 24, _masm); + montmul(xmm8_11, xmm0246, xmm20_23, xmm24_27, xmm8_11, _masm); + __ evmovdquw(xmm1, Address(perms, 256), Assembler::AVX_512bit); + __ evmovdquw(xmm24, Address(perms, 320), Assembler::AVX_512bit); + load4regs(xmm20_23, zetas, 1280, _masm); + sub_add(xmm12_15, xmm0246, xmm16_19, xmm8_11, _masm); + + // level 5 + permute(xmm1357, xmm0246, xmm12_15, 24, _masm); + montmul(xmm16_19, xmm0246, xmm20_23, xmm16_19, xmm8_11, _masm); + + __ evmovdquw(xmm12, Address(perms, 384), Assembler::AVX_512bit); + __ evmovdquw(xmm8, Address(perms, 448), Assembler::AVX_512bit); + + load4regs(xmm20_23, zetas, 1536, _masm); + sub_add(xmm24_27, xmm0246, xmm1357, xmm16_19, _masm); + + // level 6 + permute(xmm12_15, xmm0246, xmm24_27, 8, _masm); + + __ evmovdquw(xmm1, Address(perms, 512), Assembler::AVX_512bit); + __ evmovdquw(xmm24, Address(perms, 576), Assembler::AVX_512bit); + + montmul(xmm16_19, xmm0246, xmm20_23, xmm16_19, xmm8_11, _masm); + sub_add(xmm20_23, xmm0246, xmm12_15, xmm16_19, _masm); + + permute(xmm1357, xmm0246, xmm20_23, 24, _masm); + + store4regs(coeffs, 0, xmm0_3, _masm); + store4regs(coeffs, 256, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Kyber Inverse NTT function +// +// coeffs (short[256]) = c_rarg0 +// ntt_zetas (short[256]) = c_rarg1 +address generate_kyberInverseNtt_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "kyberInverseNtt"); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register perms = r11; + + __ lea(perms, ExternalAddress(kyberAvx512InverseNttPermsAddr())); + __ evmovdquw(xmm12, Address(perms, 0), Assembler::AVX_512bit); + __ evmovdquw(xmm16, Address(perms, 64), Assembler::AVX_512bit); + + __ vpbroadcastq(xmm31, + ExternalAddress(kyberAvx512ConstsAddr(qInvModROffset)), + Assembler::AVX_512bit, scratch); // q^-1 mod montR + __ vpbroadcastq(xmm30, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + __ vpbroadcastq(xmm29, + ExternalAddress(kyberAvx512ConstsAddr(dimHalfInverseOffset)), + Assembler::AVX_512bit, scratch); // (dim/2)^-1 mod q + + load4regs(xmm0_3, coeffs, 0, _masm); + load4regs(xmm4_7, coeffs, 256, _masm); + + // Each level represents one iteration of the outer for loop of the Java version. + // level 0 + load4regs(xmm8_11, zetas, 0, _masm); + permute(xmm12_15, xmm0246, xmm1357, 16, _masm); + + __ evmovdquw(xmm1, Address(perms, 128), Assembler::AVX_512bit); + __ evmovdquw(xmm20, Address(perms, 192), Assembler::AVX_512bit); + + sub_add(xmm16_19, xmm0246, xmm0246, xmm12_15, _masm); + montmul(xmm12_15, xmm16_19, xmm8_11, xmm12_15, xmm8_11, _masm); + + // level 1 + load4regs(xmm8_11, zetas, 256, _masm); + permute(xmm1357, xmm0246, xmm12_15, 20, _masm); + sub_add(xmm16_19, xmm0246, xmm1357, xmm0246, _masm); + + __ evmovdquw(xmm1, Address(perms, 256), Assembler::AVX_512bit); + __ evmovdquw(xmm20, Address(perms, 320), Assembler::AVX_512bit); + + montmul(xmm12_15, xmm16_19, xmm8_11, xmm12_15, xmm8_11, _masm); + + // level2 + load4regs(xmm8_11, zetas, 512, _masm); + permute(xmm1357, xmm0246, xmm12_15, 20, _masm); + sub_add(xmm16_19, xmm0246, xmm1357, xmm0246,_masm); + + __ evmovdquw(xmm1, Address(perms, 384), Assembler::AVX_512bit); + __ evmovdquw(xmm20, Address(perms, 448), Assembler::AVX_512bit); + + montmul(xmm12_15, xmm16_19, xmm8_11, xmm12_15, xmm8_11, _masm); + + __ vpbroadcastq(xmm16, + ExternalAddress(kyberAvx512ConstsAddr(barretMultiplierOffset)), + Assembler::AVX_512bit, scratch); // Barrett multiplier + __ vpbroadcastq(xmm17, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + + permute(xmm1357, xmm0246, xmm12_15, 20, _masm); + barrettReduce(_masm); + +// level 3 + load4regs(xmm8_11, zetas, 768, _masm); + sub_add(xmm16_19, xmm0246, xmm1357, xmm0246, _masm); + + __ evmovdquw(xmm1, Address(perms, 512), Assembler::AVX_512bit); + __ evmovdquw(xmm20, Address(perms, 576), Assembler::AVX_512bit); + + montmul(xmm12_15, xmm16_19, xmm8_11, xmm12_15, xmm8_11, _masm); + permute(xmm1357, xmm0246, xmm12_15, 20, _masm); + + // level 4 + load4regs(xmm8_11, zetas, 1024, _masm); + + __ vpbroadcastq(xmm16, + ExternalAddress(kyberAvx512ConstsAddr(barretMultiplierOffset)), + Assembler::AVX_512bit, scratch); // Barrett multiplier + __ vpbroadcastq(xmm17, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + + sub_add(xmm12_15, xmm0246, xmm0246, xmm1357, _masm); + montmul(xmm1357, xmm12_15, xmm8_11, xmm1357, xmm8_11, _masm); + barrettReduce(_masm); + + // level 5 + load4regs(xmm8_11, zetas, 1280, _masm); + sub_add(xmm12_15, xmm0145, xmm0145, xmm2367, _masm); + montmul(xmm2367, xmm12_15, xmm8_11, xmm2367, xmm8_11, _masm); + + // level 6 + load4regs(xmm8_11, zetas, 1536, _masm); + sub_add(xmm12_15, xmm0_3, xmm0_3, xmm4_7, _masm); + montmul(xmm4_7, xmm12_15, xmm8_11, xmm4_7, xmm8_11, _masm); + + montmul(xmm8_11, xmm29_29, xmm0_3, xmm8_11, xmm0_3, _masm); + montmul(xmm12_15, xmm29_29, xmm4_7, xmm12_15, xmm4_7, _masm); + + store4regs(coeffs, 0, xmm8_11, _masm); + store4regs(coeffs, 256, xmm12_15, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Kyber multiply polynomials in the NTT domain. +// +// result (short[256]) = c_rarg0 +// ntta (short[256]) = c_rarg1 +// nttb (short[256]) = c_rarg2 +// zetas (short[128]) = c_rarg3 +address generate_kyberNttMult_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "kyberNttMult"); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register ntta = c_rarg1; + const Register nttb = c_rarg2; + const Register zetas = c_rarg3; + + const Register perms = r11; + const Register loopCnt = r12; + + __ push(r12); + __ movl(loopCnt, 2); + + Label Loop; + + __ lea(perms, ExternalAddress(kyberAvx512_nttMultPermsAddr())); + + + load4regs(xmm26_29, perms, 0, _masm); + __ vpbroadcastq(xmm31, + ExternalAddress(kyberAvx512ConstsAddr(qInvModROffset)), + Assembler::AVX_512bit, scratch); // q^-1 mod montR + __ vpbroadcastq(xmm30, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + __ vpbroadcastq(xmm23, + ExternalAddress(kyberAvx512ConstsAddr(montRSquareModqOffset)), + Assembler::AVX_512bit, scratch); // montR^2 mod q + + __ BIND(Loop); + + __ evmovdquw(xmm1, Address(ntta, 0), Assembler::AVX_512bit); + __ evmovdquw(xmm8, Address(ntta, 64), Assembler::AVX_512bit); + __ evmovdquw(xmm3, Address(ntta, 128), Assembler::AVX_512bit); + __ evmovdquw(xmm9, Address(ntta, 192), Assembler::AVX_512bit); + + __ evmovdquw(xmm5, Address(nttb, 0), Assembler::AVX_512bit); + __ evmovdquw(xmm10, Address(nttb, 64), Assembler::AVX_512bit); + __ evmovdquw(xmm7, Address(nttb, 128), Assembler::AVX_512bit); + __ evmovdquw(xmm11, Address(nttb, 192), Assembler::AVX_512bit); + + __ evmovdquw(xmm0, xmm26, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm26, Assembler::AVX_512bit); + __ evmovdquw(xmm4, xmm26, Assembler::AVX_512bit); + __ evmovdquw(xmm6, xmm26, Assembler::AVX_512bit); + + __ evpermi2w(xmm0, xmm1, xmm8, Assembler::AVX_512bit); + __ evpermt2w(xmm1, xmm27, xmm8, Assembler::AVX_512bit); + __ evpermi2w(xmm2, xmm3, xmm9, Assembler::AVX_512bit); + __ evpermt2w(xmm3, xmm27, xmm9, Assembler::AVX_512bit); + + __ evpermi2w(xmm4, xmm5, xmm10, Assembler::AVX_512bit); + __ evpermt2w(xmm5, xmm27, xmm10, Assembler::AVX_512bit); + __ evpermi2w(xmm6, xmm7, xmm11, Assembler::AVX_512bit); + __ evpermt2w(xmm7, xmm27, xmm11, Assembler::AVX_512bit); + + __ evmovdquw(xmm24, Address(zetas, 0), Assembler::AVX_512bit); + __ evmovdquw(xmm25, Address(zetas, 64), Assembler::AVX_512bit); + + montmul(xmm16_19, xmm1001, xmm5454, xmm16_19, xmm12_15, _masm); + + montmul(xmm0145, xmm3223, xmm7676, xmm0145, xmm12_15, _masm); + + __ evpmullw(xmm2, k0, xmm16, xmm24, false, Assembler::AVX_512bit); + __ evpmullw(xmm3, k0, xmm0, xmm25, false, Assembler::AVX_512bit); + __ evpmulhw(xmm12, k0, xmm16, xmm24, false, Assembler::AVX_512bit); + __ evpmulhw(xmm13, k0, xmm0, xmm25, false, Assembler::AVX_512bit); + + __ evpmullw(xmm2, k0, xmm2, xmm31, false, Assembler::AVX_512bit); + __ evpmullw(xmm3, k0, xmm3, xmm31, false, Assembler::AVX_512bit); + __ evpmulhw(xmm2, k0, xmm30, xmm2, false, Assembler::AVX_512bit); + __ evpmulhw(xmm3, k0, xmm30, xmm3, false, Assembler::AVX_512bit); + + __ evpsubw(xmm2, k0, xmm12, xmm2, false, Assembler::AVX_512bit); + __ evpsubw(xmm3, k0, xmm13, xmm3, false, Assembler::AVX_512bit); + + __ evpaddw(xmm0, k0, xmm2, xmm17, false, Assembler::AVX_512bit); + __ evpaddw(xmm8, k0, xmm3, xmm1, false, Assembler::AVX_512bit); + __ evpaddw(xmm2, k0, xmm18, xmm19, false, Assembler::AVX_512bit); + __ evpaddw(xmm9, k0, xmm4, xmm5, false, Assembler::AVX_512bit); + + montmul(xmm1357, xmm0829, xmm23_23, xmm1357, xmm0829, _masm); + + __ evmovdquw(xmm0, xmm28, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm28, Assembler::AVX_512bit); + __ evpermi2w(xmm0, xmm1, xmm5, Assembler::AVX_512bit); + __ evpermt2w(xmm1, xmm29, xmm5, Assembler::AVX_512bit); + __ evpermi2w(xmm2, xmm3, xmm7, Assembler::AVX_512bit); + __ evpermt2w(xmm3, xmm29, xmm7, Assembler::AVX_512bit); + + store4regs(result, 0, xmm0_3, _masm); + + __ addptr(ntta, 256); + __ addptr(nttb, 256); + __ addptr(result, 256); + __ addptr(zetas, 128); + __ subl(loopCnt, 1); + __ jcc(Assembler::greater, Loop); + + __ pop(r12); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Kyber add 2 polynomials. +// +// result (short[256]) = c_rarg0 +// a (short[256]) = c_rarg1 +// b (short[256]) = c_rarg2 +address generate_kyberAddPoly_2_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "kyberAddPoly_2"); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register a = c_rarg1; + const Register b = c_rarg2; + + __ vpbroadcastq(xmm31, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + + for (int i = 0; i < 8; i++) { + __ evmovdquw(xmm(i), Address(a, 64 * i), Assembler::AVX_512bit); + __ evmovdquw(xmm(i + 8), Address(b, 64 * i), Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpaddw(xmm(i), k0, xmm(i), xmm(i + 8), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpaddw(xmm(i), k0, xmm(i), xmm31, false, Assembler::AVX_512bit); + } + + store4regs(result, 0, xmm0_3, _masm); + store4regs(result, 256, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Kyber add 3 polynomials. +// +// result (short[256]) = c_rarg0 +// a (short[256]) = c_rarg1 +// b (short[256]) = c_rarg2 +// c (short[256]) = c_rarg3 +address generate_kyberAddPoly_3_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "kyberAddPoly_3"); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register a = c_rarg1; + const Register b = c_rarg2; + const Register c = c_rarg3; + + __ vpbroadcastq(xmm31, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + + for (int i = 0; i < 8; i++) { + __ evmovdquw(xmm(i), Address(a, 64 * i), Assembler::AVX_512bit); + __ evmovdquw(xmm(i + 8), Address(b, 64 * i), Assembler::AVX_512bit); + __ evmovdquw(xmm(i + 16), Address(c, 64 * i), Assembler::AVX_512bit); + } + + __ evpaddw(xmm31, k0, xmm31, xmm31, false, Assembler::AVX_512bit); + + for (int i = 0; i < 8; i++) { + __ evpaddw(xmm(i), k0, xmm(i), xmm(i + 8), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpaddw(xmm(i), k0, xmm(i), xmm(i + 16), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpaddw(xmm(i), k0, xmm(i), xmm31, false, Assembler::AVX_512bit); + } + + store4regs(result, 0, xmm0_3, _masm); + store4regs(result, 256, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Kyber parse XOF output to polynomial coefficient candidates. +// +// condensed (byte[168]) = c_rarg0 +// condensedOffs (int) = c_rarg1 +// parsed (short[112]) = c_rarg2 +// parsedLength (int) = c_rarg3 +address generate_kyber12To16_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "kyber12To16"); + address start = __ pc(); + __ enter(); + + const Register condensed = c_rarg0; + const Register condensedOffs = c_rarg1; + const Register parsed = c_rarg2; + const Register parsedLength = c_rarg3; + + const Register perms = r11; + + Label Loop; + + __ addptr(condensed, condensedOffs); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16PermsAddr())); + + load4regs(xmm24_27, perms, 0, _masm); + load4regs(xmm28_31, perms, 256, _masm); + __ vpbroadcastq(xmm23, + ExternalAddress(kyberAvx512ConstsAddr(f00Offset)), + Assembler::AVX_512bit, scratch); // 0xF00 + + __ BIND(Loop); + __ evmovdqub(xmm0, Address(condensed, 0),Assembler::AVX_256bit); + __ evmovdqub(xmm1, Address(condensed, 32),Assembler::AVX_256bit); + __ evmovdqub(xmm2, Address(condensed, 64),Assembler::AVX_256bit); + __ evmovdqub(xmm8, Address(condensed, 96),Assembler::AVX_256bit); + __ evmovdqub(xmm9, Address(condensed, 128),Assembler::AVX_256bit); + __ evmovdqub(xmm10, Address(condensed, 160),Assembler::AVX_256bit); + __ vpmovzxbw(xmm0, xmm0, Assembler::AVX_512bit); + __ vpmovzxbw(xmm1, xmm1, Assembler::AVX_512bit); + __ vpmovzxbw(xmm2, xmm2, Assembler::AVX_512bit); + __ vpmovzxbw(xmm8, xmm8, Assembler::AVX_512bit); + __ vpmovzxbw(xmm9, xmm9, Assembler::AVX_512bit); + __ vpmovzxbw(xmm10, xmm10, Assembler::AVX_512bit); + __ evmovdquw(xmm3, xmm24, Assembler::AVX_512bit); + __ evmovdquw(xmm4, xmm25, Assembler::AVX_512bit); + __ evmovdquw(xmm5, xmm26, Assembler::AVX_512bit); + __ evmovdquw(xmm11, xmm24, Assembler::AVX_512bit); + __ evmovdquw(xmm12, xmm25, Assembler::AVX_512bit); + __ evmovdquw(xmm13, xmm26, Assembler::AVX_512bit); + __ evpermi2w(xmm3, xmm0, xmm1, Assembler::AVX_512bit); + __ evpermi2w(xmm4, xmm0, xmm1, Assembler::AVX_512bit); + __ evpermi2w(xmm5, xmm0, xmm1, Assembler::AVX_512bit); + __ evpermi2w(xmm11, xmm8, xmm9, Assembler::AVX_512bit); + __ evpermi2w(xmm12, xmm8, xmm9, Assembler::AVX_512bit); + __ evpermi2w(xmm13, xmm8, xmm9, Assembler::AVX_512bit); + __ evpermt2w(xmm3, xmm27, xmm2, Assembler::AVX_512bit); + __ evpermt2w(xmm4, xmm28, xmm2, Assembler::AVX_512bit); + __ evpermt2w(xmm5, xmm29, xmm2, Assembler::AVX_512bit); + __ evpermt2w(xmm11, xmm27, xmm10, Assembler::AVX_512bit); + __ evpermt2w(xmm12, xmm28, xmm10, Assembler::AVX_512bit); + __ evpermt2w(xmm13, xmm29, xmm10, Assembler::AVX_512bit); + + __ evpsraw(xmm2, k0, xmm4, 4, false, Assembler::AVX_512bit); + __ evpsllw(xmm0, k0, xmm4, 8, false, Assembler::AVX_512bit); + __ evpsllw(xmm1, k0, xmm5, 4, false, Assembler::AVX_512bit); + __ evpsllw(xmm8, k0, xmm12, 8, false, Assembler::AVX_512bit); + __ evpsraw(xmm10, k0, xmm12, 4, false, Assembler::AVX_512bit); + __ evpsllw(xmm9, k0, xmm13, 4, false, Assembler::AVX_512bit); + __ evpandq(xmm0, k0, xmm0, xmm23, false, Assembler::AVX_512bit); + __ evpandq(xmm8, k0, xmm8, xmm23, false, Assembler::AVX_512bit); + __ evpaddw(xmm1, k0, xmm1, xmm2, false, Assembler::AVX_512bit); + __ evpaddw(xmm0, k0, xmm0, xmm3, false, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm30, Assembler::AVX_512bit); + __ evpaddw(xmm9, k0, xmm9, xmm10, false, Assembler::AVX_512bit); + __ evpaddw(xmm8, k0, xmm8, xmm11, false, Assembler::AVX_512bit); + __ evmovdquw(xmm10, xmm30, Assembler::AVX_512bit); + __ evpermi2w(xmm2, xmm0, xmm1, Assembler::AVX_512bit); + __ evpermt2w(xmm0, xmm31, xmm1, Assembler::AVX_512bit); + __ evpermi2w(xmm10, xmm8, xmm9, Assembler::AVX_512bit); + __ evpermt2w(xmm8, xmm31, xmm9, Assembler::AVX_512bit); + + store4regs(parsed, 0, xmm2_0_10_8, _masm); + + __ addptr(condensed, 192); + __ addptr(parsed, 256); + __ subl(parsedLength, 128); + __ jcc(Assembler::greater, Loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + + +// Kyber barrett reduce function. +// +// coeffs (short[256]) = c_rarg0 +address generate_kyberBarrettReduce_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "kyberBarrettReduce"); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + + __ vpbroadcastq(xmm16, + ExternalAddress(kyberAvx512ConstsAddr(barretMultiplierOffset)), + Assembler::AVX_512bit, scratch); // Barrett multiplier + __ vpbroadcastq(xmm17, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + + load4regs(xmm0_3, coeffs, 0, _masm); + load4regs(xmm4_7, coeffs, 256, _masm); + + barrettReduce(_masm); + + store4regs(coeffs, 0, xmm0_3, _masm); + store4regs(coeffs, 256, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +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); + } + } +} diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,500 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "runtime/stubRoutines.hpp" +#include "macroAssembler_x86.hpp" +#include "stubGenerator_x86_64.hpp" + +#define __ _masm-> + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif // PRODUCT + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +#define xmm(i) as_XMMRegister(i) + +// Constants +ATTRIBUTE_ALIGNED(64) static const uint64_t round_consts_arr[24] = { + 0x0000000000000001L, 0x0000000000008082L, 0x800000000000808AL, + 0x8000000080008000L, 0x000000000000808BL, 0x0000000080000001L, + 0x8000000080008081L, 0x8000000000008009L, 0x000000000000008AL, + 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000AL, + 0x000000008000808BL, 0x800000000000008BL, 0x8000000000008089L, + 0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L, + 0x000000000000800AL, 0x800000008000000AL, 0x8000000080008081L, + 0x8000000000008080L, 0x0000000080000001L, 0x8000000080008008L + }; + +ATTRIBUTE_ALIGNED(64) static const uint64_t permsAndRots[] = { + // permutation in combined rho and pi + 9, 2, 11, 0, 1, 2, 3, 4, // step 1 and 3 + 8, 1, 9, 2, 11, 4, 12, 0, // step 2 + 9, 2, 10, 3, 11, 4, 12, 0, // step 4 + 8, 9, 2, 3, 4, 5, 6, 7, // step 5 + 0, 8, 9, 10, 15, 0, 0, 0, // step 6 + 4, 5, 8, 9, 6, 7, 10, 11, // step 7 and 8 + 0, 1, 2, 3, 13, 0, 0, 0, // step 9 + 2, 3, 0, 1, 11, 0, 0, 0, // step 10 + 4, 5, 6, 7, 14, 0, 0, 0, // step 11 + 14, 15, 12, 13, 4, 0, 0, 0, // step 12 + // size of rotations (after step 5) + 1, 6, 62, 55, 28, 20, 27, 36, + 3, 45, 10, 15, 25, 8, 39, 41, + 44, 43, 21, 18, 2, 61, 56, 14, + // rotation of row elements + 12, 8, 9, 10, 11, 5, 6, 7, + 9, 10, 11, 12, 8, 5, 6, 7 +}; + +static address round_constsAddr() { + return (address) round_consts_arr; +} + +static address permsAndRotsAddr() { + return (address) permsAndRots; +} + +// Arguments: +// +// Inputs: +// c_rarg0 - byte[] source+offset +// c_rarg1 - long[] SHA3.state +// c_rarg2 - int block_size +// c_rarg3 - int offset +// c_rarg4 - int limit +// +static address generate_sha3_implCompress(bool multiBlock, const char *name, + StubGenerator *stubgen, + MacroAssembler *_masm) { + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", name); + address start = __ pc(); + + const Register buf = c_rarg0; + const Register state = c_rarg1; + const Register block_size = c_rarg2; + const Register ofs = c_rarg3; +#ifndef _WIN64 + const Register limit = c_rarg4; +#else + const Address limit_mem(rbp, 6 * wordSize); + const Register limit = r12; +#endif + + const Register permsAndRots = r10; + const Register round_consts = r11; + const Register constant2use = r13; + const Register roundsLeft = r14; + + Label sha3_loop; + Label rounds24_loop, block104, block136, block144, block168; + + __ enter(); + + __ push(r12); + __ push(r13); + __ push(r14); + +#ifdef _WIN64 + // on win64, fill limit from stack position + __ movptr(limit, limit_mem); +#endif + + __ lea(permsAndRots, ExternalAddress(permsAndRotsAddr())); + __ lea(round_consts, ExternalAddress(round_constsAddr())); + + // set up the masks + __ movl(rax, 0x1F); + __ kmovwl(k5, rax); + __ kshiftrwl(k4, k5, 1); + __ kshiftrwl(k3, k5, 2); + __ kshiftrwl(k2, k5, 3); + __ kshiftrwl(k1, k5, 4); + + // load the state + for (int i = 0; i < 5; i++) { + __ evmovdquq(xmm(i), k5, Address(state, i * 40), false, Assembler::AVX_512bit); + } + + // load the permutation and rotation constants + for (int i = 0; i < 15; i++) { + __ evmovdquq(xmm(i + 17), Address(permsAndRots, i * 64), Assembler::AVX_512bit); + } + + __ align(OptoLoopAlignment); + __ BIND(sha3_loop); + + // there will be 24 keccak rounds + __ movl(roundsLeft, 24); + // load round_constants base + __ movptr(constant2use, round_consts); + + // load input: 72, 104, 136, 144 or 168 bytes + // i.e. 5+4, 2*5+3, 3*5+2, 3*5+3 or 4*5+1 longs + __ evpxorq(xmm0, k5, xmm0, Address(buf, 0), true, Assembler::AVX_512bit); + + // if(blockSize == 72) SHA3-512 + __ cmpl(block_size, 72); + __ jcc(Assembler::notEqual, block104); + __ evpxorq(xmm1, k4, xmm1, Address(buf, 40), true, Assembler::AVX_512bit); + __ jmp(rounds24_loop); + + // if(blockSize == 104) SHA3-384 + __ BIND(block104); + __ cmpl(block_size, 104); + __ jcc(Assembler::notEqual, block136); + __ evpxorq(xmm1, k5, xmm1, Address(buf, 40), true, Assembler::AVX_512bit); + __ evpxorq(xmm2, k3, xmm2, Address(buf, 80), true, Assembler::AVX_512bit); + __ jmp(rounds24_loop); + + // if(blockSize == 136) SHA3-256 and SHAKE256 + __ BIND(block136); + __ cmpl(block_size, 136); + __ jcc(Assembler::notEqual, block144); + __ evpxorq(xmm1, k5, xmm1, Address(buf, 40), true, Assembler::AVX_512bit); + __ evpxorq(xmm2, k5, xmm2, Address(buf, 80), true, Assembler::AVX_512bit); + __ evpxorq(xmm3, k2, xmm3, Address(buf, 120), true, Assembler::AVX_512bit); + __ jmp(rounds24_loop); + + // if(blockSize == 144) SHA3-224 + __ BIND(block144); + __ cmpl(block_size, 144); + __ jcc(Assembler::notEqual, block168); + __ evpxorq(xmm1, k5, xmm1, Address(buf, 40), true, Assembler::AVX_512bit); + __ evpxorq(xmm2, k5, xmm2, Address(buf, 80), true, Assembler::AVX_512bit); + __ evpxorq(xmm3, k3, xmm3, Address(buf, 120), true, Assembler::AVX_512bit); + __ jmp(rounds24_loop); + + // if(blockSize == 168) SHAKE128 + __ BIND(block168); + __ evpxorq(xmm1, k5, xmm1, Address(buf, 40), true, Assembler::AVX_512bit); + __ evpxorq(xmm2, k5, xmm2, Address(buf, 80), true, Assembler::AVX_512bit); + __ evpxorq(xmm3, k5, xmm3, Address(buf, 120), true, Assembler::AVX_512bit); + __ evpxorq(xmm4, k1, xmm4, Address(buf, 160), true, Assembler::AVX_512bit); + + // The 24 rounds of the keccak transformation. + // The implementation closely follows the Java version, with the state + // array "rows" in the lowest 5 64-bit slots of zmm0 - zmm4, i.e. + // each row of the SHA3 specification is located in one zmm register. + __ align(OptoLoopAlignment); + __ BIND(rounds24_loop); + __ subl(roundsLeft, 1); + + __ evmovdquw(xmm5, xmm0, Assembler::AVX_512bit); + // vpternlogq(x, 150, y, z) does x = x ^ y ^ z + __ vpternlogq(xmm5, 150, xmm1, xmm2, Assembler::AVX_512bit); + __ vpternlogq(xmm5, 150, xmm3, xmm4, Assembler::AVX_512bit); + // Now the "c row", i.e. c0-c4 are in zmm5. + // Rotate each element of the c row by one bit to zmm6, call the + // rotated version c'. + __ evprolq(xmm6, xmm5, 1, Assembler::AVX_512bit); + // Rotate elementwise the c row so that c4 becomes c0, + // c0 becomes c1, etc. + __ evpermt2q(xmm5, xmm30, xmm5, Assembler::AVX_512bit); + // rotate elementwise the c' row so that c'0 becomes c'4, + // c'1 becomes c'0, etc. + __ evpermt2q(xmm6, xmm31, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm0, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm1, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm2, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm3, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm4, 150, xmm5, xmm6, Assembler::AVX_512bit); + // Now the theta mapping has been finished. + + // Do the cyclical permutation of the 24 moving state elements + // and the required rotations within each element (the combined + // rho and pi steps). + __ evpermt2q(xmm4, xmm17, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm3, xmm18, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm2, xmm17, xmm1, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm19, xmm0, Assembler::AVX_512bit); + __ evpermt2q(xmm4, xmm20, xmm2, Assembler::AVX_512bit); + // The 24 moving elements are now in zmm1, zmm3 and zmm4, + // do the rotations now. + __ evprolvq(xmm1, xmm1, xmm27, Assembler::AVX_512bit); + __ evprolvq(xmm3, xmm3, xmm28, Assembler::AVX_512bit); + __ evprolvq(xmm4, xmm4, xmm29, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm1, Assembler::AVX_512bit); + __ evmovdquw(xmm5, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm0, xmm21, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm22, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm5, xmm22, xmm2, Assembler::AVX_512bit); + __ evmovdquw(xmm3, xmm1, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm23, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm2, xmm24, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm3, xmm25, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm4, xmm26, xmm5, Assembler::AVX_512bit); + // The combined rho and pi steps are done. + + // Do the chi step (the same operation on all 5 rows). + // vpternlogq(x, 180, y, z) does x = x ^ (y & ~z). + __ evpermt2q(xmm5, xmm31, xmm0, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm0, 180, xmm6, xmm5, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm1, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm1, 180, xmm6, xmm5, Assembler::AVX_512bit); + + // xor the round constant into a0 (the lowest 64 bits of zmm0 + __ evpxorq(xmm0, k1, xmm0, Address(constant2use, 0), true, Assembler::AVX_512bit); + __ addptr(constant2use, 8); + + __ evpermt2q(xmm5, xmm31, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm2, 180, xmm6, xmm5, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm3, 180, xmm6, xmm5, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm4, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ cmpl(roundsLeft, 0); + __ jcc(Assembler::notEqual, rounds24_loop); + + if (multiBlock) { + __ addptr(buf, block_size); + __ addl(ofs, block_size); + __ cmpl(ofs, limit); + __ jcc(Assembler::lessEqual, sha3_loop); + __ movq(rax, ofs); // return ofs + } else { + __ xorq(rax, rax); // return 0 + } + + // store the state + for (int i = 0; i < 5; i++) { + __ evmovdquq(Address(state, i * 40), k5, xmm(i), true, Assembler::AVX_512bit); + } + + __ pop(r14); + __ pop(r13); + __ pop(r12); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; +} + +// Inputs: +// c_rarg0 - long[] state0 +// c_rarg1 - long[] state1 +// +// Performs two keccak() computations in parallel. The steps of the +// two computations are executed interleaved. +static address generate_double_keccak(StubGenerator *stubgen, MacroAssembler *_masm) { + __ align(CodeEntryAlignment); + StubCodeMark mark(stubgen, "StubRoutines", "double_keccak"); + address start = __ pc(); + + const Register state0 = c_rarg0; + const Register state1 = c_rarg1; + + const Register permsAndRots = c_rarg2; + const Register round_consts = c_rarg3; + const Register constant2use = r10; + const Register roundsLeft = r11; + + Label rounds24_loop; + + __ enter(); + + __ lea(permsAndRots, ExternalAddress(permsAndRotsAddr())); + __ lea(round_consts, ExternalAddress(round_constsAddr())); + + // set up the masks + __ movl(rax, 0x1F); + __ kmovwl(k5, rax); + __ kshiftrwl(k4, k5, 1); + __ kshiftrwl(k3, k5, 2); + __ kshiftrwl(k2, k5, 3); + __ kshiftrwl(k1, k5, 4); + + // load the states + for (int i = 0; i < 5; i++) { + __ evmovdquq(xmm(i), k5, Address(state0, i * 40), false, Assembler::AVX_512bit); + } + for (int i = 0; i < 5; i++) { + __ evmovdquq(xmm(10 + i), k5, Address(state1, i * 40), false, Assembler::AVX_512bit); + } + + // load the permutation and rotation constants + + for (int i = 0; i < 15; i++) { + __ evmovdquq(xmm(17 + i), Address(permsAndRots, i * 64), Assembler::AVX_512bit); + } + + // there will be 24 keccak rounds + // The same operations as the ones in generate_sha3_implCompress are + // performed, but in parallel for two states: one in regs z0-z5, using z6 + // as the scratch register and the other in z10-z15, using z16 as the + // scratch register. + // The permutation and rotation constants, that are loaded into z17-z31, + // are shared between the two computations. + __ movl(roundsLeft, 24); + // load round_constants base + __ movptr(constant2use, round_consts); + + __ align(OptoLoopAlignment); + __ BIND(rounds24_loop); + __ subl( roundsLeft, 1); + + __ evmovdquw(xmm5, xmm0, Assembler::AVX_512bit); + __ evmovdquw(xmm15, xmm10, Assembler::AVX_512bit); + __ vpternlogq(xmm5, 150, xmm1, xmm2, Assembler::AVX_512bit); + __ vpternlogq(xmm15, 150, xmm11, xmm12, Assembler::AVX_512bit); + __ vpternlogq(xmm5, 150, xmm3, xmm4, Assembler::AVX_512bit); + __ vpternlogq(xmm15, 150, xmm13, xmm14, Assembler::AVX_512bit); + __ evprolq(xmm6, xmm5, 1, Assembler::AVX_512bit); + __ evprolq(xmm16, xmm15, 1, Assembler::AVX_512bit); + __ evpermt2q(xmm5, xmm30, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm30, xmm15, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm6, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm16, Assembler::AVX_512bit); + __ vpternlogq(xmm0, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm10, 150, xmm15, xmm16, Assembler::AVX_512bit); + __ vpternlogq(xmm1, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm11, 150, xmm15, xmm16, Assembler::AVX_512bit); + __ vpternlogq(xmm2, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm12, 150, xmm15, xmm16, Assembler::AVX_512bit); + __ vpternlogq(xmm3, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm13, 150, xmm15, xmm16, Assembler::AVX_512bit); + __ vpternlogq(xmm4, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm14, 150, xmm15, xmm16, Assembler::AVX_512bit); + __ evpermt2q(xmm4, xmm17, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm14, xmm17, xmm13, Assembler::AVX_512bit); + __ evpermt2q(xmm3, xmm18, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm13, xmm18, xmm12, Assembler::AVX_512bit); + __ evpermt2q(xmm2, xmm17, xmm1, Assembler::AVX_512bit); + __ evpermt2q(xmm12, xmm17, xmm11, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm19, xmm0, Assembler::AVX_512bit); + __ evpermt2q(xmm11, xmm19, xmm10, Assembler::AVX_512bit); + __ evpermt2q(xmm4, xmm20, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm14, xmm20, xmm12, Assembler::AVX_512bit); + __ evprolvq(xmm1, xmm1, xmm27, Assembler::AVX_512bit); + __ evprolvq(xmm11, xmm11, xmm27, Assembler::AVX_512bit); + __ evprolvq(xmm3, xmm3, xmm28, Assembler::AVX_512bit); + __ evprolvq(xmm13, xmm13, xmm28, Assembler::AVX_512bit); + __ evprolvq(xmm4, xmm4, xmm29, Assembler::AVX_512bit); + __ evprolvq(xmm14, xmm14, xmm29, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm1, Assembler::AVX_512bit); + __ evmovdquw(xmm12, xmm11, Assembler::AVX_512bit); + __ evmovdquw(xmm5, xmm3, Assembler::AVX_512bit); + __ evmovdquw(xmm15, xmm13, Assembler::AVX_512bit); + __ evpermt2q(xmm0, xmm21, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm10, xmm21, xmm14, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm22, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm11, xmm22, xmm13, Assembler::AVX_512bit); + __ evpermt2q(xmm5, xmm22, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm22, xmm12, Assembler::AVX_512bit); + __ evmovdquw(xmm3, xmm1, Assembler::AVX_512bit); + __ evmovdquw(xmm13, xmm11, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm5, Assembler::AVX_512bit); + __ evmovdquw(xmm12, xmm15, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm23, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm11, xmm23, xmm14, Assembler::AVX_512bit); + __ evpermt2q(xmm2, xmm24, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm12, xmm24, xmm14, Assembler::AVX_512bit); + __ evpermt2q(xmm3, xmm25, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm13, xmm25, xmm14, Assembler::AVX_512bit); + __ evpermt2q(xmm4, xmm26, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm14, xmm26, xmm15, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm0, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm31, xmm10, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm15, Assembler::AVX_512bit); + __ vpternlogq(xmm0, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm10, 180, xmm16, xmm15, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm1, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm31, xmm11, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm15, Assembler::AVX_512bit); + __ vpternlogq(xmm1, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm11, 180, xmm16, xmm15, Assembler::AVX_512bit); + + __ evpxorq(xmm0, k1, xmm0, Address(constant2use, 0), true, Assembler::AVX_512bit); + __ evpxorq(xmm10, k1, xmm10, Address(constant2use, 0), true, Assembler::AVX_512bit); + __ addptr(constant2use, 8); + + __ evpermt2q(xmm5, xmm31, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm31, xmm12, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm15, Assembler::AVX_512bit); + __ vpternlogq(xmm2, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm12, 180, xmm16, xmm15, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm31, xmm13, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm15, Assembler::AVX_512bit); + __ vpternlogq(xmm3, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm13, 180, xmm16, xmm15, Assembler::AVX_512bit); + __ evpermt2q(xmm5, xmm31, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm31, xmm14, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm15, Assembler::AVX_512bit); + __ vpternlogq(xmm4, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm14, 180, xmm16, xmm15, Assembler::AVX_512bit); + __ 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); + } + for (int i = 0; i < 5; i++) { + __ evmovdquq(Address(state1, i * 40), k5, xmm(10 + i), true, Assembler::AVX_512bit); + } + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; +} + +void StubGenerator::generate_sha3_stubs() { + if (UseSHA3Intrinsics) { + StubRoutines::_sha3_implCompress = + generate_sha3_implCompress(false, "sha3_implCompress", this, _masm); + StubRoutines::_double_keccak = + generate_double_keccak(this, _masm); + StubRoutines::_sha3_implCompressMB = + generate_sha3_implCompress(true, "sha3_implCompressMB", this, _masm); + } +} diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubRoutines_x86.hpp openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubRoutines_x86.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/stubRoutines_x86.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/stubRoutines_x86.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -37,7 +37,7 @@ _continuation_stubs_code_size = 1000 LP64_ONLY(+1000), // AVX512 intrinsics add more code in 64-bit VM, // Windows have more code to save/restore registers - _compiler_stubs_code_size = 20000 LP64_ONLY(+30000) WINDOWS_ONLY(+2000), + _compiler_stubs_code_size = 20000 LP64_ONLY(+55000) WINDOWS_ONLY(+2000), _final_stubs_code_size = 10000 LP64_ONLY(+20000) WINDOWS_ONLY(+2000) ZGC_ONLY(+20000) }; diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/vm_version_x86.cpp openjdk-21-21.0.13+9/src/hotspot/cpu/x86/vm_version_x86.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/vm_version_x86.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/vm_version_x86.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1148,6 +1148,34 @@ } #endif // _LP64 + // Kyber Intrinsics + // Currently we only have them for AVX512 +#ifdef _LP64 + if (supports_evex() && supports_avx512bw()) { + if (FLAG_IS_DEFAULT(UseKyberIntrinsics)) { + UseKyberIntrinsics = true; + } + } else +#endif + if (UseKyberIntrinsics) { + warning("Intrinsics for ML-KEM are not available on this CPU."); + FLAG_SET_DEFAULT(UseKyberIntrinsics, false); + } + + // Dilithium Intrinsics + // Currently we only have them for AVX512 +#ifdef _LP64 + if (supports_evex() && supports_avx512bw()) { + if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { + UseDilithiumIntrinsics = true; + } + } else +#endif + if (UseDilithiumIntrinsics) { + warning("Intrinsics for ML-DSA are not available on this CPU."); + FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false); + } + // Base64 Intrinsics (Check the condition for which the intrinsic will be active) if (UseAVX >= 2) { if (FLAG_IS_DEFAULT(UseBASE64Intrinsics)) { @@ -1212,9 +1240,16 @@ FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } - if (UseSHA3Intrinsics) { - warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); - FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); +#ifdef _LP64 + if (supports_evex() && supports_avx512bw()) { + if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) { + UseSHA3Intrinsics = true; + } + } else +#endif + if (UseSHA3Intrinsics) { + warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); + FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) { diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/x86_32.ad openjdk-21-21.0.13+9/src/hotspot/cpu/x86/x86_32.ad --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/x86_32.ad 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/x86_32.ad 2026-10-19 12:10:20.000000000 +0000 @@ -2051,6 +2051,19 @@ emit_rm( cbuf, 0x0, 1, $mem_ptr$$reg ); %} + enc_class enc_cmpxchgb_narrow(eSIRegP mem_ptr, eAXRegI oldval) %{ + // [Lock] + emit_opcode(cbuf, 0xF0); + + // CMPXCHGB [Eptr] + emit_opcode(cbuf, 0x0F); + emit_opcode(cbuf, 0xB0); + emit_rm(cbuf, 0x0, 1, $mem_ptr$$reg); + + MacroAssembler _masm(&cbuf); + __ narrow_subword_type($oldval$$Register, T_BYTE); + %} + enc_class enc_cmpxchgb(eSIRegP mem_ptr) %{ // [Lock] emit_opcode(cbuf,0xF0); @@ -2061,6 +2074,22 @@ emit_rm( cbuf, 0x0, 1, $mem_ptr$$reg ); %} + enc_class enc_cmpxchgw_narrow(eSIRegP mem_ptr, eAXRegI oldval) %{ + // [Lock] + emit_opcode(cbuf,0xF0); + + // 16-bit mode + emit_opcode(cbuf, 0x66); + + // CMPXCHGW [Eptr] + emit_opcode(cbuf,0x0F); + emit_opcode(cbuf,0xB1); + emit_rm( cbuf, 0x0, 1, $mem_ptr$$reg ); + + MacroAssembler _masm(&cbuf); + __ narrow_subword_type($oldval$$Register, T_SHORT); + %} + enc_class enc_cmpxchgw(eSIRegP mem_ptr) %{ // [Lock] emit_opcode(cbuf,0xF0); @@ -7370,7 +7399,7 @@ match(Set oldval (CompareAndExchangeB mem_ptr (Binary oldval newval))); effect(KILL cr); format %{ "CMPXCHGB [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} - ins_encode( enc_cmpxchgb(mem_ptr) ); + ins_encode( enc_cmpxchgb_narrow(mem_ptr, oldval) ); ins_pipe( pipe_cmpxchg ); %} @@ -7378,7 +7407,7 @@ match(Set oldval (CompareAndExchangeS mem_ptr (Binary oldval newval))); effect(KILL cr); format %{ "CMPXCHGW [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} - ins_encode( enc_cmpxchgw(mem_ptr) ); + ins_encode( enc_cmpxchgw_narrow(mem_ptr, oldval) ); ins_pipe( pipe_cmpxchg ); %} diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/x86_64.ad openjdk-21-21.0.13+9/src/hotspot/cpu/x86/x86_64.ad --- openjdk-21-21.0.12.1+1/src/hotspot/cpu/x86/x86_64.ad 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/cpu/x86/x86_64.ad 2026-10-19 12:10:20.000000000 +0000 @@ -8231,10 +8231,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 ); %} @@ -8248,10 +8250,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 ); %} @@ -8265,7 +8269,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); @@ -8283,7 +8288,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); @@ -8299,7 +8305,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); @@ -8317,7 +8324,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); diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/os/linux/os_linux.cpp openjdk-21-21.0.13+9/src/hotspot/os/linux/os_linux.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/os/linux/os_linux.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/os/linux/os_linux.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -2058,6 +2058,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); @@ -2427,6 +2431,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; diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/os/linux/os_linux.hpp openjdk-21-21.0.13+9/src/hotspot/os/linux/os_linux.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/os/linux/os_linux.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/os/linux/os_linux.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -96,6 +96,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 { diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/os/windows/os_perf_windows.cpp openjdk-21-21.0.13+9/src/hotspot/os/windows/os_perf_windows.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/os/windows/os_perf_windows.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/os/windows/os_perf_windows.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -780,6 +780,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; @@ -787,8 +895,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; @@ -822,13 +933,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() { @@ -848,7 +963,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; @@ -862,8 +986,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; @@ -881,7 +1005,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, @@ -897,6 +1025,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-21-21.0.12.1+1/src/hotspot/share/c1/c1_Compiler.cpp openjdk-21-21.0.13+9/src/hotspot/share/c1/c1_Compiler.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/c1/c1_Compiler.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/c1/c1_Compiler.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -138,7 +138,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-21-21.0.12.1+1/src/hotspot/share/c1/c1_GraphBuilder.cpp openjdk-21-21.0.13+9/src/hotspot/share/c1/c1_GraphBuilder.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/c1/c1_GraphBuilder.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/c1/c1_GraphBuilder.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -3377,7 +3377,7 @@ break; } - case vmIntrinsics::_Reference_get: + case vmIntrinsics::_Reference_get0: { { // With java.lang.ref.reference.get() we must go through the diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/c1/c1_LIRGenerator.cpp openjdk-21-21.0.13+9/src/hotspot/share/c1/c1_LIRGenerator.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/c1/c1_LIRGenerator.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/c1/c1_LIRGenerator.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1203,7 +1203,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(); @@ -3016,8 +3016,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-21-21.0.12.1+1/src/hotspot/share/c1/c1_LIRGenerator.hpp openjdk-21-21.0.13+9/src/hotspot/share/c1/c1_LIRGenerator.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/c1/c1_LIRGenerator.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/c1/c1_LIRGenerator.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -267,7 +267,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-21-21.0.12.1+1/src/hotspot/share/classfile/classLoader.cpp openjdk-21-21.0.13+9/src/hotspot/share/classfile/classLoader.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/classfile/classLoader.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/classfile/classLoader.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -815,7 +815,8 @@ ClassPathEntry* e = _app_classpath_entries; if (check_for_duplicates) { while (e != nullptr) { - if (strcmp(e->name(), entry->name()) == 0) { + if (strcmp(e->name(), entry->name()) == 0 && + e->from_class_path_attr() == entry->from_class_path_attr()) { // entry already exists return false; } @@ -1463,6 +1464,10 @@ jio_snprintf(modules_path, JVM_MAXPATHLEN, "%s%slib%smodules", Arguments::get_java_home(), fileSep, fileSep); JImage_file =(*JImageOpen)(modules_path, &error); if (JImage_file == nullptr) { + if (Arguments::has_jimage()) { + // The modules file exists but is unreadable or corrupt + vm_exit_during_initialization(err_msg("Unable to load %s", modules_path)); + } return nullptr; } diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/classfile/stringTable.cpp openjdk-21-21.0.13+9/src/hotspot/share/classfile/stringTable.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/classfile/stringTable.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/classfile/stringTable.cpp 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 @@ -455,6 +455,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; @@ -462,7 +466,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-21-21.0.12.1+1/src/hotspot/share/classfile/symbolTable.cpp openjdk-21-21.0.13+9/src/hotspot/share/classfile/symbolTable.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/classfile/symbolTable.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/classfile/symbolTable.cpp 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 @@ -755,6 +755,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; @@ -762,7 +766,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-21-21.0.12.1+1/src/hotspot/share/classfile/vmIntrinsics.cpp openjdk-21-21.0.13+9/src/hotspot/share/classfile/vmIntrinsics.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/classfile/vmIntrinsics.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/classfile/vmIntrinsics.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -94,7 +94,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: @@ -238,7 +238,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: break; @@ -472,6 +472,7 @@ case vmIntrinsics::_sha5_implCompress: if (!UseSHA512Intrinsics) return true; break; + case vmIntrinsics::_double_keccak: case vmIntrinsics::_sha3_implCompress: if (!UseSHA3Intrinsics) return true; break; @@ -484,6 +485,22 @@ case vmIntrinsics::_chacha20Block: if (!UseChaCha20Intrinsics) return true; break; + case vmIntrinsics::_kyberNtt: + case vmIntrinsics::_kyberInverseNtt: + case vmIntrinsics::_kyberNttMult: + case vmIntrinsics::_kyberAddPoly_2: + case vmIntrinsics::_kyberAddPoly_3: + case vmIntrinsics::_kyber12To16: + case vmIntrinsics::_kyberBarrettReduce: + if (!UseKyberIntrinsics) return true; + break; + case vmIntrinsics::_dilithiumAlmostNtt: + case vmIntrinsics::_dilithiumAlmostInverseNtt: + case vmIntrinsics::_dilithiumNttMult: + case vmIntrinsics::_dilithiumMontMulByConstant: + case vmIntrinsics::_dilithiumDecomposePoly: + if (!UseDilithiumIntrinsics) return true; + break; case vmIntrinsics::_base64_encodeBlock: case vmIntrinsics::_base64_decodeBlock: if (!UseBASE64Intrinsics) return true; diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/classfile/vmIntrinsics.hpp openjdk-21-21.0.13+9/src/hotspot/share/classfile/vmIntrinsics.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/classfile/vmIntrinsics.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/classfile/vmIntrinsics.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -458,7 +458,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) \ \ @@ -514,6 +514,12 @@ do_class(sun_security_provider_sha3, "sun/security/provider/SHA3") \ do_intrinsic(_sha3_implCompress, sun_security_provider_sha3, implCompress_name, implCompress_signature, F_R) \ \ + /* support for sun.security.provider.SHAKE128Parallel */ \ + do_class(sun_security_provider_sha3_parallel, "sun/security/provider/SHA3Parallel") \ + do_intrinsic(_double_keccak, sun_security_provider_sha3_parallel, double_keccak_name, double_keccak_signature, F_S) \ + do_name( double_keccak_name, "doubleKeccak") \ + do_signature(double_keccak_signature, "([J[J)I") \ + \ /* support for sun.security.provider.DigestBase */ \ do_class(sun_security_provider_digestbase, "sun/security/provider/DigestBase") \ do_intrinsic(_digestBase_implCompressMB, sun_security_provider_digestbase, implCompressMB_name, countPositives_signature, F_R) \ @@ -548,6 +554,47 @@ do_name(chacha20Block_name, "implChaCha20Block") \ do_signature(chacha20Block_signature, "([I[B)I") \ \ + /* support for com.sun.crypto.provider.ML_KEM */ \ + do_class(com_sun_crypto_provider_ML_KEM, "com/sun/crypto/provider/ML_KEM") \ + do_signature(SaSaSaSaI_signature, "([S[S[S[S)I") \ + do_signature(BaISaII_signature, "([BI[SI)I") \ + do_signature(SaSaSaI_signature, "([S[S[S)I") \ + do_signature(SaSaI_signature, "([S[S)I") \ + do_signature(SaI_signature, "([S)I") \ + do_name(kyberAddPoly_name, "implKyberAddPoly") \ + do_intrinsic(_kyberNtt, com_sun_crypto_provider_ML_KEM, kyberNtt_name, SaSaI_signature, F_S) \ + do_name(kyberNtt_name, "implKyberNtt") \ + do_intrinsic(_kyberInverseNtt, com_sun_crypto_provider_ML_KEM, kyberInverseNtt_name, SaSaI_signature, F_S) \ + do_name(kyberInverseNtt_name, "implKyberInverseNtt") \ + do_intrinsic(_kyberNttMult, com_sun_crypto_provider_ML_KEM, kyberNttMult_name, SaSaSaSaI_signature, F_S) \ + do_name(kyberNttMult_name, "implKyberNttMult") \ + do_intrinsic(_kyberAddPoly_2, com_sun_crypto_provider_ML_KEM, kyberAddPoly_name, SaSaSaI_signature, F_S) \ + do_intrinsic(_kyberAddPoly_3, com_sun_crypto_provider_ML_KEM, kyberAddPoly_name, SaSaSaSaI_signature, F_S) \ + do_intrinsic(_kyber12To16, com_sun_crypto_provider_ML_KEM, kyber12To16_name, BaISaII_signature, F_S) \ + do_name(kyber12To16_name, "implKyber12To16") \ + do_intrinsic(_kyberBarrettReduce, com_sun_crypto_provider_ML_KEM, kyberBarrettReduce_name, SaI_signature, F_S) \ + do_name(kyberBarrettReduce_name, "implKyberBarrettReduce") \ + \ + /* support for sun.security.provider.ML_DSA */ \ + do_class(sun_security_provider_ML_DSA, "sun/security/provider/ML_DSA") \ + do_signature(IaII_signature, "([II)I") \ + do_signature(IaIaI_signature, "([I[I)I") \ + do_signature(IaIaIaI_signature, "([I[I[I)I") \ + do_signature(IaIaIaIII_signature, "([I[I[III)I") \ + do_intrinsic(_dilithiumAlmostNtt, sun_security_provider_ML_DSA, dilithiumAlmostNtt_name, IaIaI_signature, F_S) \ + do_name(dilithiumAlmostNtt_name, "implDilithiumAlmostNtt") \ + do_intrinsic(_dilithiumAlmostInverseNtt, sun_security_provider_ML_DSA, \ + dilithiumAlmostInverseNtt_name, IaIaI_signature, F_S) \ + do_name(dilithiumAlmostInverseNtt_name, "implDilithiumAlmostInverseNtt") \ + do_intrinsic(_dilithiumNttMult, sun_security_provider_ML_DSA, dilithiumNttMult_name, IaIaIaI_signature, F_S) \ + do_name(dilithiumNttMult_name, "implDilithiumNttMult") \ + do_intrinsic(_dilithiumMontMulByConstant, sun_security_provider_ML_DSA, \ + dilithiumMontMulByConstant_name, IaII_signature, F_S) \ + do_name(dilithiumMontMulByConstant_name, "implDilithiumMontMulByConstant") \ + do_intrinsic(_dilithiumDecomposePoly, sun_security_provider_ML_DSA, \ + dilithiumDecomposePoly_name, IaIaIaIII_signature, F_S) \ + do_name(dilithiumDecomposePoly_name, "implDilithiumDecomposePoly") \ + \ /* support for java.util.zip */ \ do_class(java_util_zip_CRC32, "java/util/zip/CRC32") \ do_intrinsic(_updateCRC32, java_util_zip_CRC32, update_name, int2_int_signature, F_SN) \ diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/classfile/vmSymbols.hpp openjdk-21-21.0.13+9/src/hotspot/share/classfile/vmSymbols.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/classfile/vmSymbols.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/classfile/vmSymbols.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -441,7 +441,7 @@ template(cs_name, "cs") \ template(refStack_name, "refStack") \ template(refSP_name, "refSP") \ - template(get_name, "get") \ + template(get0_name, "get0") \ template(refersTo0_name, "refersTo0") \ template(put_name, "put") \ template(type_name, "type") \ diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/include/jvm.h openjdk-21-21.0.13+9/src/hotspot/share/include/jvm.h --- openjdk-21-21.0.12.1+1/src/hotspot/share/include/jvm.h 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/include/jvm.h 2026-10-19 12:10:20.000000000 +0000 @@ -357,6 +357,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-21-21.0.12.1+1/src/hotspot/share/interpreter/abstractInterpreter.cpp openjdk-21-21.0.13+9/src/hotspot/share/interpreter/abstractInterpreter.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/interpreter/abstractInterpreter.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/interpreter/abstractInterpreter.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -147,7 +147,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 (RegisterFinalizersAtInit && m->code_size() == 1) { // We need to execute the special return bytecode to check for @@ -207,7 +207,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; @@ -323,7 +323,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_intBitsToFloat : tty->print("java_lang_Float_intBitsToFloat"); break; case java_lang_Float_floatToRawIntBits : tty->print("java_lang_Float_floatToRawIntBits"); break; diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/interpreter/abstractInterpreter.hpp openjdk-21-21.0.13+9/src/hotspot/share/interpreter/abstractInterpreter.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/interpreter/abstractInterpreter.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/interpreter/abstractInterpreter.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -81,7 +81,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-21-21.0.12.1+1/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp openjdk-21-21.0.13+9/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -201,7 +201,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) @@ -225,6 +225,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) @@ -467,7 +468,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-21-21.0.12.1+1/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp openjdk-21-21.0.13+9/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -63,7 +63,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(); @@ -104,7 +104,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-21-21.0.12.1+1/src/hotspot/share/jvmci/vmStructs_jvmci.cpp openjdk-21-21.0.13+9/src/hotspot/share/jvmci/vmStructs_jvmci.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/jvmci/vmStructs_jvmci.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/jvmci/vmStructs_jvmci.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -350,7 +350,20 @@ static_field(StubRoutines, _sha512_implCompress, address) \ static_field(StubRoutines, _sha512_implCompressMB, address) \ static_field(StubRoutines, _sha3_implCompress, address) \ + static_field(StubRoutines, _double_keccak, address) \ static_field(StubRoutines, _sha3_implCompressMB, address) \ + static_field(StubRoutines, _kyberNtt, address) \ + static_field(StubRoutines, _kyberInverseNtt, address) \ + static_field(StubRoutines, _kyberNttMult, address) \ + static_field(StubRoutines, _kyberAddPoly_2, address) \ + static_field(StubRoutines, _kyberAddPoly_3, address) \ + static_field(StubRoutines, _kyber12To16, address) \ + static_field(StubRoutines, _kyberBarrettReduce, address) \ + static_field(StubRoutines, _dilithiumAlmostNtt, address) \ + static_field(StubRoutines, _dilithiumAlmostInverseNtt, address) \ + static_field(StubRoutines, _dilithiumNttMult, address) \ + static_field(StubRoutines, _dilithiumMontMulByConstant, address) \ + static_field(StubRoutines, _dilithiumDecomposePoly, address) \ static_field(StubRoutines, _updateBytesCRC32, address) \ static_field(StubRoutines, _crc_table_adr, address) \ static_field(StubRoutines, _crc32c_table_addr, address) \ diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/opto/c2compiler.cpp openjdk-21-21.0.13+9/src/hotspot/share/opto/c2compiler.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/c2compiler.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/c2compiler.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -706,7 +706,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::_Class_cast: @@ -723,6 +723,7 @@ case vmIntrinsics::_sha2_implCompress: case vmIntrinsics::_sha5_implCompress: case vmIntrinsics::_sha3_implCompress: + case vmIntrinsics::_double_keccak: case vmIntrinsics::_digestBase_implCompressMB: case vmIntrinsics::_multiplyToLen: case vmIntrinsics::_squareToLen: @@ -734,6 +735,18 @@ case vmIntrinsics::_vectorizedMismatch: case vmIntrinsics::_ghash_processBlocks: case vmIntrinsics::_chacha20Block: + case vmIntrinsics::_kyberNtt: + case vmIntrinsics::_kyberInverseNtt: + case vmIntrinsics::_kyberNttMult: + case vmIntrinsics::_kyberAddPoly_2: + case vmIntrinsics::_kyberAddPoly_3: + case vmIntrinsics::_kyber12To16: + case vmIntrinsics::_kyberBarrettReduce: + case vmIntrinsics::_dilithiumAlmostNtt: + case vmIntrinsics::_dilithiumAlmostInverseNtt: + case vmIntrinsics::_dilithiumNttMult: + case vmIntrinsics::_dilithiumMontMulByConstant: + case vmIntrinsics::_dilithiumDecomposePoly: case vmIntrinsics::_base64_encodeBlock: case vmIntrinsics::_base64_decodeBlock: case vmIntrinsics::_poly1305_processBlocks: diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/opto/compile.cpp openjdk-21-21.0.13+9/src/hotspot/share/opto/compile.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/compile.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/compile.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -748,19 +748,9 @@ StartNode* s = new StartNode(root(), tf()->domain()); initial_gvn()->set_type_bottom(s); init_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) { diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/opto/escape.cpp openjdk-21-21.0.13+9/src/hotspot/share/opto/escape.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/escape.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/escape.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1172,6 +1172,18 @@ strcmp(call->as_CallLeaf()->_name, "poly1305_processBlocks") == 0 || strcmp(call->as_CallLeaf()->_name, "ghash_processBlocks") == 0 || strcmp(call->as_CallLeaf()->_name, "chacha20Block") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberNtt") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberInverseNtt") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberNttMult") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberAddPoly_2") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberAddPoly_3") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyber12To16") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberBarrettReduce") == 0 || + strcmp(call->as_CallLeaf()->_name, "dilithiumAlmostNtt") == 0 || + strcmp(call->as_CallLeaf()->_name, "dilithiumAlmostInverseNtt") == 0 || + strcmp(call->as_CallLeaf()->_name, "dilithiumNttMult") == 0 || + strcmp(call->as_CallLeaf()->_name, "dilithiumMontMulByConstant") == 0 || + strcmp(call->as_CallLeaf()->_name, "dilithiumDecomposePoly") == 0 || strcmp(call->as_CallLeaf()->_name, "encodeBlock") == 0 || strcmp(call->as_CallLeaf()->_name, "decodeBlock") == 0 || strcmp(call->as_CallLeaf()->_name, "md5_implCompress") == 0 || @@ -1183,6 +1195,7 @@ strcmp(call->as_CallLeaf()->_name, "sha512_implCompress") == 0 || strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0 || strcmp(call->as_CallLeaf()->_name, "sha3_implCompress") == 0 || + strcmp(call->as_CallLeaf()->_name, "double_keccak") == 0 || strcmp(call->as_CallLeaf()->_name, "sha3_implCompressMB") == 0 || strcmp(call->as_CallLeaf()->_name, "multiplyToLen") == 0 || strcmp(call->as_CallLeaf()->_name, "squareToLen") == 0 || diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/opto/library_call.cpp openjdk-21-21.0.13+9/src/hotspot/share/opto/library_call.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/library_call.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/library_call.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -568,7 +568,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); @@ -597,6 +597,8 @@ case vmIntrinsics::_sha5_implCompress: case vmIntrinsics::_sha3_implCompress: return inline_digestBase_implCompress(intrinsic_id()); + case vmIntrinsics::_double_keccak: + return inline_double_keccak(); case vmIntrinsics::_digestBase_implCompressMB: return inline_digestBase_implCompressMB(predicate); @@ -627,6 +629,30 @@ return inline_ghash_processBlocks(); case vmIntrinsics::_chacha20Block: return inline_chacha20Block(); + case vmIntrinsics::_kyberNtt: + return inline_kyberNtt(); + case vmIntrinsics::_kyberInverseNtt: + return inline_kyberInverseNtt(); + case vmIntrinsics::_kyberNttMult: + return inline_kyberNttMult(); + case vmIntrinsics::_kyberAddPoly_2: + return inline_kyberAddPoly_2(); + case vmIntrinsics::_kyberAddPoly_3: + return inline_kyberAddPoly_3(); + case vmIntrinsics::_kyber12To16: + return inline_kyber12To16(); + case vmIntrinsics::_kyberBarrettReduce: + return inline_kyberBarrettReduce(); + case vmIntrinsics::_dilithiumAlmostNtt: + return inline_dilithiumAlmostNtt(); + case vmIntrinsics::_dilithiumAlmostInverseNtt: + return inline_dilithiumAlmostInverseNtt(); + case vmIntrinsics::_dilithiumNttMult: + return inline_dilithiumNttMult(); + case vmIntrinsics::_dilithiumMontMulByConstant: + return inline_dilithiumMontMulByConstant(); + case vmIntrinsics::_dilithiumDecomposePoly: + return inline_dilithiumDecomposePoly(); case vmIntrinsics::_base64_encodeBlock: return inline_base64_encodeBlock(); case vmIntrinsics::_base64_decodeBlock: @@ -6554,9 +6580,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: @@ -7258,6 +7284,417 @@ return true; } +//------------------------------inline_kyberNtt +bool LibraryCallKit::inline_kyberNtt() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 2, "kyberNtt has 2 parameters"); + + stubAddr = StubRoutines::kyberNtt(); + stubName = "kyberNtt"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + Node* ntt_zetas = argument(1); + + coeffs = must_be_not_null(coeffs, true); + ntt_zetas = must_be_not_null(ntt_zetas, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_SHORT); + assert(coeffs_start, "coeffs is null"); + Node* ntt_zetas_start = array_element_address(ntt_zetas, intcon(0), T_SHORT); + assert(ntt_zetas_start, "ntt_zetas is null"); + Node* kyberNtt = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberNtt_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start, ntt_zetas_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberNtt, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_kyberInverseNtt +bool LibraryCallKit::inline_kyberInverseNtt() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 2, "kyberInverseNtt has 2 parameters"); + + stubAddr = StubRoutines::kyberInverseNtt(); + stubName = "kyberInverseNtt"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + Node* zetas = argument(1); + + coeffs = must_be_not_null(coeffs, true); + zetas = must_be_not_null(zetas, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_SHORT); + assert(coeffs_start, "coeffs is null"); + Node* zetas_start = array_element_address(zetas, intcon(0), T_SHORT); + assert(zetas_start, "inverseNtt_zetas is null"); + Node* kyberInverseNtt = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberInverseNtt_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start, zetas_start); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberInverseNtt, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_kyberNttMult +bool LibraryCallKit::inline_kyberNttMult() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 4, "kyberNttMult has 4 parameters"); + + stubAddr = StubRoutines::kyberNttMult(); + stubName = "kyberNttMult"; + if (!stubAddr) return false; + + Node* result = argument(0); + Node* ntta = argument(1); + Node* nttb = argument(2); + Node* zetas = argument(3); + + result = must_be_not_null(result, true); + ntta = must_be_not_null(ntta, true); + nttb = must_be_not_null(nttb, true); + zetas = must_be_not_null(zetas, true); + + Node* result_start = array_element_address(result, intcon(0), T_SHORT); + assert(result_start, "result is null"); + Node* ntta_start = array_element_address(ntta, intcon(0), T_SHORT); + assert(ntta_start, "ntta is null"); + Node* nttb_start = array_element_address(nttb, intcon(0), T_SHORT); + assert(nttb_start, "nttb is null"); + Node* zetas_start = array_element_address(zetas, intcon(0), T_SHORT); + assert(zetas_start, "nttMult_zetas is null"); + Node* kyberNttMult = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberNttMult_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + result_start, ntta_start, nttb_start, + zetas_start); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberNttMult, TypeFunc::Parms)); + set_result(retvalue); + + return true; +} + +//------------------------------inline_kyberAddPoly_2 +bool LibraryCallKit::inline_kyberAddPoly_2() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 3, "kyberAddPoly_2 has 3 parameters"); + + stubAddr = StubRoutines::kyberAddPoly_2(); + stubName = "kyberAddPoly_2"; + if (!stubAddr) return false; + + Node* result = argument(0); + Node* a = argument(1); + Node* b = argument(2); + + result = must_be_not_null(result, true); + a = must_be_not_null(a, true); + b = must_be_not_null(b, true); + + Node* result_start = array_element_address(result, intcon(0), T_SHORT); + assert(result_start, "result is null"); + Node* a_start = array_element_address(a, intcon(0), T_SHORT); + assert(a_start, "a is null"); + Node* b_start = array_element_address(b, intcon(0), T_SHORT); + assert(b_start, "b is null"); + Node* kyberAddPoly_2 = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberAddPoly_2_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + result_start, a_start, b_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberAddPoly_2, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_kyberAddPoly_3 +bool LibraryCallKit::inline_kyberAddPoly_3() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 4, "kyberAddPoly_3 has 4 parameters"); + + stubAddr = StubRoutines::kyberAddPoly_3(); + stubName = "kyberAddPoly_3"; + if (!stubAddr) return false; + + Node* result = argument(0); + Node* a = argument(1); + Node* b = argument(2); + Node* c = argument(3); + + result = must_be_not_null(result, true); + a = must_be_not_null(a, true); + b = must_be_not_null(b, true); + c = must_be_not_null(c, true); + + Node* result_start = array_element_address(result, intcon(0), T_SHORT); + assert(result_start, "result is null"); + Node* a_start = array_element_address(a, intcon(0), T_SHORT); + assert(a_start, "a is null"); + Node* b_start = array_element_address(b, intcon(0), T_SHORT); + assert(b_start, "b is null"); + Node* c_start = array_element_address(c, intcon(0), T_SHORT); + assert(c_start, "c is null"); + Node* kyberAddPoly_3 = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberAddPoly_3_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + result_start, a_start, b_start, c_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberAddPoly_3, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_kyber12To16 +bool LibraryCallKit::inline_kyber12To16() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 4, "kyber12To16 has 4 parameters"); + + stubAddr = StubRoutines::kyber12To16(); + stubName = "kyber12To16"; + if (!stubAddr) return false; + + Node* condensed = argument(0); + Node* condensedOffs = argument(1); + Node* parsed = argument(2); + Node* parsedLength = argument(3); + + condensed = must_be_not_null(condensed, true); + parsed = must_be_not_null(parsed, true); + + Node* condensed_start = array_element_address(condensed, intcon(0), T_BYTE); + assert(condensed_start, "condensed is null"); + Node* parsed_start = array_element_address(parsed, intcon(0), T_SHORT); + assert(parsed_start, "parsed is null"); + Node* kyber12To16 = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyber12To16_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + condensed_start, condensedOffs, parsed_start, parsedLength); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyber12To16, TypeFunc::Parms)); + set_result(retvalue); + return true; + +} + +//------------------------------inline_kyberBarrettReduce +bool LibraryCallKit::inline_kyberBarrettReduce() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 1, "kyberBarrettReduce has 1 parameters"); + + stubAddr = StubRoutines::kyberBarrettReduce(); + stubName = "kyberBarrettReduce"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + + coeffs = must_be_not_null(coeffs, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_SHORT); + assert(coeffs_start, "coeffs is null"); + Node* kyberBarrettReduce = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberBarrettReduce_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberBarrettReduce, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_dilithiumAlmostNtt +bool LibraryCallKit::inline_dilithiumAlmostNtt() { + address stubAddr; + const char *stubName; + assert(UseDilithiumIntrinsics, "need Dilithium intrinsics support"); + assert(callee()->signature()->size() == 2, "dilithiumAlmostNtt has 2 parameters"); + + stubAddr = StubRoutines::dilithiumAlmostNtt(); + stubName = "dilithiumAlmostNtt"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + Node* ntt_zetas = argument(1); + + coeffs = must_be_not_null(coeffs, true); + ntt_zetas = must_be_not_null(ntt_zetas, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_INT); + assert(coeffs_start, "coeffs is null"); + Node* ntt_zetas_start = array_element_address(ntt_zetas, intcon(0), T_INT); + assert(ntt_zetas_start, "ntt_zetas is null"); + Node* dilithiumAlmostNtt = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::dilithiumAlmostNtt_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start, ntt_zetas_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(dilithiumAlmostNtt, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_dilithiumAlmostInverseNtt +bool LibraryCallKit::inline_dilithiumAlmostInverseNtt() { + address stubAddr; + const char *stubName; + assert(UseDilithiumIntrinsics, "need Dilithium intrinsics support"); + assert(callee()->signature()->size() == 2, "dilithiumAlmostInverseNtt has 2 parameters"); + + stubAddr = StubRoutines::dilithiumAlmostInverseNtt(); + stubName = "dilithiumAlmostInverseNtt"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + Node* zetas = argument(1); + + coeffs = must_be_not_null(coeffs, true); + zetas = must_be_not_null(zetas, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_INT); + assert(coeffs_start, "coeffs is null"); + Node* zetas_start = array_element_address(zetas, intcon(0), T_INT); + assert(zetas_start, "inverseNtt_zetas is null"); + Node* dilithiumAlmostInverseNtt = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::dilithiumAlmostInverseNtt_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start, zetas_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(dilithiumAlmostInverseNtt, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_dilithiumNttMult +bool LibraryCallKit::inline_dilithiumNttMult() { + address stubAddr; + const char *stubName; + assert(UseDilithiumIntrinsics, "need Dilithium intrinsics support"); + assert(callee()->signature()->size() == 3, "dilithiumNttMult has 3 parameters"); + + stubAddr = StubRoutines::dilithiumNttMult(); + stubName = "dilithiumNttMult"; + if (!stubAddr) return false; + + Node* result = argument(0); + Node* ntta = argument(1); + Node* nttb = argument(2); + Node* zetas = argument(3); + + result = must_be_not_null(result, true); + ntta = must_be_not_null(ntta, true); + nttb = must_be_not_null(nttb, true); + zetas = must_be_not_null(zetas, true); + + Node* result_start = array_element_address(result, intcon(0), T_INT); + assert(result_start, "result is null"); + Node* ntta_start = array_element_address(ntta, intcon(0), T_INT); + assert(ntta_start, "ntta is null"); + Node* nttb_start = array_element_address(nttb, intcon(0), T_INT); + assert(nttb_start, "nttb is null"); + Node* dilithiumNttMult = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::dilithiumNttMult_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + result_start, ntta_start, nttb_start); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(dilithiumNttMult, TypeFunc::Parms)); + set_result(retvalue); + + return true; +} + +//------------------------------inline_dilithiumMontMulByConstant +bool LibraryCallKit::inline_dilithiumMontMulByConstant() { + address stubAddr; + const char *stubName; + assert(UseDilithiumIntrinsics, "need Dilithium intrinsics support"); + assert(callee()->signature()->size() == 2, "dilithiumMontMulByConstant has 2 parameters"); + + stubAddr = StubRoutines::dilithiumMontMulByConstant(); + stubName = "dilithiumMontMulByConstant"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + Node* constant = argument(1); + + coeffs = must_be_not_null(coeffs, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_INT); + assert(coeffs_start, "coeffs is null"); + Node* dilithiumMontMulByConstant = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::dilithiumMontMulByConstant_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start, constant); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(dilithiumMontMulByConstant, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + + +//------------------------------inline_dilithiumDecomposePoly +bool LibraryCallKit::inline_dilithiumDecomposePoly() { + address stubAddr; + const char *stubName; + assert(UseDilithiumIntrinsics, "need Dilithium intrinsics support"); + assert(callee()->signature()->size() == 5, "dilithiumDecomposePoly has 5 parameters"); + + stubAddr = StubRoutines::dilithiumDecomposePoly(); + stubName = "dilithiumDecomposePoly"; + if (!stubAddr) return false; + + Node* input = argument(0); + Node* lowPart = argument(1); + Node* highPart = argument(2); + Node* twoGamma2 = argument(3); + Node* multiplier = argument(4); + + input = must_be_not_null(input, true); + lowPart = must_be_not_null(lowPart, true); + highPart = must_be_not_null(highPart, true); + + Node* input_start = array_element_address(input, intcon(0), T_INT); + assert(input_start, "input is null"); + Node* lowPart_start = array_element_address(lowPart, intcon(0), T_INT); + assert(lowPart_start, "lowPart is null"); + Node* highPart_start = array_element_address(highPart, intcon(0), T_INT); + assert(highPart_start, "highPart is null"); + + Node* dilithiumDecomposePoly = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::dilithiumDecomposePoly_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + input_start, lowPart_start, highPart_start, + twoGamma2, multiplier); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(dilithiumDecomposePoly, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + bool LibraryCallKit::inline_base64_encodeBlock() { address stubAddr; const char *stubName; @@ -7430,7 +7867,7 @@ break; case vmIntrinsics::_sha3_implCompress: assert(UseSHA3Intrinsics, "need SHA3 instruction support"); - state = get_state_from_digest_object(digestBase_obj, T_BYTE); + state = get_state_from_digest_object(digestBase_obj, T_LONG); stubAddr = StubRoutines::sha3_implCompress(); stubName = "sha3_implCompress"; block_size = get_block_size_from_digest_object(digestBase_obj); @@ -7460,6 +7897,38 @@ return true; } +//------------------------------inline_double_keccak +bool LibraryCallKit::inline_double_keccak() { + address stubAddr; + const char *stubName; + assert(UseSHA3Intrinsics, "need SHA3 intrinsics support"); + assert(callee()->signature()->size() == 2, "double_keccak has 2 parameters"); + + stubAddr = StubRoutines::double_keccak(); + stubName = "double_keccak"; + if (!stubAddr) return false; + + Node* status0 = argument(0); + Node* status1 = argument(1); + + status0 = must_be_not_null(status0, true); + status1 = must_be_not_null(status1, true); + + Node* status0_start = array_element_address(status0, intcon(0), T_LONG); + assert(status0_start, "status0 is null"); + Node* status1_start = array_element_address(status1, intcon(0), T_LONG); + assert(status1_start, "status1 is null"); + Node* double_keccak = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::double_keccak_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + status0_start, status1_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(double_keccak, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + + //------------------------------inline_digestBase_implCompressMB----------------------- // // Calculate MD5/SHA/SHA2/SHA5/SHA3 for multi-block byte[] array. @@ -7530,7 +7999,7 @@ klass_digestBase_name = "sun/security/provider/SHA3"; stub_name = "sha3_implCompressMB"; stub_addr = StubRoutines::sha3_implCompressMB(); - elem_type = T_BYTE; + elem_type = T_LONG; } break; default: diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/opto/library_call.hpp openjdk-21-21.0.13+9/src/hotspot/share/opto/library_call.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/library_call.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/library_call.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -288,7 +288,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_Class_cast(); bool inline_aescrypt_Block(vmIntrinsics::ID id); @@ -301,10 +301,23 @@ Node* get_key_start_from_aescrypt_object(Node* aescrypt_object); bool inline_ghash_processBlocks(); bool inline_chacha20Block(); + bool inline_kyberNtt(); + bool inline_kyberInverseNtt(); + bool inline_kyberNttMult(); + bool inline_kyberAddPoly_2(); + bool inline_kyberAddPoly_3(); + bool inline_kyber12To16(); + bool inline_kyberBarrettReduce(); + bool inline_dilithiumAlmostNtt(); + bool inline_dilithiumAlmostInverseNtt(); + bool inline_dilithiumNttMult(); + bool inline_dilithiumMontMulByConstant(); + bool inline_dilithiumDecomposePoly(); bool inline_base64_encodeBlock(); bool inline_base64_decodeBlock(); bool inline_poly1305_processBlocks(); bool inline_digestBase_implCompress(vmIntrinsics::ID id); + bool inline_double_keccak(); bool inline_digestBase_implCompressMB(int predicate); bool inline_digestBase_implCompressMB(Node* digestBaseObj, ciInstanceKlass* instklass, BasicType elem_type, address stubAddr, const char *stubName, diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/opto/loopPredicate.cpp openjdk-21-21.0.13+9/src/hotspot/share/opto/loopPredicate.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/loopPredicate.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/loopPredicate.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -827,10 +827,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(); @@ -888,20 +888,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-21-21.0.12.1+1/src/hotspot/share/opto/loopTransform.cpp openjdk-21-21.0.13+9/src/hotspot/share/opto/loopTransform.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/loopTransform.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/loopTransform.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -2576,8 +2576,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)) { @@ -2592,88 +2599,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. @@ -2682,41 +2730,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. @@ -2725,9 +2808,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; } } @@ -2737,27 +2817,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] -// -// 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) { +// 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) +// +// 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; } @@ -2768,59 +2896,110 @@ } 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 = _igvn.integercon(0, exp_bt); + Node* zero = _igvn.integercon(0, bt); set_ctrl(zero, C->root()); - Node *ctrl_off = get_ctrl(offset); - offset = SubNode::make(zero, offset, exp_bt); - register_new_node(offset, ctrl_off); + 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; } @@ -2829,26 +3008,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-21-21.0.12.1+1/src/hotspot/share/opto/loopnode.cpp openjdk-21-21.0.13+9/src/hotspot/share/opto/loopnode.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/loopnode.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/loopnode.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1096,11 +1096,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()) { @@ -1115,6 +1120,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); } @@ -1125,138 +1131,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) { @@ -1281,9 +2205,14 @@ // 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); @@ -1291,144 +2220,183 @@ Node* R = range; Node* K = _igvn.longcon(scale); set_ctrl(K, this->C->root()); - Node* L = offset; - - if (short_scale) { - // This converts: - // (int)i*K + L u64 (long)max_jint and still is root()); - Node* max_range = new AddLNode(max_jint_plus_one_long, L); - register_new_node(max_range, entry_control); - R = MaxNode::unsigned_min(R, max_range, TypeLong::POS, _igvn); - set_subtree_ctrl(R, true); - } - Node* C = outer_phi; - // Start with 64-bit values: - // i*K + L 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 = _igvn.longcon(max_jlong); set_ctrl(max_jlong_long, this->C->root()); - 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)); set_ctrl(K, this->C->root()); 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-21-21.0.12.1+1/src/hotspot/share/opto/loopnode.hpp openjdk-21-21.0.13+9/src/hotspot/share/opto/loopnode.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/loopnode.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/loopnode.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -1322,12 +1322,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)) { @@ -1340,10 +1340,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 IfProjNode* create_new_if_for_predicate(IfProjNode* cont_proj, Node* new_entry, Deoptimization::DeoptReason reason, @@ -1708,7 +1708,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-21-21.0.12.1+1/src/hotspot/share/opto/runtime.cpp openjdk-21-21.0.13+9/src/hotspot/share/opto/runtime.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/runtime.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/runtime.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1081,6 +1081,25 @@ return TypeFunc::make(domain, range); } +// SHAKE128Parallel doubleKeccak function +const TypeFunc* OptoRuntime::double_keccak_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // status0 + fields[argp++] = TypePtr::NOTNULL; // status1 + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + const TypeFunc* OptoRuntime::multiplyToLen_Type() { // create input type (domain) int num_args = 6; @@ -1270,6 +1289,247 @@ return TypeFunc::make(domain, range); } +// Kyber NTT function +const TypeFunc* OptoRuntime::kyberNtt_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + fields[argp++] = TypePtr::NOTNULL; // NTT zetas + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Kyber inverse NTT function +const TypeFunc* OptoRuntime::kyberInverseNtt_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + fields[argp++] = TypePtr::NOTNULL; // inverse NTT zetas + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Kyber NTT multiply function +const TypeFunc* OptoRuntime::kyberNttMult_Type() { + int argcnt = 4; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // result + fields[argp++] = TypePtr::NOTNULL; // ntta + fields[argp++] = TypePtr::NOTNULL; // nttb + fields[argp++] = TypePtr::NOTNULL; // NTT multiply zetas + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Kyber add 2 polynomials function +const TypeFunc* OptoRuntime::kyberAddPoly_2_Type() { + int argcnt = 3; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // result + fields[argp++] = TypePtr::NOTNULL; // a + fields[argp++] = TypePtr::NOTNULL; // b + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + + +// Kyber add 3 polynomials function +const TypeFunc* OptoRuntime::kyberAddPoly_3_Type() { + int argcnt = 4; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // result + fields[argp++] = TypePtr::NOTNULL; // a + fields[argp++] = TypePtr::NOTNULL; // b + fields[argp++] = TypePtr::NOTNULL; // c + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + + +// Kyber XOF output parsing into polynomial coefficients candidates +// or decompress(12,...) function +const TypeFunc* OptoRuntime::kyber12To16_Type() { + int argcnt = 4; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // condensed + fields[argp++] = TypeInt::INT; // condensedOffs + fields[argp++] = TypePtr::NOTNULL; // parsed + fields[argp++] = TypeInt::INT; // parsedLength + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Kyber Barrett reduce function +const TypeFunc* OptoRuntime::kyberBarrettReduce_Type() { + int argcnt = 1; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Dilithium NTT function except for the final "normalization" to |coeff| < Q +const TypeFunc* OptoRuntime::dilithiumAlmostNtt_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + fields[argp++] = TypePtr::NOTNULL; // NTT zetas + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Dilithium inverse NTT function except the final mod Q division by 2^256 +const TypeFunc* OptoRuntime::dilithiumAlmostInverseNtt_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + fields[argp++] = TypePtr::NOTNULL; // inverse NTT zetas + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Dilithium NTT multiply function +const TypeFunc* OptoRuntime::dilithiumNttMult_Type() { + int argcnt = 3; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // result + fields[argp++] = TypePtr::NOTNULL; // ntta + fields[argp++] = TypePtr::NOTNULL; // nttb + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Dilithium Montgomery multiply a polynome coefficient array by a constant +const TypeFunc* OptoRuntime::dilithiumMontMulByConstant_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + fields[argp++] = TypeInt::INT; // constant multiplier + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Dilithium decompose polynomial +const TypeFunc* OptoRuntime::dilithiumDecomposePoly_Type() { + int argcnt = 5; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // input + fields[argp++] = TypePtr::NOTNULL; // lowPart + fields[argp++] = TypePtr::NOTNULL; // highPart + fields[argp++] = TypeInt::INT; // 2 * gamma2 + fields[argp++] = TypeInt::INT; // multiplier + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + // Base64 encode function const TypeFunc* OptoRuntime::base64_encodeBlock_Type() { int argcnt = 6; @@ -1291,6 +1551,7 @@ const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields); return TypeFunc::make(domain, range); } + // Base64 decode function const TypeFunc* OptoRuntime::base64_decodeBlock_Type() { int argcnt = 7; diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/opto/runtime.hpp openjdk-21-21.0.13+9/src/hotspot/share/opto/runtime.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/opto/runtime.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/opto/runtime.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -275,6 +275,7 @@ static const TypeFunc* galoisCounterMode_aescrypt_Type(); static const TypeFunc* digestBase_implCompress_Type(bool is_sha3); + static const TypeFunc* double_keccak_Type(); static const TypeFunc* digestBase_implCompressMB_Type(bool is_sha3); static const TypeFunc* multiplyToLen_Type(); @@ -291,6 +292,18 @@ static const TypeFunc* ghash_processBlocks_Type(); static const TypeFunc* chacha20Block_Type(); + static const TypeFunc* kyberNtt_Type(); + static const TypeFunc* kyberInverseNtt_Type(); + static const TypeFunc* kyberNttMult_Type(); + static const TypeFunc* kyberAddPoly_2_Type(); + static const TypeFunc* kyberAddPoly_3_Type(); + static const TypeFunc* kyber12To16_Type(); + static const TypeFunc* kyberBarrettReduce_Type(); + static const TypeFunc* dilithiumAlmostNtt_Type(); + static const TypeFunc* dilithiumAlmostInverseNtt_Type(); + static const TypeFunc* dilithiumNttMult_Type(); + static const TypeFunc* dilithiumMontMulByConstant_Type(); + static const TypeFunc* dilithiumDecomposePoly_Type(); static const TypeFunc* base64_encodeBlock_Type(); static const TypeFunc* base64_decodeBlock_Type(); static const TypeFunc* poly1305_processBlocks_Type(); diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/prims/jvm.cpp openjdk-21-21.0.13+9/src/hotspot/share/prims/jvm.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/prims/jvm.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/prims/jvm.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -3257,9 +3257,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-21-21.0.12.1+1/src/hotspot/share/runtime/globals.hpp openjdk-21-21.0.13+9/src/hotspot/share/runtime/globals.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/runtime/globals.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/runtime/globals.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -332,6 +332,12 @@ product(bool, UseChaCha20Intrinsics, false, DIAGNOSTIC, \ "Use intrinsics for the vectorized version of ChaCha20") \ \ + product(bool, UseKyberIntrinsics, false, DIAGNOSTIC, \ + "Use intrinsics for the vectorized version of Kyber") \ + \ + product(bool, UseDilithiumIntrinsics, false, DIAGNOSTIC, \ + "Use intrinsics for the vectorized version of Dilithium") \ + \ product(bool, UseMD5Intrinsics, false, DIAGNOSTIC, \ "Use intrinsics for MD5 crypto hash function") \ \ diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/runtime/os.cpp openjdk-21-21.0.13+9/src/hotspot/share/runtime/os.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/runtime/os.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/runtime/os.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -198,9 +198,9 @@ abs_local_to_UTC = -(abs_local_to_UTC); } // Convert time zone offset seconds to hours and minutes. - const time_t zone_hours = (abs_local_to_UTC / seconds_per_hour); - const time_t zone_min = - ((abs_local_to_UTC % seconds_per_hour) / seconds_per_minute); + const int zone_hours = static_cast(abs_local_to_UTC / seconds_per_hour); + const int zone_min = + static_cast((abs_local_to_UTC % seconds_per_hour) / seconds_per_minute); // Print an ISO 8601 date and time stamp into the buffer const int year = 1900 + time_struct.tm_year; diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/runtime/stubRoutines.cpp openjdk-21-21.0.13+9/src/hotspot/share/runtime/stubRoutines.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/runtime/stubRoutines.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/runtime/stubRoutines.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -127,6 +127,18 @@ address StubRoutines::_galoisCounterMode_AESCrypt = nullptr; address StubRoutines::_ghash_processBlocks = nullptr; address StubRoutines::_chacha20Block = nullptr; +address StubRoutines::_kyberNtt = nullptr; +address StubRoutines::_kyberInverseNtt = nullptr; +address StubRoutines::_kyberNttMult = nullptr; +address StubRoutines::_kyberAddPoly_2 = nullptr; +address StubRoutines::_kyberAddPoly_3 = nullptr; +address StubRoutines::_kyber12To16 = nullptr; +address StubRoutines::_kyberBarrettReduce = nullptr; +address StubRoutines::_dilithiumAlmostNtt = nullptr; +address StubRoutines::_dilithiumAlmostInverseNtt = nullptr; +address StubRoutines::_dilithiumNttMult = nullptr; +address StubRoutines::_dilithiumMontMulByConstant = nullptr; +address StubRoutines::_dilithiumDecomposePoly = nullptr; address StubRoutines::_base64_encodeBlock = nullptr; address StubRoutines::_base64_decodeBlock = nullptr; address StubRoutines::_poly1305_processBlocks = nullptr; @@ -140,6 +152,7 @@ address StubRoutines::_sha512_implCompress = nullptr; address StubRoutines::_sha512_implCompressMB = nullptr; address StubRoutines::_sha3_implCompress = nullptr; +address StubRoutines::_double_keccak = nullptr; address StubRoutines::_sha3_implCompressMB = nullptr; address StubRoutines::_updateBytesCRC32 = nullptr; diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/runtime/stubRoutines.hpp openjdk-21-21.0.13+9/src/hotspot/share/runtime/stubRoutines.hpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/runtime/stubRoutines.hpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/runtime/stubRoutines.hpp 2026-10-19 12:10:20.000000000 +0000 @@ -207,6 +207,18 @@ static address _galoisCounterMode_AESCrypt; static address _ghash_processBlocks; static address _chacha20Block; + static address _kyberNtt; + static address _kyberInverseNtt; + static address _kyberNttMult; + static address _kyberAddPoly_2; + static address _kyberAddPoly_3; + static address _kyber12To16; + static address _kyberBarrettReduce; + static address _dilithiumAlmostNtt; + static address _dilithiumAlmostInverseNtt; + static address _dilithiumNttMult; + static address _dilithiumMontMulByConstant; + static address _dilithiumDecomposePoly; static address _base64_encodeBlock; static address _base64_decodeBlock; static address _poly1305_processBlocks; @@ -220,6 +232,7 @@ static address _sha512_implCompress; static address _sha512_implCompressMB; static address _sha3_implCompress; + static address _double_keccak; static address _sha3_implCompressMB; static address _updateBytesCRC32; @@ -396,6 +409,18 @@ static address counterMode_AESCrypt() { return _counterMode_AESCrypt; } static address ghash_processBlocks() { return _ghash_processBlocks; } static address chacha20Block() { return _chacha20Block; } + static address kyberNtt() { return _kyberNtt; } + static address kyberInverseNtt() { return _kyberInverseNtt; } + static address kyberNttMult() { return _kyberNttMult; } + static address kyberAddPoly_2() { return _kyberAddPoly_2; } + static address kyberAddPoly_3() { return _kyberAddPoly_3; } + static address kyber12To16() { return _kyber12To16; } + static address kyberBarrettReduce() { return _kyberBarrettReduce; } + static address dilithiumAlmostNtt() { return _dilithiumAlmostNtt; } + static address dilithiumAlmostInverseNtt() { return _dilithiumAlmostInverseNtt; } + static address dilithiumNttMult() { return _dilithiumNttMult; } + static address dilithiumMontMulByConstant() { return _dilithiumMontMulByConstant; } + static address dilithiumDecomposePoly() { return _dilithiumDecomposePoly; } static address base64_encodeBlock() { return _base64_encodeBlock; } static address base64_decodeBlock() { return _base64_decodeBlock; } static address md5_implCompress() { return _md5_implCompress; } @@ -407,6 +432,7 @@ static address sha512_implCompress() { return _sha512_implCompress; } static address sha512_implCompressMB() { return _sha512_implCompressMB; } static address sha3_implCompress() { return _sha3_implCompress; } + static address double_keccak() { return _double_keccak; } static address sha3_implCompressMB() { return _sha3_implCompressMB; } static address updateBytesCRC32() { return _updateBytesCRC32; } diff -Nru openjdk-21-21.0.12.1+1/src/hotspot/share/runtime/threads.cpp openjdk-21-21.0.13+9/src/hotspot/share/runtime/threads.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/runtime/threads.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/runtime/threads.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -1306,10 +1306,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-21-21.0.12.1+1/src/hotspot/share/runtime/vmStructs.cpp openjdk-21-21.0.13+9/src/hotspot/share/runtime/vmStructs.cpp --- openjdk-21-21.0.12.1+1/src/hotspot/share/runtime/vmStructs.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/hotspot/share/runtime/vmStructs.cpp 2026-10-19 12:10:20.000000000 +0000 @@ -540,6 +540,18 @@ static_field(StubRoutines, _galoisCounterMode_AESCrypt, address) \ static_field(StubRoutines, _ghash_processBlocks, address) \ static_field(StubRoutines, _chacha20Block, address) \ + static_field(StubRoutines, _kyberNtt, address) \ + static_field(StubRoutines, _kyberInverseNtt, address) \ + static_field(StubRoutines, _kyberNttMult, address) \ + static_field(StubRoutines, _kyberAddPoly_2, address) \ + static_field(StubRoutines, _kyberAddPoly_3, address) \ + static_field(StubRoutines, _kyber12To16, address) \ + static_field(StubRoutines, _kyberBarrettReduce, address) \ + static_field(StubRoutines, _dilithiumAlmostNtt, address) \ + static_field(StubRoutines, _dilithiumAlmostInverseNtt, address) \ + static_field(StubRoutines, _dilithiumNttMult, address) \ + static_field(StubRoutines, _dilithiumMontMulByConstant, address) \ + static_field(StubRoutines, _dilithiumDecomposePoly, address) \ static_field(StubRoutines, _base64_encodeBlock, address) \ static_field(StubRoutines, _base64_decodeBlock, address) \ static_field(StubRoutines, _poly1305_processBlocks, address) \ @@ -548,6 +560,7 @@ static_field(StubRoutines, _crc32c_table_addr, address) \ static_field(StubRoutines, _updateBytesCRC32C, address) \ static_field(StubRoutines, _updateBytesAdler32, address) \ + static_field(StubRoutines, _double_keccak, address) \ static_field(StubRoutines, _multiplyToLen, address) \ static_field(StubRoutines, _squareToLen, address) \ static_field(StubRoutines, _bigIntegerRightShiftWorker, address) \ diff -Nru openjdk-21-21.0.12.1+1/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c openjdk-21-21.0.13+9/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c --- openjdk-21-21.0.12.1+1/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c 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 @@ -63,7 +63,7 @@ if (n < 0) { if (errno == EAGAIN) return IOS_UNAVAILABLE; - if (errno == ENOSYS) + if (errno == ENOSYS || errno == EOPNOTSUPP) return IOS_UNSUPPORTED_CASE; if ((errno == EBADF || errno == EINVAL || errno == EXDEV) && ((ssize_t)count >= 0)) @@ -103,6 +103,7 @@ case EINVAL: case ENOSYS: case EXDEV: + case EOPNOTSUPP: // ignore and try sendfile() break; default: diff -Nru openjdk-21-21.0.12.1+1/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c openjdk-21-21.0.13+9/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c --- openjdk-21-21.0.12.1+1/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -199,6 +199,7 @@ case EINVAL: case ENOSYS: case EXDEV: + case EOPNOTSUPP: // ignore and try sendfile() break; default: diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java openjdk-21-21.0.13+9/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.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, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -393,11 +393,10 @@ throw new NoSuchAlgorithmException("null algorithm"); } - if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") && - !AllowKDF.VALUE) { - - throw new NoSuchAlgorithmException("Unsupported secret key " - + "algorithm: " + algorithm); + if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm) && + !AllowKDF.VALUE) { + throw new NoSuchAlgorithmException( + "Unsupported secret key algorithm: " + algorithm); } byte[] secret = engineGenerateSecret(); @@ -435,13 +434,17 @@ throw new InvalidKeyException("Key material is too short"); } return skey; - } else if (algorithm.equals("TlsPremasterSecret")) { - // remove leading zero bytes per RFC 5246 Section 8.1.2 - return new SecretKeySpec( + } else if (KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) { + if (algorithm.equalsIgnoreCase("TlsPremasterSecret")) { + // remove leading zero bytes per RFC 5246 Section 8.1.2 + return new SecretKeySpec( KeyUtil.trimZeroes(secret), "TlsPremasterSecret"); + } else { + return new SecretKeySpec(secret, algorithm); + } } else { - throw new NoSuchAlgorithmException("Unsupported secret key " - + "algorithm: "+ algorithm); + throw new NoSuchAlgorithmException( + "Unsupported secret key algorithm: " + algorithm); } } } diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java openjdk-21-21.0.13+9/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1642,8 +1642,9 @@ NIO_ACCESS.acquireSession(dst); try { Unsafe.getUnsafe().setMemory( - ((DirectBuffer)dst).address(), - len + dst.position(), (byte) 0); + ((DirectBuffer)dst).address() + + dst.position(), + len, (byte) 0); } finally { NIO_ACCESS.releaseSession(dst); } diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java openjdk-21-21.0.13+9/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,1574 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.crypto.provider; + +import java.security.*; +import java.util.Arrays; +import javax.crypto.DecapsulateException; +import jdk.internal.vm.annotation.IntrinsicCandidate; + +import sun.security.provider.SHA3.SHAKE256; +import sun.security.provider.SHA3Parallel.Shake128Parallel; + +public final class ML_KEM { + + public static final int SECRET_SIZE = 32; + private static final String HASH_H_NAME = "SHA3-256"; + private static final String HASH_G_NAME = "SHA3-512"; + + private static final int ML_KEM_Q = 3329; + private static final int ML_KEM_N = 256; + + private static final int XOF_BLOCK_LEN = 168; // the block length for SHAKE128 + private static final int XOF_PAD = 24; + private static final int MONT_R_BITS = 20; + private static final int MONT_Q = 3329; + private static final int MONT_R_SQUARE_MOD_Q = 152; + private static final int MONT_Q_INV_MOD_R = 586497; + + // toMont((ML_KEM_N / 2)^-1 mod ML_KEM_Q) using R = 2^MONT_R_BITS + private static final int MONT_DIM_HALF_INVERSE = 1534; + private static final int BARRETT_MULTIPLIER = 20159; + private static final int BARRETT_SHIFT = 26; + private static final int[] MONT_ZETAS_FOR_NTT = new int[]{ + 1188, 914, -969, 585, -551, 1263, -97, 593, + -35, -1400, -417, -1253, 742, -281, 185, -819, + -1226, 895, -530, 52, 25, 1000, 1249, -909, + -373, -1604, -259, -1369, -82, 49, 1496, -406, + 445, 1155, -405, -714, 553, -1183, -1401, 1598, + -128, 1538, -669, 744, 1382, -1313, 201, -332, + -1440, -1007, -36, -1617, 567, -623, 1429, 290, + -1269, -825, -1613, 510, -395, 845, -426, -1003, + 222, -1107, 172, -42, 620, 1497, -1649, 94, + -595, -497, -431, -1327, -702, -1448, -184, -607, + -868, -1430, 977, 884, 425, 355, 1259, 1192, + 317, -636, -1074, 30, -1394, 833, -1200, -244, + 907, -339, -227, 1178, -586, -137, -514, 534, + 1153, -486, -1386, -668, 191, 982, 88, 1014, + -1177, -474, -612, -857, -348, -604, 990, 1601, + -1599, -709, -789, -1317, -57, 1049, -584 + }; + + private static final short[] montZetasForVectorNttArr = new short[]{ + // level 0 + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + // level 1 + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + // level 2 + 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, + 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, + 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, + 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, + 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, + 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, + 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, + 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, + 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, + 202, 202, 202, 202, 202, 202, 202, 202, + 202, 202, 202, 202, 202, 202, 202, 202, + 202, 202, 202, 202, 202, 202, 202, 202, + 202, 202, 202, 202, 202, 202, 202, 202, + // level 3 + -171, -171, -171, -171, -171, -171, -171, -171, + -171, -171, -171, -171, -171, -171, -171, -171, + 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 622, 622, 622, 622, 622, + 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, + 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, + 182, 182, 182, 182, 182, 182, 182, 182, + 182, 182, 182, 182, 182, 182, 182, 182, + 962, 962, 962, 962, 962, 962, 962, 962, + 962, 962, 962, 962, 962, 962, 962, 962, + -1202, -1202, -1202, -1202, -1202, -1202, -1202, -1202, + -1202, -1202, -1202, -1202, -1202, -1202, -1202, -1202, + -1474, -1474, -1474, -1474, -1474, -1474, -1474, -1474, + -1474, -1474, -1474, -1474, -1474, -1474, -1474, -1474, + 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, + 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, + // level 4 + 573, 573, 573, 573, 573, 573, 573, 573, + -1325, -1325, -1325, -1325, -1325, -1325, -1325, -1325, + 264, 264, 264, 264, 264, 264, 264, 264, + 383, 383, 383, 383, 383, 383, 383, 383, + -829, -829, -829, -829, -829, -829, -829, -829, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + -1602, -1602, -1602, -1602, -1602, -1602, -1602, -1602, + -130, -130, -130, -130, -130, -130, -130, -130, + -681, -681, -681, -681, -681, -681, -681, -681, + 1017, 1017, 1017, 1017, 1017, 1017, 1017, 1017, + 732, 732, 732, 732, 732, 732, 732, 732, + 608, 608, 608, 608, 608, 608, 608, 608, + -1542, -1542, -1542, -1542, -1542, -1542, -1542, -1542, + 411, 411, 411, 411, 411, 411, 411, 411, + -205, -205, -205, -205, -205, -205, -205, -205, + -1571, -1571, -1571, -1571, -1571, -1571, -1571, -1571, + // level 5 + 1223, 1223, 1223, 1223, 652, 652, 652, 652, + -552, -552, -552, -552, 1015, 1015, 1015, 1015, + -1293, -1293, -1293, -1293, 1491, 1491, 1491, 1491, + -282, -282, -282, -282, -1544, -1544, -1544, -1544, + 516, 516, 516, 516, -8, -8, -8, -8, + -320, -320, -320, -320, -666, -666, -666, -666, + 1711, 1711, 1711, 1711, -1162, -1162, -1162, -1162, + 126, 126, 126, 126, 1469, 1469, 1469, 1469, + -853, -853, -853, -853, -90, -90, -90, -90, + -271, -271, -271, -271, 830, 830, 830, 830, + 107, 107, 107, 107, -1421, -1421, -1421, -1421, + -247, -247, -247, -247, -951, -951, -951, -951, + -398, -398, -398, -398, 961, 961, 961, 961, + -1508, -1508, -1508, -1508, -725, -725, -725, -725, + 448, 448, 448, 448, -1065, -1065, -1065, -1065, + 677, 677, 677, 677, -1275, -1275, -1275, -1275, + // level 6 + -1103, -1103, 430, 430, 555, 555, 843, 843, + -1251, -1251, 871, 871, 1550, 1550, 105, 105, + 422, 422, 587, 587, 177, 177, -235, -235, + -291, -291, -460, -460, 1574, 1574, 1653, 1653, + -246, -246, 778, 778, 1159, 1159, -147, -147, + -777, -777, 1483, 1483, -602, -602, 1119, 1119, + -1590, -1590, 644, 644, -872, -872, 349, 349, + 418, 418, 329, 329, -156, -156, -75, -75, + 817, 817, 1097, 1097, 603, 603, 610, 610, + 1322, 1322, -1285, -1285, -1465, -1465, 384, 384, + -1215, -1215, -136, -136, 1218, 1218, -1335, -1335, + -874, -874, 220, 220, -1187, -1187, 1670, 1670, + -1185, -1185, -1530, -1530, -1278, -1278, 794, 794, + -1510, -1510, -854, -854, -870, -870, 478, 478, + -108, -108, -308, -308, 996, 996, 991, 991, + 958, 958, -1460, -1460, 1522, 1522, 1628, 1628 + }; + private static final int[] MONT_ZETAS_FOR_INVERSE_NTT = new int[]{ + 584, -1049, 57, 1317, 789, 709, 1599, -1601, + -990, 604, 348, 857, 612, 474, 1177, -1014, + -88, -982, -191, 668, 1386, 486, -1153, -534, + 514, 137, 586, -1178, 227, 339, -907, 244, + 1200, -833, 1394, -30, 1074, 636, -317, -1192, + -1259, -355, -425, -884, -977, 1430, 868, 607, + 184, 1448, 702, 1327, 431, 497, 595, -94, + 1649, -1497, -620, 42, -172, 1107, -222, 1003, + 426, -845, 395, -510, 1613, 825, 1269, -290, + -1429, 623, -567, 1617, 36, 1007, 1440, 332, + -201, 1313, -1382, -744, 669, -1538, 128, -1598, + 1401, 1183, -553, 714, 405, -1155, -445, 406, + -1496, -49, 82, 1369, 259, 1604, 373, 909, + -1249, -1000, -25, -52, 530, -895, 1226, 819, + -185, 281, -742, 1253, 417, 1400, 35, -593, + 97, -1263, 551, -585, 969, -914, -1188 + }; + + private static final short[] montZetasForVectorInverseNttArr = new short[]{ + // level 0 + -1628, -1628, -1522, -1522, 1460, 1460, -958, -958, + -991, -991, -996, -996, 308, 308, 108, 108, + -478, -478, 870, 870, 854, 854, 1510, 1510, + -794, -794, 1278, 1278, 1530, 1530, 1185, 1185, + 1659, 1659, 1187, 1187, -220, -220, 874, 874, + 1335, 1335, -1218, -1218, 136, 136, 1215, 1215, + -384, -384, 1465, 1465, 1285, 1285, -1322, -1322, + -610, -610, -603, -603, -1097, -1097, -817, -817, + 75, 75, 156, 156, -329, -329, -418, -418, + -349, -349, 872, 872, -644, -644, 1590, 1590, + -1119, -1119, 602, 602, -1483, -1483, 777, 777, + 147, 147, -1159, -1159, -778, -778, 246, 246, + -1653, -1653, -1574, -1574, 460, 460, 291, 291, + 235, 235, -177, -177, -587, -587, -422, -422, + -105, -105, -1550, -1550, -871, -871, 1251, 1251, + -843, -843, -555, -555, -430, -430, 1103, 1103, + // level 1 + 1275, 1275, 1275, 1275, -677, -677, -677, -677, + 1065, 1065, 1065, 1065, -448, -448, -448, -448, + 725, 725, 725, 725, 1508, 1508, 1508, 1508, + -961, -961, -961, -961, 398, 398, 398, 398, + 951, 951, 951, 951, 247, 247, 247, 247, + 1421, 1421, 1421, 1421, -107, -107, -107, -107, + -830, -830, -830, -830, 271, 271, 271, 271, + 90, 90, 90, 90, 853, 853, 853, 853, + -1469, -1469, -1469, -1469, -126, -126, -126, -126, + 1162, 1162, 1162, 1162, 1618, 1618, 1618, 1618, + 666, 666, 666, 666, 320, 320, 320, 320, + 8, 8, 8, 8, -516, -516, -516, -516, + 1544, 1544, 1544, 1544, 282, 282, 282, 282, + -1491, -1491, -1491, -1491, 1293, 1293, 1293, 1293, + -1015, -1015, -1015, -1015, 552, 552, 552, 552, + -652, -652, -652, -652, -1223, -1223, -1223, -1223, + // level 2 + 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, + 205, 205, 205, 205, 205, 205, 205, 205, + -411, -411, -411, -411, -411, -411, -411, -411, + 1542, 1542, 1542, 1542, 1542, 1542, 1542, 1542, + -608, -608, -608, -608, -608, -608, -608, -608, + -732, -732, -732, -732, -732, -732, -732, -732, + -1017, -1017, -1017, -1017, -1017, -1017, -1017, -1017, + 681, 681, 681, 681, 681, 681, 681, 681, + 130, 130, 130, 130, 130, 130, 130, 130, + 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, + -1458, -1458, -1458, -1458, -1458, -1458, -1458, -1458, + 829, 829, 829, 829, 829, 829, 829, 829, + -383, -383, -383, -383, -383, -383, -383, -383, + -264, -264, -264, -264, -264, -264, -264, -264, + 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, + -573, -573, -573, -573, -573, -573, -573, -573, + // level 3 + -1468, -1468, -1468, -1468, -1468, -1468, -1468, -1468, + -1468, -1468, -1468, -1468, -1468, -1468, -1468, -1468, + 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, + 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, + 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, + 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, + -962, -962, -962, -962, -962, -962, -962, -962, + -962, -962, -962, -962, -962, -962, -962, -962, + -182, -182, -182, -182, -182, -182, -182, -182, + -182, -182, -182, -182, -182, -182, -182, -182, + -1577, -1577, -1577, -1577, -1577, -1577, -1577, -1577, + -1577, -1577, -1577, -1577, -1577, -1577, -1577, -1577, + -622, -622, -622, -622, -622, -622, -622, -622, + -622, -622, -622, -622, -622, -622, -622, -622, + 171, 171, 171, 171, 171, 171, 171, 171, + 171, 171, 171, 171, 171, 171, 171, 171, + // level 4 + -202, -202, -202, -202, -202, -202, -202, -202, + -202, -202, -202, -202, -202, -202, -202, -202, + -202, -202, -202, -202, -202, -202, -202, -202, + -202, -202, -202, -202, -202, -202, -202, -202, + -287, -287, -287, -287, -287, -287, -287, -287, + -287, -287, -287, -287, -287, -287, -287, -287, + -287, -287, -287, -287, -287, -287, -287, -287, + -287, -287, -287, -287, -287, -287, -287, -287, + -1422, -1422, -1422, -1422, -1422, -1422, -1422, -1422, + -1422, -1422, -1422, -1422, -1422, -1422, -1422, -1422, + -1422, -1422, -1422, -1422, -1422, -1422, -1422, -1422, + -1422, -1422, -1422, -1422, -1422, -1422, -1422, -1422, + -1493, -1493, -1493, -1493, -1493, -1493, -1493, -1493, + -1493, -1493, -1493, -1493, -1493, -1493, -1493, -1493, + -1493, -1493, -1493, -1493, -1493, -1493, -1493, -1493, + -1493, -1493, -1493, -1493, -1493, -1493, -1493, -1493, + // level 5 + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + // level 6 + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758 + }; + + private static final int[] MONT_ZETAS_FOR_NTT_MULT = new int[]{ + -1003, 1003, 222, -222, -1107, 1107, 172, -172, + -42, 42, 620, -620, 1497, -1497, -1649, 1649, + 94, -94, -595, 595, -497, 497, -431, 431, + -1327, 1327, -702, 702, -1448, 1448, -184, 184, + -607, 607, -868, 868, -1430, 1430, 977, -977, + 884, -884, 425, -425, 355, -355, 1259, -1259, + 1192, -1192, 317, -317, -636, 636, -1074, 1074, + 30, -30, -1394, 1394, 833, -833, -1200, 1200, + -244, 244, 907, -907, -339, 339, -227, 227, + 1178, -1178, -586, 586, -137, 137, -514, 514, + 534, -534, 1153, -1153, -486, 486, -1386, 1386, + -668, 668, 191, -191, 982, -982, 88, -88, + 1014, -1014, -1177, 1177, -474, 474, -612, 612, + -857, 857, -348, 348, -604, 604, 990, -990, + 1601, -1601, -1599, 1599, -709, 709, -789, 789, + -1317, 1317, -57, 57, 1049, -1049, -584, 584 + }; + private static final short[] montZetasForVectorNttMultArr = new short[]{ + -1103, 1103, 430, -430, 555, -555, 843, -843, + -1251, 1251, 871, -871, 1550, -1550, 105, -105, + 422, -422, 587, -587, 177, -177, -235, 235, + -291, 291, -460, 460, 1574, -1574, 1653, -1653, + -246, 246, 778, -778, 1159, -1159, -147, 147, + -777, 777, 1483, -1483, -602, 602, 1119, -1119, + -1590, 1590, 644, -644, -872, 872, 349, -349, + 418, -418, 329, -329, -156, 156, -75, 75, + 817, -817, 1097, -1097, 603, -603, 610, -610, + 1322, -1322, -1285, 1285, -1465, 1465, 384, -384, + -1215, 1215, -136, 136, 1218, -1218, -1335, 1335, + -874, 874, 220, -220, -1187, 1187, 1670, 1659, + -1185, 1185, -1530, 1530, -1278, 1278, 794, -794, + -1510, 1510, -854, 854, -870, 870, 478, -478, + -108, 108, -308, 308, 996, -996, 991, -991, + 958, -958, -1460, 1460, 1522, -1522, 1628, -1628 + }; + + private final int mlKem_k; + private final int mlKem_eta1; + private final int mlKem_eta2; + + private final int mlKem_du; + private final int mlKem_dv; + private final int encapsulationSize; + + public ML_KEM(String name) { + switch (name) { + case "ML-KEM-512" -> { + mlKem_k = 2; + mlKem_eta1 = 3; + mlKem_eta2 = 2; + mlKem_du = 10; + mlKem_dv = 4; + } + case "ML-KEM-768" -> { + mlKem_k = 3; + mlKem_eta1 = 2; + mlKem_eta2 = 2; + mlKem_du = 10; + mlKem_dv = 4; + } + case "ML-KEM-1024" -> { + mlKem_k = 4; + mlKem_eta1 = 2; + mlKem_eta2 = 2; + mlKem_du = 11; + mlKem_dv = 5; + } + default -> throw new IllegalArgumentException( + // This should never happen. + "Invalid algorithm name (" + name + ")."); + } + encapsulationSize = (mlKem_k * mlKem_du + mlKem_dv) * 32; + } + + /* + Classes for the internal K_PKE scheme + */ + private record K_PKE_EncryptionKey(byte[] keyBytes) {} + + private record K_PKE_DecryptionKey(byte[] keyBytes) {} + + private record K_PKE_KeyPair( + K_PKE_EncryptionKey publicKey, K_PKE_DecryptionKey privateKey) { + } + + protected record K_PKE_CipherText(byte[] encryptedBytes) { + } + + private boolean isValidCipherText(K_PKE_CipherText cipherText) { + return (cipherText.encryptedBytes.length == encapsulationSize); + } + + /* + Classes for internal KEM scheme + */ + protected record ML_KEM_EncapsulationKey(byte[] keyBytes) { + } + + protected record ML_KEM_DecapsulationKey(byte[] keyBytes) { + } + + protected record ML_KEM_KeyPair( + ML_KEM_EncapsulationKey encapsulationKey, + ML_KEM_DecapsulationKey decapsulationKey) { + } + + protected record ML_KEM_EncapsulateResult( + K_PKE_CipherText cipherText, byte[] sharedSecret) { + } + + protected int getEncapsulationSize() { + return encapsulationSize; + } + + // Encapsulation key checks from section 7.2 of spec + protected Object checkPublicKey(byte[] pk) throws InvalidKeyException { + //Encapsulation key type check + if (pk.length != mlKem_k * 384 + 32) { + throw new InvalidKeyException("Public key is not the correct size"); + } + + //Encapsulation key modulus check + int x, y, z, a, b; + for (int i = 0; i < mlKem_k * 384; i += 3) { + x = pk[i] & 0xFF; + y = pk[i + 1] & 0xFF; + z = pk[i + 2] & 0xFF; + a = x + ((y & 0xF) << 8); + b = (y >> 4) + (z << 4); + if ((a >= ML_KEM_Q) || (b >= ML_KEM_Q)) { + throw new InvalidKeyException( + "Coefficients in public key not in specified range"); + } + } + return null; + } + + // Decapsulation key checks from Section 7.3 of spec + protected Object checkPrivateKey(byte[] sk) throws InvalidKeyException { + MessageDigest mlKemH; + try { + mlKemH = MessageDigest.getInstance(HASH_H_NAME); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + + //Decapsulation key type check + if (sk.length != mlKem_k * 768 + 96) { + throw new InvalidKeyException("Private key is not the correct size"); + } + + //Decapsulation hash check + mlKemH.update(sk, mlKem_k * 384, mlKem_k * 384 + 32); + byte[] check = Arrays.copyOfRange(sk, mlKem_k * 768 + 32, mlKem_k * 768 + 64); + if (!MessageDigest.isEqual(mlKemH.digest(), check)) { + throw new InvalidKeyException("Private key hash check failed"); + } + return null; + } + + /* + Main internal algorithms from Section 6 of specification + */ + protected ML_KEM_KeyPair generateKemKeyPair(byte[] kem_d_z) { + MessageDigest mlKemH; + try { + mlKemH = MessageDigest.getInstance(HASH_H_NAME); + } catch (NoSuchAlgorithmException e) { + // This should never happen. + throw new RuntimeException(e); + } + + //Generate K-PKE keys + //The 1st 32-byte `d` is used in K-PKE key pair generation + var kPkeKeyPair = generateK_PkeKeyPair(kem_d_z); + //encaps key = kPke encryption key + byte[] encapsKey = kPkeKeyPair.publicKey.keyBytes; + + //Derive decapsulation key = kPkePrivatKey || encapsKey || H(encapsKey) || kem_Z + byte[] kPkePrivateKey = kPkeKeyPair.privateKey.keyBytes; + byte[] decapsKey = new byte[encapsKey.length + kPkePrivateKey.length + 64]; + System.arraycopy(kPkePrivateKey, 0, decapsKey, 0, kPkePrivateKey.length); + Arrays.fill(kPkePrivateKey, (byte)0); + System.arraycopy(encapsKey, 0, decapsKey, + kPkePrivateKey.length, encapsKey.length); + + mlKemH.update(encapsKey); + try { + mlKemH.digest(decapsKey, kPkePrivateKey.length + encapsKey.length, 32); + } catch (DigestException e) { + // This should never happen. + throw new RuntimeException(e); + } + // The 2nd 32-byte `z` is copied into decapsKey + System.arraycopy(kem_d_z, 32, decapsKey, + kPkePrivateKey.length + encapsKey.length + 32, 32); + + return new ML_KEM_KeyPair( + new ML_KEM_EncapsulationKey(encapsKey), + new ML_KEM_DecapsulationKey(decapsKey)); + } + + public byte[] privKeyToPubKey(byte[] decapsKey) { + int pkLen = (mlKem_k * ML_KEM_N * 12) / 8 + 32 /* rho */; + int skLen = (mlKem_k * ML_KEM_N * 12) / 8; + return Arrays.copyOfRange(decapsKey, skLen, skLen + pkLen); + } + + protected ML_KEM_EncapsulateResult encapsulate( + ML_KEM_EncapsulationKey encapsulationKey, byte[] randomMessage) { + MessageDigest mlKemH; + MessageDigest mlKemG; + try { + mlKemH = MessageDigest.getInstance(HASH_H_NAME); + mlKemG = MessageDigest.getInstance(HASH_G_NAME); + } catch (NoSuchAlgorithmException e) { + // This should never happen. + throw new RuntimeException(e); + } + + mlKemH.update(encapsulationKey.keyBytes); + mlKemG.update(randomMessage); + mlKemG.update(mlKemH.digest()); + var kHatAndRandomCoins = mlKemG.digest(); + 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); + + return new ML_KEM_EncapsulateResult(cipherText, sharedSecret); + } + + protected byte[] decapsulate(ML_KEM_DecapsulationKey decapsulationKey, + K_PKE_CipherText cipherText) + throws DecapsulateException { + + //Check ciphertext validity + if (!isValidCipherText(cipherText)) { + throw new DecapsulateException("Invalid ciphertext"); + } + + int encode12PolyLen = 12 * ML_KEM_N / 8; + var decapsKeyBytes = decapsulationKey.keyBytes; + MessageDigest mlKemG; + SHAKE256 mlKemJ; + try { + mlKemG = MessageDigest.getInstance(HASH_G_NAME); + mlKemJ = new SHAKE256(32); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + + byte[] kPkePrivateKeyBytes = new byte[mlKem_k * encode12PolyLen]; + System.arraycopy(decapsKeyBytes, 0, kPkePrivateKeyBytes, 0, + kPkePrivateKeyBytes.length); + + byte[] encapsKeyBytes = new byte[mlKem_k * encode12PolyLen + 32]; + System.arraycopy(decapsKeyBytes, mlKem_k * encode12PolyLen, + encapsKeyBytes, 0, encapsKeyBytes.length); + var mCandidate = kPkeDecrypt( + new K_PKE_DecryptionKey(kPkePrivateKeyBytes), cipherText); + mlKemG.update(mCandidate); + mlKemG.update(decapsKeyBytes, decapsKeyBytes.length - 64, 32); + var kAndCoins = mlKemG.digest(); + var realResult = Arrays.copyOfRange(kAndCoins, 0, 32); + var coins = Arrays.copyOfRange(kAndCoins, 32, 64); + + // Zero out unused byte arrays containing sensitive data + Arrays.fill(kPkePrivateKeyBytes, (byte) 0); + Arrays.fill(kAndCoins, (byte) 0); + + mlKemJ.update(decapsKeyBytes, decapsKeyBytes.length - 32, 32); + mlKemJ.update(cipherText.encryptedBytes); + var fakeResult = mlKemJ.digest(); + var computedCipherText = kPkeEncrypt( + new K_PKE_EncryptionKey(encapsKeyBytes), mCandidate, coins); + + // The rest of this method implements the following in constant time + // + // if (Arrays.equals(cipherText.encryptedBytes, + // computedCipherText.encryptedBytes)) { + // return realResult; + // } else { + // return fakeResult; + // } + + int mask = 0; + byte[] origCiphertestBytes = cipherText.encryptedBytes; + byte[] compCipherTextBytes = computedCipherText.encryptedBytes; + for (int i = 0; i < cipherText.encryptedBytes.length; i++) { + mask |= (origCiphertestBytes[i] ^ compCipherTextBytes[i]); + } + mask = - (mask & 0xff); // sets mask to negative or 0 + mask >>= 31; // sets mask to all 1-bits or all 0-bits + int notMask = ~mask; + + byte[] result = realResult; + for (int i = 0; i < realResult.length; i ++) { + result[i] = (byte)((notMask & realResult[i]) | (mask & fakeResult[i])); + } + + return result; + } + + /* + K-PKE subroutines defined in Section 5 of spec + */ + private K_PKE_KeyPair generateK_PkeKeyPair(byte[] seed) { + + MessageDigest mlKemG; + SHAKE256 mlKemJ; + try { + mlKemG = MessageDigest.getInstance(HASH_G_NAME); + mlKemJ = new SHAKE256(64 * mlKem_eta1); + } catch (NoSuchAlgorithmException e) { + // This should never happen. + throw new RuntimeException(e); + } + + // Note: only the 1st 32-byte in the seed is used + mlKemG.update(seed, 0, 32); + mlKemG.update((byte)mlKem_k); + + var rhoSigma = mlKemG.digest(); + mlKemG.reset(); + var rho = Arrays.copyOfRange(rhoSigma, 0, 32); + var sigma = Arrays.copyOfRange(rhoSigma, 32, 64); + Arrays.fill(rhoSigma, (byte)0); + + var keyGenA = generateA(rho, false); + + 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); + } + Arrays.fill(sigma, (byte)0); + + short[][] keyGenSHat = mlKemVectorNTT(keyGenS); + mlKemVectorReduce(keyGenSHat); + short[][] keyGenEHat = mlKemVectorNTT(keyGenE); + + short[][] keyGenTHat = + mlKemMatrixVectorMuladd(keyGenA, keyGenSHat, keyGenEHat); + + byte[] pkEncoded = new byte[(mlKem_k * ML_KEM_N * 12) / 8 + rho.length]; + byte[] skEncoded = new byte[(mlKem_k * ML_KEM_N * 12) / 8]; + 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, + pkEncoded, (mlKem_k * ML_KEM_N * 12) / 8, rho.length); + + return new K_PKE_KeyPair( + new K_PKE_EncryptionKey(pkEncoded), + new K_PKE_DecryptionKey(skEncoded)); + } + + private K_PKE_CipherText kPkeEncrypt( + K_PKE_EncryptionKey publicKey, byte[] message, byte[] sigma) { + short[][] zeroes = shortMatrixAlloc(mlKem_k, ML_KEM_N); + byte[] pkBytes = publicKey.keyBytes; + byte[] rho = Arrays.copyOfRange(pkBytes, + pkBytes.length - 32, pkBytes.length); + byte[] tHatBytes = Arrays.copyOfRange(pkBytes, + 0, pkBytes.length - 32); + var encryptTHat = decodeVector(12, tHatBytes); + var encryptA = generateA(rho, true); + short[][] encryptR = new short[mlKem_k][]; + short[][] encryptE1 = new short[mlKem_k][]; + int encryptN = 0; + byte[] prfSeed = new byte[sigma.length + 1]; + System.arraycopy(sigma, 0, prfSeed, 0, sigma.length); + + 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++); + kPkePRFeta2.update(prfSeed); + byte[] cbdInput = kPkePRFeta2.digest(); + encryptE1[i] = centeredBinomialDistribution(mlKem_eta2, cbdInput); + } + 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); + 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)); + + byte[] result = new byte[encryptC1.length + encryptC2.length]; + System.arraycopy(encryptC1, 0, + result, 0, encryptC1.length); + System.arraycopy(encryptC2, 0, + result, encryptC1.length, encryptC2.length); + + return new K_PKE_CipherText(result); + } + + private byte[] kPkeDecrypt(K_PKE_DecryptionKey privateKey, + K_PKE_CipherText cipherText) { + int uBytesLen = mlKem_k * mlKem_du * ML_KEM_N / 8; + byte[] uBytes = Arrays.copyOfRange(cipherText.encryptedBytes, + 0, uBytesLen); + byte[] vBytes = Arrays.copyOfRange(cipherText.encryptedBytes, + uBytesLen, cipherText.encryptedBytes.length); + var decryptU = decompressVector(decodeVector(mlKem_du, uBytes), mlKem_du); + var decryptV = decompressPoly( + decodePoly(mlKem_dv, vBytes, 0), mlKem_dv); + var decryptSHat = decodeVector(12, privateKey.keyBytes); + var decryptSU = mlKemInverseNTT( + mlKemVectorScalarMult(decryptSHat, mlKemVectorNTT(decryptU))); + for (int i = 0; i < mlKem_k; i++) { + Arrays.fill(decryptSHat[i], (short) 0); + } + decryptV = mlKemSubtractPoly(decryptV, decryptSU); + Arrays.fill(decryptSU, (short) 0); + + return encodeCompress(decryptV); + } + + /* + Sampling algorithms from Section 4.2.2 of the spec + */ + + //Combination of SampleNTT and KeyGen/Encrypt generation of A + private short[][][] generateA(byte[] rho, Boolean transposed) { + short[][][] a = new short[mlKem_k][mlKem_k][]; + + int nrPar = 2; + int rhoLen = rho.length; + byte[] seedBuf = new byte[XOF_BLOCK_LEN]; + System.arraycopy(rho, 0, seedBuf, 0, rho.length); + seedBuf[rhoLen + 2] = 0x1F; + seedBuf[XOF_BLOCK_LEN - 1] = (byte)0x80; + byte[][] xofBufArr = byteMatrixAlloc(nrPar, XOF_BLOCK_LEN + XOF_PAD); + int[] iIndex = new int[nrPar]; + int[] jIndex = new int[nrPar]; + + short[] parsedBuf = new short[(xofBufArr[0].length / 3) * 2]; + + int parInd = 0; + boolean allDone; + int[] ofs = new int[nrPar]; + Arrays.fill(ofs, 0); + short[][] aij = new short[nrPar][]; + try { + Shake128Parallel parXof = new Shake128Parallel(xofBufArr); + + for (int i = 0; i < mlKem_k; i++) { + for (int j = 0; j < mlKem_k; j++) { + System.arraycopy(seedBuf, 0, xofBufArr[parInd], 0, seedBuf.length); + if (transposed) { + xofBufArr[parInd][rhoLen] = (byte) i; + xofBufArr[parInd][rhoLen + 1] = (byte) j; + } else { + xofBufArr[parInd][rhoLen] = (byte) j; + xofBufArr[parInd][rhoLen + 1] = (byte) i; + } + iIndex[parInd] = i; + jIndex[parInd] = j; + ofs[parInd] = 0; + aij[parInd] = new short[ML_KEM_N]; + parInd++; + + if ((parInd == nrPar) || + ((i == mlKem_k - 1) && (j == mlKem_k - 1))) { + parXof.reset(xofBufArr); + + allDone = false; + while (!allDone) { + allDone = true; + parXof.squeezeBlock(); + for (int k = 0; k < parInd; k++) { + int parsedOfs = 0; + int tmp; + if (ofs[k] < ML_KEM_N) { + twelve2Sixteen(xofBufArr[k], 0, + parsedBuf, (XOF_BLOCK_LEN / 3) * 2); + } + while ((ofs[k] < ML_KEM_N) && + (parsedOfs < (XOF_BLOCK_LEN / 3) * 2)) { + tmp = parsedBuf[parsedOfs++] & 0xFFFF; + if (tmp < ML_KEM_Q) { + aij[k][ofs[k]] = (short) tmp; + ofs[k]++; + } + tmp = parsedBuf[parsedOfs++] & 0xFFFF; + if ((ofs[k] < ML_KEM_N) && (tmp < ML_KEM_Q)) { + aij[k][ofs[k]] = (short) tmp; + ofs[k]++; + } + } + if (ofs[k] < ML_KEM_N) { + allDone = false; + } + } + } + + for (int k = 0; k < parInd; k++) { + a[iIndex[k]][jIndex[k]] = aij[k]; + } + parInd = 0; + } + } + } + } catch (InvalidAlgorithmParameterException e) { + // This should never happen since xofBufArr is of the correct size + throw new RuntimeException("Internal error."); + } + + return a; + } + + private short[] centeredBinomialDistribution(int eta, byte[] input) { + if (eta == 2) return centeredBinomialDistribution2(input); + if (eta == 3) return centeredBinomialDistribution3(input); + // Below for arbitrary eta, not used in ML-KEM + short[] result = new short[ML_KEM_N]; + int index = 0; + int shift = 8; + int currentByte = input[0]; + for (int m = 0; m < ML_KEM_N; m++) { + int a = 0; + int b = 0; + for (int j = 0; j < eta; j++) { + if (shift == 8) { + currentByte = input[index++]; + shift = 0; + } + a += (currentByte >> shift) & 1; + shift++; + } + for (int j = 0; j < eta; j++) { + if (shift == 8) { + currentByte = input[index++]; + shift = 0; + } + b += (currentByte >> shift) & 1; + shift++; + } + result[m] = (short) (a - b); + } + return result; + } + + private short[] centeredBinomialDistribution2(byte[] input) { + short[] result = new short[ML_KEM_N]; + // A 64-bit number divided into 16 4-bits, representing all 4-bit + // patterns of input with values are CBD samples in [-2, 2]. + long bits = 0x0112f001f001eff0L; + int j = 0; + + for (int i = 0; i < input.length; i++) { + // One byte has 2 4-bit sequences, each producing a sample + int a = input[i]; + int shift1 = (a << 2) & 0x3c; + int shift2 = (a >> 2) & 0x3c; + result[j++] = (short) ((bits << shift1) >> 60); + result[j++] = (short) ((bits << shift2) >> 60); + } + + return result; + } + + private short[] centeredBinomialDistribution3(byte[] input) { + short[] result = new short[ML_KEM_N]; + // A 32-bit number divided into 8 4-bits, representing all 3-bits + // patterns (one half of a 6-bit input) with values in [0, 3]. + int bits = 0x01121223; + int j = 0; + + for (int i = 0; i < input.length; i += 3) { + // Every 3 bytes has 24 bits that produce 4 6-bit sequences. + // We calculate values for both halves of each sequence and + // do the subtraction to get the sample + int a1 = input[i]; + int a2 = input[i + 1]; + int a3 = input[i + 2]; + int shift1 = (a1 << 2) & 0x1c; + int shift2 = (a1 >> 1) & 0x1c; + int shift3 = ((a1 >> 4) & 0x0c) | ((a2 << 4) & 0x10); + int shift4 = (a2 << 1) & 0x1c; + int shift5 = (a2 >> 2) & 0x1c; + int shift6 = ((a2 >> 5) & 0x04) | ((a3 << 3) & 0x18); + int shift7 = a3 & 0x1c; + int shift8 = (a3 >> 3) & 0x1c; + result[j++] = (short) + (((bits << shift1) >> 28) - ((bits << shift2) >> 28)); + result[j++] = (short) + (((bits << shift3) >> 28) - ((bits << shift4) >> 28)); + result[j++] = (short) + (((bits << shift5) >> 28) - ((bits << shift6) >> 28)); + result[j++] = (short) + (((bits << shift7) >> 28) - ((bits << shift8) >> 28)); + } + + return result; + } + + /* + NTT algorithms from Section 4.3 of the specification + */ + + // Works in place, it returns its (modified) input so that it can be used in + // expressions + private short[][] mlKemVectorNTT(short[][] vector) { + for (int i = 0; i < mlKem_k; i++) { + mlKemNTT(vector[i]); + } + return vector; + } + + // Works in place, it returns its (modified) input so that it can be used in + // expressions + private short[][] mlKemVectorReduce(short[][] vector) { + for (int i = 0; i < mlKem_k; i++) { + mlKemBarrettReduce(vector[i]); + } + return vector; + } + + // Works in place, it returns its (modified) input so that it can be used in + // expressions + private short[][] mlKemVectorInverseNTT(short[][] vector) { + for (int i = 0; i < mlKem_k; i++) { + vector[i] = mlKemInverseNTT(vector[i]); + } + return vector; + } + + @IntrinsicCandidate + static int implKyberNtt(short[] poly, short[] ntt_zetas) { + implKyberNttJava(poly); + return 1; + } + + static void implKyberNttJava(short[] poly) { + int[] coeffs = new int[ML_KEM_N]; + for (int m = 0; m < ML_KEM_N; m++) { + coeffs[m] = poly[m]; + } + seilerNTT(coeffs); + for (int m = 0; m < ML_KEM_N; m++) { + poly[m] = (short) coeffs[m]; + } + } + + // The elements of poly should be in the range [-mlKem_q, mlKem_q] + // The elements of poly at return will be in the range of [0, mlKem_q] + private void mlKemNTT(short[] poly) { + assert poly.length == ML_KEM_N; + implKyberNtt(poly, montZetasForVectorNttArr); + mlKemBarrettReduce(poly); + } + + @IntrinsicCandidate + static int implKyberInverseNtt(short[] poly, short[] zetas) { + implKyberInverseNttJava(poly); + return 1; + } + + static void implKyberInverseNttJava(short[] poly) { + int[] coeffs = new int[ML_KEM_N]; + for (int m = 0; m < ML_KEM_N; m++) { + coeffs[m] = poly[m]; + } + seilerInverseNTT(coeffs); + for (int m = 0; m < ML_KEM_N; m++) { + poly[m] = (short) coeffs[m]; + } + } + + // Works in place, but also returns its (modified) input so that it can + // be used in expressions + private short[] mlKemInverseNTT(short[] poly) { + assert poly.length == ML_KEM_N; + implKyberInverseNtt(poly, montZetasForVectorInverseNttArr); + return poly; + } + + // Implements the ML_KEM NTT algorithm similarly to that described + // in https://eprint.iacr.org/2018/039.pdf . + // It works in place, replaces the elements of the input coeffs array + // by the transformed representation. + // The input elements should be in the range [-MONT_Q, MONT_Q]. + // The result elements will fit into the range of short + // (i.e. [-32768, 32767]). + private static void seilerNTT(int[] coeffs) { + int dimension = ML_KEM_N; + int zetaIndex = 0; + for (int l = dimension / 2; l > 1; l /= 2) { + for (int s = 0; s < dimension; s += 2 * l) { + for (int j = s; j < s + l; j++) { + int tmp = montMul(MONT_ZETAS_FOR_NTT[zetaIndex], coeffs[j + l]); + coeffs[j + l] = coeffs[j] - tmp; + coeffs[j] = coeffs[j] + tmp; + } + zetaIndex++; + } + } + } + + // Implements the ML_KEM inverse NTT algorithm similarly to that described + // in https://eprint.iacr.org/2018/039.pdf . + // It works in place, replaces the elements of the input coeffs array + // by the transformed representation. + // The input elements should be in the range [-MONT_Q, MONT_Q). + // The output elements will be in the range (-MONT_Q, MONT_Q). + private static void seilerInverseNTT(int[] coeffs) { + int dimension = ML_KEM_N; + int zetaIndex = MONT_ZETAS_FOR_NTT.length - 1; + for (int l = 2; l < dimension; l *= 2) { + for (int s = 0; s < dimension; s += 2 * l) { + for (int j = s; j < s + l; j++) { + int tmp = coeffs[j]; + coeffs[j] = (tmp + coeffs[j + l]); + coeffs[j + l] = montMul( + tmp - coeffs[j + l], + -MONT_ZETAS_FOR_NTT[zetaIndex]); + } + zetaIndex--; + } + } + + for (int i = 0; i < dimension; i++) { + int r = montMul(coeffs[i], MONT_DIM_HALF_INVERSE); + coeffs[i] = r; + } + } + + // Performs A o b + c where + // A is a mlKem_k by mlKem_k matrix, + // b and c are mlKem_k long vectors of degree ML_KEM_N - 1 + // polynomials in the NTT domain representation. + // The coefficients in the result are in the range [0, ML_KEM_Q). + private short[][] mlKemMatrixVectorMuladd( + short[][][] a, short[][] b, short[][] c) { + short[] product = new short[ML_KEM_N]; + + for (int i = 0; i < mlKem_k; i++) { + for (int j = 0; j < mlKem_k; j++) { + nttMult(product, a[i][j], b[j]); + mlKemAddPoly(c[i], product); + } + mlKemBarrettReduce(c[i]); + } + return c; + } + + // Performs a^T o b where a and b are mlKem_k long vectors + // of degree ML_KEM_N - 1 polynomials in the NTT representation, + // with coefficients in the range [-ML_KEM_Q, ML_KEM_Q]. + // The coefficients in the result are in the range [0, ML_KEM_Q). + private short[] mlKemVectorScalarMult(short[][] a, short[][] b) { + short[] result = new short[ML_KEM_N]; + short[] product = new short[ML_KEM_N]; + + int j; + for (j = 0; j < mlKem_k; j++) { + nttMult(product, a[j], b[j]); + mlKemAddPoly(result, product); + } + mlKemBarrettReduce(result); + + return result; + } + + @IntrinsicCandidate + static int implKyberNttMult(short[] result, short[] ntta, short[] nttb, + short[] zetas) { + implKyberNttMultJava(result, ntta, nttb); + return 1; + } + + static void implKyberNttMultJava(short[] result, short[] ntta, short[] nttb) { + for (int m = 0; m < ML_KEM_N / 2; m++) { + + int a0 = ntta[2 * m]; + int a1 = ntta[2 * m + 1]; + int b0 = nttb[2 * m]; + int b1 = nttb[2 * m + 1]; + int r = montMul(a0, b0) + + montMul(montMul(a1, b1), MONT_ZETAS_FOR_NTT_MULT[m]); + result[2 * m] = (short) montMul(r, MONT_R_SQUARE_MOD_Q); + result[2 * m + 1] = (short) montMul( + (montMul(a0, b1) + montMul(a1, b0)), MONT_R_SQUARE_MOD_Q); + } + } + + // Multiplies two polynomials represented in the NTT domain. + // The result is a representation of the product still in the NTT domain. + // The coefficients in the result are in the range (-mlKem_q, mlKem_q). + private void nttMult(short[] result, short[] ntta, short[] nttb) { + assert (result.length == ML_KEM_N) && (ntta.length == ML_KEM_N) && + (nttb.length == ML_KEM_N); + implKyberNttMult(result, ntta, nttb, montZetasForVectorNttMultArr); + } + + // Adds the vector of polynomials b to a in place, i.e. a will hold + // the result. It also returns (the modified) a so that it can be used + // in an expression. + // The coefficients in all polynomials of both vectors are supposed to be + // greater than -ML_KEM_Q and less than ML_KEM_Q. + // The coefficients in the result are nonnegative and less than ML_KEM_Q. + private short[][] mlKemAddVec(short[][] a, short[][] b) { + for (int i = 0; i < mlKem_k; i++) { + mlKemAddPoly(a[i], b[i]); + mlKemBarrettReduce(a[i]); + } + return a; + } + + @IntrinsicCandidate + static int implKyberAddPoly(short[] result, short[] a, short[] b) { + implKyberAddPolyJava(result, a, b); + return 1; + } + + static void implKyberAddPolyJava(short[] result, short[] a, short[] b) { + for (int m = 0; m < ML_KEM_N; m++) { + int r = a[m] + b[m] + ML_KEM_Q; // This makes r > - ML_KEM_Q + a[m] = (short) r; + } + } + + // Adds the polynomial b to a in place, i.e. (the modified) a will hold + // the result. + // The coefficients are supposed be greater than -ML_KEM_Q in a and + // greater than -ML_KEM_Q and less than ML_KEM_Q in b. + // The coefficients in the result are greater than -ML_KEM_Q. + private short[] mlKemAddPoly(short[] a, short[] b) { + assert (a.length == ML_KEM_N) && (b.length == ML_KEM_N); + implKyberAddPoly(a, a, b); + return a; + } + + @IntrinsicCandidate + static int implKyberAddPoly(short[] result, short[] a, short[] b, short[] c) { + implKyberAddPolyJava(result, a, b, c); + return 1; + } + + static void implKyberAddPolyJava(short[] result, short[] a, short[] b, short[] c) { + for (int m = 0; m < ML_KEM_N; m++) { + int r = a[m] + b[m] + c[m] + 2 * ML_KEM_Q; // This makes r > - ML_KEM_Q + result[m] = (short) r; + } + } + + // Adds the polynomials b and c to a in place, i.e. 'a' will hold the sum. + // 'a' is also returned so that this function can be used in an expression. + // The coefficients in all three polynomials are supposed to be + // greater than -ML_KEM_Q and less than ML_KEM_Q. + // The coefficients in the result are nonnegative and less than ML_KEM_Q. + private short[] mlKemAddPoly(short[] a, short[] b, short[] c) { + assert (a.length == ML_KEM_N) && (b.length == ML_KEM_N) && + (c.length == ML_KEM_N); + implKyberAddPoly(a, a, b, c); + mlKemBarrettReduce(a); + return a; + } + + // Subtracts the polynomial b from a in place, i.e. the result is + // stored in a. It also returns (the modified) a, so that it can be used + // in an expression. + // The coefficiens in both are assumed to be greater than -ML_KEM_Q + // and less than ML_KEM_Q. + // The coefficients in the result are nonnegative and less than ML_KEM_Q. + private short[] mlKemSubtractPoly(short[] a, short[] b) { + for (int m = 0; m < ML_KEM_N; m++) { + int r = a[m] - b[m] + ML_KEM_Q; // This makes r > -ML_KEM_Q + a[m] = (short) r; + } + mlKemBarrettReduce(a); + return a; + } + + private byte[] encodeVector(int l, short[][] vector) { + return encodeVector(l, vector, mlKem_k); + } + + private static byte[] encodeVector(int l, short[][] vector, int k) { + int encodedPolyLength = ML_KEM_N * l / 8; + byte[] result = new byte[k * encodedPolyLength]; + + for (int i = 0; i < k; i++) { + byte[] resultBytes = encodePoly(l, vector[i]); + System.arraycopy(resultBytes, 0, + result, i * encodedPolyLength, encodedPolyLength); + } + return result; + } + + private static void encodePoly12(short[] poly, byte[] result, int resultOffs) { + int low; + int high; + for (int m = 0; m < ML_KEM_N / 2; m++) { + low = poly[2 * m]; + low += ((low >> 31) & ML_KEM_Q); + low = low & 0xfff; + high = poly[2 * m + 1]; + high += ((high >> 31) & ML_KEM_Q); + high = high & 0xfff; + + result[resultOffs++] = (byte) low; + result[resultOffs++] = (byte) ((high << 4) + (low >> 8)); + result[resultOffs++] = (byte) (high >> 4); + } + } + + private static void encodePoly4(short[] poly, byte[] result) { + for (int m = 0; m < ML_KEM_N / 2; m++) { + result[m] = (byte) ((poly[2 * m] & 0xf) + (poly[2 * m + 1] << 4)); + } + } + + // Computes the byte array containing the packed l-bit representation + // of a polynomial. The coefficients in poly should be either nonnegative + // or elements of Z_(ML_KEM_Q) represented by a 16-bit value + // between -ML_KEM_Q and ML_KEM_Q. + private static byte[] encodePoly(int l, short[] poly) { + byte[] result = new byte[ML_KEM_N / 8 * l]; + if (l == 4) { + encodePoly4(poly, result); + } else { + int mask = (1 << l) - 1; + int shift = 0; + int index = 0; + int current = 0; + for (int m = 0; m < ML_KEM_N; m++) { + int currentShort = poly[m]; + currentShort += (currentShort >> 31) & ML_KEM_Q; + current += ((currentShort & mask) << shift); + shift += l; + while (shift >= 8) { + result[index++] = (byte) current; + current >>>= 8; + shift -= 8; + } + } + } + + return result; + } + + private static byte[] encodeCompress(short[] poly) { + byte[] result = new byte[ML_KEM_N / 8]; + int xx; + int currentByte; + for (int i = 0; i < ML_KEM_N / 8; i++) { + currentByte = 0; + xx = poly[i * 8]; + currentByte |= (((832 - xx) & (xx - 2497)) >>> 31); + xx = poly[i * 8 + 1]; + currentByte |= ((((832 - xx) & (xx - 2497)) >>> 30) & 2); + xx = poly[i * 8 + 2]; + currentByte |= ((((832 - xx) & (xx - 2497)) >>> 29) & 4); + xx = poly[i * 8 + 3]; + currentByte |= ((((832 - xx) & (xx - 2497)) >>> 28) & 8); + xx = poly[i * 8 + 4]; + currentByte |= ((((832 - xx) & (xx - 2497)) >>> 27) & 16); + xx = poly[i * 8 + 5]; + currentByte |= ((((832 - xx) & (xx - 2497)) >>> 26) & 32); + xx = poly[i * 8 + 6]; + currentByte |= ((((832 - xx) & (xx - 2497)) >>> 25) & 64); + xx = poly[i * 8 + 7]; + currentByte |= ((((832 - xx) & (xx - 2497)) >>> 24) & 128); + result[i] = (byte) currentByte; + } + return result; + } + + private short[][] decodeVector(int l, byte[] encodedVector) { + short[][] result = new short[mlKem_k][]; + for (int i = 0; i < mlKem_k; i++) { + result[i] = decodePoly(l, encodedVector, (i * ML_KEM_N * l) / 8); + } + return result; + } + + @IntrinsicCandidate + private static int implKyber12To16(byte[] condensed, int index, short[] parsed, int parsedLength) { + implKyber12To16Java(condensed, index, parsed, parsedLength); + return 1; + } + + private static void implKyber12To16Java(byte[] condensed, int index, short[] parsed, int parsedLength) { + for (int i = 0; i < parsedLength * 3 / 2; i += 3) { + parsed[(i / 3) * 2] = (short) ((condensed[i + index] & 0xff) + + 256 * (condensed[i + index + 1] & 0xf)); + parsed[(i / 3) * 2 + 1] = (short) (((condensed[i + index + 1] >>> 4) & 0xf) + + 16 * (condensed[i + index + 2] & 0xff)); + } + } + + // 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 n = (parsedLength + 127) / 128; + assert ((parsed.length >= n * 128) && + (condensed.length >= index + n * 192)); + + implKyber12To16(condensed, index, parsed, parsedLength); + } + + private static void decodePoly5(byte[] condensed, int index, short[] parsed) { + int j = index; + for (int i = 0; i < ML_KEM_N; i += 8) { + parsed[i] = (short) (condensed[j] & 0x1f); + parsed[i + 1] = (short) ((((condensed[j] & 0xff) >>> 5) + + (condensed[j + 1] << 3) & 0x1f)); + parsed[i + 2] = (short) ((condensed[j + 1] & 0x7f) >>> 2); + parsed[i + 3] = (short) ((((condensed[j + 1] & 0xff) >>> 7) + + (condensed[j + 2] << 1)) & 0x1f); + parsed[i + 4] = (short) ((((condensed[j + 2] & 0xff) >>> 4) + + (condensed[j + 3] << 4)) & 0x1f); + parsed[i + 5] = (short) ((condensed[j + 3] & 0x3f) >>> 1); + parsed[i + 6] = (short) ((((condensed[j + 3] & 0xff) >>> 6) + + (condensed[j + 4] << 2)) & 0x1f); + parsed[i + 7] = (short) ((condensed[j + 4] & 0xff) >>> 3); + j += 5; + } + } + + private static void decodePoly4(byte[] condensed, int index, short[] parsed) { + for (int i = 0; i < ML_KEM_N / 2; i++) { + parsed[i * 2] = (short) (condensed[i + index] & 0xf); + parsed[i * 2 + 1] = (short) ((condensed[i + index] >>> 4) & 0xf); + } + } + + // Recovers the 16-bit coefficients of a polynomial from a byte array + // containing a packed l-bit representation. + // The recovered coefficients will be in the range 0 <= coeff < 2^l . + private short[] decodePoly(int l, byte[] input, int index) { + short[] poly = new short[ML_KEM_N]; + if (l == 12) { + twelve2Sixteen(input, index, poly, ML_KEM_N); + } else if (l == 4) { + decodePoly4(input, index, poly); + } else if (l == 5) { + decodePoly5(input, index, poly); + } else { + int mask = (1 << l) - 1; + int top = 0; + int shift = 0; + int acc = 0; + for (int m = 0; m < ML_KEM_N; m++) { + while (top - shift < l) { + acc += ((input[index++] & 0xff) << top); + top += 8; + } + poly[m] = (short) ((acc >> shift) & mask); + shift += l; + while (shift >= 8) { + top -= 8; + shift -= 8; + acc >>>= 8; + } + } + } + + return poly; + } + + // Prerequisite: d == 10 or d == 11 + // Compresses a vector in place, i.e. it modifies the coefficients of the + // polynomials of its input vector. It returns its (modified) input so that + // the function can be used in an expression. + private short[][] compressVector10_11(short[][] vector, int d) { + for (int i = 0; i < mlKem_k; i++) { + vector[i] = compressPoly10_11(vector[i], d); + } + return vector; + } + + // Prerequisite: for all m, 0 <= poly[m] < ML_KEM_Q, d == 4 or d == 5 + // Replaces poly[m] with round(2^d * poly[m] / ML_KEM_Q) mod 2^d for all m, + // where round(z) is the integer closest to z, i.e. + // compresses a polynomial in place. + private static short[] compressPoly4_5(short[] poly, int d) { + int xx; + for (int m = 0; m < ML_KEM_N; m++) { + xx = (poly[m] << d) + ML_KEM_Q / 2; + poly[m] = (short)((xx * 315) >> 20); + } + return poly; + } + + // Prerequisite: for all m, 0 <= poly[m] < ML_KEM_Q, d == 10 or d == 11 + // Replaces poly[m] with round(2^d * poly[m] / ML_KEM_Q) mod 2^d for all m, + // where round(z) is the integer closest to z, i.e. + // compresses a polynomial in place. + private static short[] compressPoly10_11(short[] poly, int d) { + long xx; + for (int m = 0; m < ML_KEM_N; m++) { + xx = (poly[m] << d) + ML_KEM_Q / 2; + poly[m] = (short)((xx * 161271L) >> 29); + } + return poly; + } + + // Decompresses a vector in place, i.e. it modifies the coefficients of the + // polynomials of its input vector. It returns its (modified) input so that + // the function can be used in an expression. + private short[][] decompressVector(short[][] vector, int d) { + for (int i = 0; i < mlKem_k; i++) { + vector[i] = decompressPoly(vector[i], d); + } + return vector; + } + + // Decompresses a polynomial in place, i.e. it modifies the coefficients + // in its input. It returns its (modified) input so that the function can + // be used in an expression. + // Prerequisite: 0 <= x[i] < 2^d < ML_KEM_Q . + // Computes Round(ML_KEM_Q * x[i] / 2^d), + // where Round(z) is the integer closest to z, + // for each coefficient of a polynomial + private static short[] decompressPoly(short[] poly, int d) { + for (int m = 0; m < ML_KEM_N; m++) { + int qx = ML_KEM_Q * poly[m]; + poly[m] = (short) ((qx >> d) + ((qx >> (d - 1)) & 1)); + } + return poly; + } + + private static short[] decompressDecode(byte[] input) { + short[] result = new short[256]; + for (int i = 0; i < 32; i++) { + int currentByte = input[i] & 0xFF; + result [i * 8] = (short)(((currentByte << 31 ) >> 31) & 1665); + result [i * 8 + 1] = (short)(((currentByte << 30 ) >> 31) & 1665); + result [i * 8 + 2] = (short)(((currentByte << 29 ) >> 31) & 1665); + result [i * 8 + 3] = (short)(((currentByte << 28 ) >> 31) & 1665); + result [i * 8 + 4] = (short)(((currentByte << 27 ) >> 31) & 1665); + result [i * 8 + 5] = (short)(((currentByte << 26 ) >> 31) & 1665); + result [i * 8 + 6] = (short)(((currentByte << 25 ) >> 31) & 1665); + result [i * 8 + 7] = (short)(((currentByte << 24 ) >> 31) & 1665); + } + return result; + } + + @IntrinsicCandidate + static int implKyberBarrettReduce(short[] coeffs) { + implKyberBarrettReduceJava(coeffs); + return 1; + } + + static void implKyberBarrettReduceJava(short[] poly) { + for (int m = 0; m < ML_KEM_N; m++) { + int tmp = ((int) poly[m] * BARRETT_MULTIPLIER) >> BARRETT_SHIFT; + poly[m] = (short) (poly[m] - tmp * ML_KEM_Q); + } + } + + // The input elements can have any short value. + // Modifies poly such that upon return poly[i] will be + // in the range [0, ML_KEM_Q] and will be congruent with the original + // poly[i] modulo ML_KEM_Q, for all i in [0, ML_KEM_N). + // At return, poly[i] == ML_KEM_Q if and only if the original poly[i] was + // a negative integer multiple of ML_KEM_Q. + // That means that if the original poly[i] > -ML_KEM_Q then at return it + // will be in the range [0, ML_KEM_Q), i.e. it will be the canonical + // representative of its residue class. + private static void mlKemBarrettReduce(short[] poly) { + assert poly.length == ML_KEM_N; + implKyberBarrettReduce(poly); + } + + // Precondition: -(2^MONT_R_BITS -1) * MONT_Q <= b * c < (2^MONT_R_BITS - 1) * MONT_Q + // Computes b * c * 2^-MONT_R_BITS mod MONT_Q + // The result is between -MONT_Q and MONT_Q + private static int montMul(int b, int c) { + int a = b * c; + int aHigh = a >> MONT_R_BITS; + int aLow = a & ((1 << MONT_R_BITS) - 1); + // signed low product + int m = ((MONT_Q_INV_MOD_R * aLow) << (32 - MONT_R_BITS)) >> (32 - MONT_R_BITS); + + return (aHigh - ((m * MONT_Q) >> MONT_R_BITS)); // subtract signed high product + } + + // For multidimensional array initialization, manually allocating each entry is + // faster than doing the entire initialization in one go + static short[][] shortMatrixAlloc(int first, int second) { + short[][] res = new short[first][]; + for (int i = 0; i < first; i++) { + res[i] = new short[second]; + } + return res; + } + + static byte[][] byteMatrixAlloc(int first, int second) { + byte[][] res = new byte[first][]; + for (int i = 0; i < first; i++) { + res[i] = new byte[second]; + } + return res; + } +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM_Impls.java openjdk-21-21.0.13+9/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM_Impls.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM_Impls.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM_Impls.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,261 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.crypto.provider; + +import sun.security.jca.JCAUtil; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.provider.NamedKEM; +import sun.security.provider.NamedKeyFactory; +import sun.security.provider.NamedKeyPairGenerator; +import sun.security.util.KeyChoices; +import sun.security.x509.NamedX509Key; + +import java.security.*; +import java.util.Arrays; + +import javax.crypto.DecapsulateException; + +public final class ML_KEM_Impls { + + private static final int SEED_LEN = 64; + + public static byte[] seedToExpanded(String pname, byte[] seed) { + return new ML_KEM(pname).generateKemKeyPair(seed) + .decapsulationKey() + .keyBytes(); + } + + public static NamedX509Key privKeyToPubKey(NamedPKCS8Key npk) { + return new NamedX509Key(npk.getAlgorithm(), + npk.getParams().getName(), + new ML_KEM(npk.getParams().getName()).privKeyToPubKey(npk.getExpanded())); + } + + public sealed static class KPG + extends NamedKeyPairGenerator permits KPG2, KPG3, KPG5 { + + public KPG() { + // ML-KEM-768 is the default + super("ML-KEM", "ML-KEM-768", "ML-KEM-512", "ML-KEM-1024"); + } + + protected KPG(String pname) { + super("ML-KEM", pname); + } + + @Override + protected byte[][] implGenerateKeyPair(String pname, SecureRandom random) { + byte[] seed = new byte[SEED_LEN]; + var r = random != null ? random : JCAUtil.getDefSecureRandom(); + r.nextBytes(seed); + + ML_KEM mlKem = new ML_KEM(pname); + ML_KEM.ML_KEM_KeyPair kp; + kp = mlKem.generateKemKeyPair(seed); + var expanded = kp.decapsulationKey().keyBytes(); + + try { + return new byte[][]{ + kp.encapsulationKey().keyBytes(), + KeyChoices.writeToChoice( + KeyChoices.getPreferred("mlkem"), + seed, expanded), + expanded + }; + } finally { + Arrays.fill(seed, (byte) 0); + } + } + } + + public final static class KPG2 extends KPG { + public KPG2() { + super("ML-KEM-512"); + } + } + + public final static class KPG3 extends KPG { + public KPG3() { + super("ML-KEM-768"); + } + } + + public final static class KPG5 extends KPG { + public KPG5() { + super("ML-KEM-1024"); + } + } + + public sealed static class KF extends NamedKeyFactory permits KF2, KF3, KF5 { + public KF() { + super("ML-KEM", "ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"); + } + public KF(String pname) { + super("ML-KEM", pname); + } + + @Override + protected byte[] implExpand(String pname, byte[] input) + throws InvalidKeyException { + return KeyChoices.choiceToExpanded(pname, SEED_LEN, input, + ML_KEM_Impls::seedToExpanded); + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + var nk = toNamedKey(key); + if (nk instanceof NamedPKCS8Key npk) { + var type = KeyChoices.getPreferred("mlkem"); + if (KeyChoices.typeOfChoice(npk.getRawBytes()) != type) { + var encoding = KeyChoices.choiceToChoice( + type, + npk.getParams().getName(), + SEED_LEN, npk.getRawBytes(), + ML_KEM_Impls::seedToExpanded); + nk = NamedPKCS8Key.internalCreate( + npk.getAlgorithm(), + npk.getParams().getName(), + encoding, + npk.getExpanded().clone()); + if (npk != key) { // npk is neither input or output + npk.destroy(); + } + } + } + return nk; + } + } + + public final static class KF2 extends KF { + public KF2() { + super("ML-KEM-512"); + } + } + + public final static class KF3 extends KF { + public KF3() { + super("ML-KEM-768"); + } + } + + public final static class KF5 extends KF { + public KF5() { + super("ML-KEM-1024"); + } + } + + public sealed static class K extends NamedKEM permits K2, K3, K5 { + private static final int SEED_SIZE = 32; + + @Override + protected byte[][] implEncapsulate(String pname, byte[] encapsulationKey, + Object ek, SecureRandom secureRandom) { + + byte[] randomBytes = new byte[SEED_SIZE]; + var r = secureRandom != null ? secureRandom : JCAUtil.getDefSecureRandom(); + r.nextBytes(randomBytes); + + ML_KEM mlKem = new ML_KEM(pname); + ML_KEM.ML_KEM_EncapsulateResult mlKemEncapsulateResult; + try { + mlKemEncapsulateResult = mlKem.encapsulate( + new ML_KEM.ML_KEM_EncapsulationKey( + encapsulationKey), randomBytes); + } finally { + Arrays.fill(randomBytes, (byte) 0); + } + + return new byte[][] { + mlKemEncapsulateResult.cipherText().encryptedBytes(), + mlKemEncapsulateResult.sharedSecret() + }; + } + + @Override + protected byte[] implDecapsulate(String pname, byte[] decapsulationKey, + Object dk, byte[] cipherText) + throws DecapsulateException { + + ML_KEM mlKem = new ML_KEM(pname); + var kpkeCipherText = new ML_KEM.K_PKE_CipherText(cipherText); + return mlKem.decapsulate(new ML_KEM.ML_KEM_DecapsulationKey( + decapsulationKey), kpkeCipherText); + } + + @Override + protected int implSecretSize(String pname) { + return ML_KEM.SECRET_SIZE; + } + + @Override + protected int implEncapsulationSize(String pname) { + ML_KEM mlKem = new ML_KEM(pname); + return mlKem.getEncapsulationSize(); + } + + @Override + protected Object implCheckPublicKey(String pname, byte[] pk) + throws InvalidKeyException { + + ML_KEM mlKem = new ML_KEM(pname); + return mlKem.checkPublicKey(pk); + } + + @Override + protected Object implCheckPrivateKey(String pname, byte[] sk) + throws InvalidKeyException { + + ML_KEM mlKem = new ML_KEM(pname); + return mlKem.checkPrivateKey(sk); + } + + public K() { + super("ML-KEM", new KF()); + } + + public K(String pname) { + super("ML-KEM", new KF(pname)); + } + } + + public final static class K2 extends K { + public K2() { + super("ML-KEM-512"); + } + } + + public final static class K3 extends K { + public K3() { + super("ML-KEM-768"); + } + } + + public final static class K5 extends K { + public K5() { + super("ML-KEM-1024"); + } + } +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java openjdk-21-21.0.13+9/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2017, 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 @@ -92,25 +92,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-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java openjdk-21-21.0.13+9/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java 2026-10-19 12:10:20.000000000 +0000 @@ -78,6 +78,8 @@ * * - DHKEM * + * - ML-KEM + * */ public final class SunJCE extends Provider { @@ -87,7 +89,7 @@ private static final String info = "SunJCE Provider " + "(implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, " - + "Diffie-Hellman, HMAC, ChaCha20)"; + + "Diffie-Hellman, HMAC, ChaCha20, DHKEM, and ML-KEM)"; /* Are we debugging? -- for developers */ static final boolean debug = false; @@ -759,6 +761,23 @@ "|java.security.interfaces.XECKey"); ps("KEM", "DHKEM", "com.sun.crypto.provider.DHKEM", null, attrs); + attrs.clear(); + attrs.put("ImplementedIn", "Software"); + ps("KEM", "ML-KEM", "com.sun.crypto.provider.ML_KEM_Impls$K", null, attrs); + psA("KEM", "ML-KEM-512", "com.sun.crypto.provider.ML_KEM_Impls$K2", attrs); + psA("KEM", "ML-KEM-768", "com.sun.crypto.provider.ML_KEM_Impls$K3", attrs); + psA("KEM", "ML-KEM-1024", "com.sun.crypto.provider.ML_KEM_Impls$K5",attrs); + + ps("KeyPairGenerator", "ML-KEM", "com.sun.crypto.provider.ML_KEM_Impls$KPG", null, attrs); + psA("KeyPairGenerator", "ML-KEM-512", "com.sun.crypto.provider.ML_KEM_Impls$KPG2", attrs); + psA("KeyPairGenerator", "ML-KEM-768", "com.sun.crypto.provider.ML_KEM_Impls$KPG3", attrs); + psA("KeyPairGenerator", "ML-KEM-1024", "com.sun.crypto.provider.ML_KEM_Impls$KPG5", attrs); + + ps("KeyFactory", "ML-KEM", "com.sun.crypto.provider.ML_KEM_Impls$KF", null, attrs); + psA("KeyFactory", "ML-KEM-512", "com.sun.crypto.provider.ML_KEM_Impls$KF2", attrs); + psA("KeyFactory", "ML-KEM-768", "com.sun.crypto.provider.ML_KEM_Impls$KF3", attrs); + psA("KeyFactory", "ML-KEM-1024", "com.sun.crypto.provider.ML_KEM_Impls$KF5", attrs); + /* * SSL/TLS mechanisms * diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/java/lang/ref/Reference.java openjdk-21-21.0.13+9/src/java.base/share/classes/java/lang/ref/Reference.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/java/lang/ref/Reference.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/java/net/SocksSocketImpl.java openjdk-21-21.0.13+9/src/java.base/share/classes/java/net/SocksSocketImpl.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/java/net/SocksSocketImpl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/java/net/SocksSocketImpl.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 @@ -167,13 +167,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); @@ -276,6 +290,16 @@ security.checkConnect(epoint.getAddress().getHostAddress(), epoint.getPort()); } + + 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 @@ -409,8 +433,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-21-21.0.12.1+1/src/java.base/share/classes/java/text/SimpleDateFormat.java openjdk-21-21.0.13+9/src/java.base/share/classes/java/text/SimpleDateFormat.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/java/text/SimpleDateFormat.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/java/text/SimpleDateFormat.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -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 @@ -1283,15 +1285,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++; @@ -1300,8 +1309,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-21-21.0.12.1+1/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java openjdk-21-21.0.13+9/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2023, 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 @@ -4503,7 +4503,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-21-21.0.12.1+1/src/java.base/share/classes/java/util/zip/ZipFile.java openjdk-21-21.0.13+9/src/java.base/share/classes/java/util/zip/ZipFile.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/java/util/zip/ZipFile.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/java/util/zip/ZipFile.java 2026-10-19 12:10:20.000000000 +0000 @@ -1544,7 +1544,7 @@ private static class End { - int centot; // 4 bytes + long centot; // 4 bytes long cenlen; // 4 bytes long cenoff; // 4 bytes long endpos; // 4 bytes @@ -1639,7 +1639,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; } catch (IOException x) {} // no zip64 loc/end return end; @@ -1662,8 +1662,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. @@ -1671,15 +1673,22 @@ if (locpos < 0) { zerror("invalid END header (bad central directory offset)"); } - // read in the CEN and END if (end.cenlen + ENDHDR >= Integer.MAX_VALUE) { zerror("invalid END header (central directory size too large)"); } - cen = this.cen = new byte[(int)(end.cenlen + ENDHDR)]; - if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) { + 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 and END + cen = this.cen = new byte[cenlen + ENDHDR]; + if (readFullyAt(cen, 0, cen.length, cenpos) != cenlen + ENDHDR) { zerror("read CEN tables failed"); } - this.total = end.centot; + this.total = centot; } else { cen = this.cen; this.total = knownTotal; diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/javax/crypto/KeyAgreement.java openjdk-21-21.0.13+9/src/java.base/share/classes/javax/crypto/KeyAgreement.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/javax/crypto/KeyAgreement.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/javax/crypto/KeyAgreement.java 2026-10-19 12:10:20.000000000 +0000 @@ -661,7 +661,7 @@ * {@code generateSecret} to change the private information used in * subsequent operations. * - * @param algorithm the requested secret-key algorithm + * @param algorithm the requested secret key algorithm * * @return the shared secret key * diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/javax/crypto/KeyAgreementSpi.java openjdk-21-21.0.13+9/src/java.base/share/classes/javax/crypto/KeyAgreementSpi.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/javax/crypto/KeyAgreementSpi.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/javax/crypto/KeyAgreementSpi.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, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java openjdk-21-21.0.13+9/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/module-info.java openjdk-21-21.0.13+9/src/java.base/share/classes/module-info.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/module-info.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/module-info.java 2026-10-19 12:10:20.000000000 +0000 @@ -274,6 +274,7 @@ jdk.random; exports jdk.internal.util to java.desktop, + java.net.http, java.prefs, java.security.jgss, java.smartcardio, @@ -328,6 +329,7 @@ exports sun.security.internal.spec to jdk.crypto.cryptoki; exports sun.security.jca to + java.security.sasl, java.smartcardio, jdk.crypto.ec, jdk.crypto.cryptoki, diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -543,7 +543,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-21-21.0.12.1+1/src/java.base/share/classes/sun/net/smtp/SmtpClient.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/net/smtp/SmtpClient.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/net/smtp/SmtpClient.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2017, 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 @@ -75,7 +75,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")); } @@ -121,7 +121,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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,205 @@ +/* + * 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. 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.pkcs; + +import sun.security.x509.AlgorithmId; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.Serial; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; +import java.util.Objects; + +/// Represents a private key from an algorithm family that is specialized +/// with a named parameter set. +/// +/// This key is generated by either a [sun.security.provider.NamedKeyPairGenerator] +/// or [sun.security.provider.NamedKeyFactory]. Its [#getAlgorithm] method +/// returns the algorithm family name, while its [#getParams()] method returns +/// the parameter set name as a [NamedParameterSpec] object. The algorithm +/// identifier in the PKCS #8 encoding of the key is always a single OID derived +/// from the parameter set name. +/// +/// Besides the existing [PKCS8Key#key] field, this class optionally +/// supports an expanded format stored in [#expanded]. While `key` +/// always represents the format used for encoding, `expanded` is always used +/// in computations. The expanded format must be self-sufficient for +/// cryptographic computations without requiring the encoding format. +/// +/// 1. If only `key` is present, it's also the expanded format. +/// 2. If both `key` and `expanded` are available, `key` +/// is the encoding format, and `expanded` is the expanded format. +/// +/// If the two formats are the same, only `key` is included, and +/// `expanded` must be `null`. Some implementations might be tempted to put the +/// same value into `key` and `expanded`. However, problems can +/// arise if they happen to be the same object. To avoid ambiguity, always set +/// `expanded` to `null`. +/// +/// If the `expanded` field is required by the algorithm, it is either +/// [calculated from the PKCS #8 encoding][#NamedPKCS8Key(String, byte\[\], Expander)], +/// or [provided directly][#internalCreate(String, String, byte\[\], byte\[\])]. +/// In the latter case, the caller must ensure the consistency of the `encoded` +/// and `expanded` arguments. For example, seed and expanded key must match. +/// +/// @see sun.security.provider.NamedKeyPairGenerator +public final class NamedPKCS8Key extends PKCS8Key { + @Serial + private static final long serialVersionUID = 1L; + + private final String fname; + private final transient NamedParameterSpec paramSpec; + private final transient byte[] expanded; + + private transient boolean destroyed = false; + + /// Creates a `NamedPKCS8Key` from raw components. + /// + /// @param fname family name + /// @param pname parameter set name + /// @param encoded raw key bytes, not null + /// @param expanded expanded key format, can be `null`. + private NamedPKCS8Key(String fname, String pname, byte[] encoded, byte[] expanded) { + this.fname = fname; + this.paramSpec = new NamedParameterSpec(pname); + this.expanded = expanded; + this.key = Objects.requireNonNull(encoded); + try { + this.algid = AlgorithmId.get(pname); + } catch (NoSuchAlgorithmException e) { + throw new ProviderException(e); + } + } + + /// Creates a `NamedPKCS8Key` from raw components. + /// + /// `encoded` and `expanded` won't be cloned, caller must relinquish + /// ownership. This caller must ensure `encoded` and `expanded` match + /// each other and `encoded` is valid and internally-consistent. + /// + /// @param fname family name + /// @param pname parameter set name + /// @param encoded raw key bytes, not null + /// @param expanded expanded key format, can be `null`. + public static NamedPKCS8Key internalCreate(String fname, String pname, + byte[] encoded, byte[] expanded) { + return new NamedPKCS8Key(fname, pname, encoded, expanded); + } + + /// Creates a `NamedPKCS8Key` from family name and PKCS #8 encoding. + /// + /// @param fname family name + /// @param encoded PKCS #8 encoding. It is copied so caller can modify + /// it after the method call. + /// @param expander a function that is able to calculate the expanded + /// format from the encoding format inside `encoded`. If it recognizes + /// the input already in expanded format, it must return `null`. + /// This argument must be `null` if the algorithm's expanded format + /// is always the same as its encoding format. Whatever the case, the + /// ownership of the result is fully granted to this object. + public NamedPKCS8Key(String fname, byte[] encoded, Expander expander) + throws InvalidKeyException { + super(encoded); + this.fname = fname; + this.expanded = expander == null + ? null + : expander.expand(algid.getName(), this.key); + paramSpec = new NamedParameterSpec(algid.getName()); + if (algid.getEncodedParams() != null) { + throw new InvalidKeyException("algorithm identifier has params"); + } + } + + @Override + public String toString() { + // Do not modify: this can be used by earlier JDKs that + // do not have the getParams() method + return paramSpec.getName() + " private key"; + } + + /// Returns the reference to the internal key. Caller must not modify + /// the content or pass the reference to untrusted application code. + public byte[] getRawBytes() { + return key; + } + + /// Returns the reference to the key in expanded format. Caller must not + /// modify the content or pass the reference to untrusted application code. + public byte[] getExpanded() { + return expanded == null ? key : expanded; + } + + public NamedParameterSpec getParams() { + return paramSpec; + } + + @Override + public String getAlgorithm() { + return fname; + } + + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "NamedPKCS8Key keys are not directly deserializable"); + } + + @Override + public void destroy() { + Arrays.fill(key, (byte)0); + if (expanded != null) { + Arrays.fill(expanded, (byte)0); + } + if (encodedKey != null) { + Arrays.fill(encodedKey, (byte)0); + } + destroyed = true; + } + + @Override + public boolean isDestroyed() { + return destroyed; + } + + /// Expands from encoding format to expanded format. + @FunctionalInterface + public interface Expander { + /// The expand method + /// + /// @param pname parameter set name + /// @param input input encoding + /// @return the expanded key, `null` if `input` is already in expanded + /// @throws InvalidKeyException if `input` is invalid, for example, + /// wrong encoding, or internal inconsistency + byte[] expand(String pname, byte[] input) throws InvalidKeyException; + } +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/pkcs/PKCS7.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/pkcs/PKCS7.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/pkcs/PKCS7.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/pkcs/PKCS7.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import java.util.function.Function; import sun.security.jca.JCAUtil; -import sun.security.provider.SHAKE256; +import sun.security.provider.SHA3.SHAKE256; import sun.security.timestamp.*; import sun.security.util.*; import sun.security.x509.*; diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java 2026-10-19 12:10:20.000000000 +0000 @@ -32,7 +32,7 @@ import java.security.spec.PSSParameterSpec; import java.util.*; -import sun.security.provider.SHAKE256; +import sun.security.provider.SHA3.SHAKE256; import sun.security.timestamp.TimestampToken; import sun.security.util.*; import sun.security.x509.AlgorithmId; diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/DigestBase.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/DigestBase.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/DigestBase.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/DigestBase.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, 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 @@ -61,7 +61,7 @@ private final int digestLength; // size of the input to the compression function in bytes - private final int blockSize; + protected final int blockSize; // buffer to store partial blocks, blockSize bytes large // Subclasses should not access this array directly except possibly in their // implDigest() method. See MD5.java as an example. diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/ML_DSA.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/ML_DSA.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/ML_DSA.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/ML_DSA.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,1641 @@ +/* + * 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. 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.provider; + +import jdk.internal.vm.annotation.IntrinsicCandidate; +import sun.security.provider.SHA3.SHAKE256; +import sun.security.provider.SHA3Parallel.Shake128Parallel; + +import java.security.InvalidAlgorithmParameterException; +import java.security.MessageDigest; +import java.security.InvalidKeyException; +import java.security.SignatureException; +import java.util.Arrays; + +public class ML_DSA { + // Security level constants + static final int ML_DSA_44 = 2; + static final int ML_DSA_65 = 3; + static final int ML_DSA_87 = 5; + + // Constants from FIPS 204 that do not depend on security level + private static final int ML_DSA_D = 13; + private static final int ML_DSA_Q = 8380417; + private static final int ML_DSA_N = 256; + private static final int SHAKE256_BLOCK_SIZE = 136; // the block length for SHAKE256 + private static final int SHAKE128_BLOCK_SIZE = 168; // the block length for SHAKE128 + private final int A_SEED_LEN = 32; + private final int S1S2_SEED_LEN = 64; + private final int K_LEN = 32; + private final int TR_LEN = 64; + private final int MU_LEN = 64; + private final int MASK_SEED_LEN = 64; + private static final int D_MASK = (1 << ML_DSA_D) - 1; + private final int T0_COEFF_SIZE = 13; + + private static final int MONT_R_BITS = 32; + private static final long MONT_R = 4294967296L; // 1 << MONT_R_BITS + private static final int MONT_Q = 8380417; + private static final int MONT_R_SQUARE_MOD_Q = 2365951; + private static final int MONT_Q_INV_MOD_R = 58728449; + private static final int MONT_R_MOD_Q = 4193792; + // toMont((ML_DSA_N)^-1 (mod ML_DSA_Q)) + private static final int MONT_DIM_INVERSE = 16382; + + // Zeta values for NTT with montgomery factor precomputed + private static final int[] MONT_ZETAS_FOR_NTT = new int[]{ + 25847, -2608894, -518909, 237124, -777960, -876248, 466468, 1826347, + 2353451, -359251, -2091905, 3119733, -2884855, 3111497, 2680103, 2725464, + 1024112, -1079900, 3585928, -549488, -1119584, 2619752, -2108549, -2118186, + -3859737, -1399561, -3277672, 1757237, -19422, 4010497, 280005, 2706023, + 95776, 3077325, 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, + -3043716, 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, 2071892, -2797779, -3930395, + -1528703, -3677745, -3041255, -1452451, 3475950, 2176455, -1585221, -1257611, + 1939314, -4083598, -1000202, -3190144, -3157330, -3632928, 126922, 3412210, + -983419, 2147896, 2715295, -2967645, -3693493, -411027, -2477047, -671102, + -1228525, -22981, -1308169, -381987, 1349076, 1852771, -1430430, -3343383, + 264944, 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, 189548, + -3553272, 3159746, -1851402, -2409325, -177440, 1315589, 1341330, 1285669, + -1584928, -812732, -1439742, -3019102, -3881060, -3628969, 3839961, 2091667, + 3407706, 2316500, 3817976, -3342478, 2244091, -2446433, -3562462, 266997, + 2434439, -1235728, 3513181, -3520352, -3759364, -1197226, -3193378, 900702, + 1859098, 909542, 819034, 495491, -1613174, -43260, -522500, -655327, + -3122442, 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, 2842341, + 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, 1595974, -3767016, + 1250494, 2635921, -3548272, -2994039, 1869119, 1903435, -1050970, -1333058, + 1237275, -3318210, -1430225, -451100, 1312455, 3306115, -1962642, -1279661, + 1917081, -2546312, -1374803, 1500165, 777191, 2235880, 3406031, -542412, + -2831860, -1671176, -1846953, -2584293, -3724270, 594136, -3776993, -2013608, + 2432395, 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, -3038916, + 3523897, 3866901, 269760, 2213111, -975884, 1717735, 472078, -426683, + 1723600, -1803090, 1910376, -1667432, -1104333, -260646, -3833893, -2939036, + -2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687, -554416, + 3919660, -48306, -1362209, 3937738, 1400424, -846154, 1976782 + }; + private static final int[] MONT_ZETAS_FOR_VECTOR_NTT = new int[]{ + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + + 237124, 237124, 237124, 237124, 237124, 237124, 237124, 237124, + 237124, 237124, 237124, 237124, 237124, 237124, 237124, 237124, + 237124, 237124, 237124, 237124, 237124, 237124, 237124, 237124, + 237124, 237124, 237124, 237124, 237124, 237124, 237124, 237124, + -777960, -777960, -777960, -777960, -777960, -777960, -777960, -777960, + -777960, -777960, -777960, -777960, -777960, -777960, -777960, -777960, + -777960, -777960, -777960, -777960, -777960, -777960, -777960, -777960, + -777960, -777960, -777960, -777960, -777960, -777960, -777960, -777960, + -876248, -876248, -876248, -876248, -876248, -876248, -876248, -876248, + -876248, -876248, -876248, -876248, -876248, -876248, -876248, -876248, + -876248, -876248, -876248, -876248, -876248, -876248, -876248, -876248, + -876248, -876248, -876248, -876248, -876248, -876248, -876248, -876248, + 466468, 466468, 466468, 466468, 466468, 466468, 466468, 466468, + 466468, 466468, 466468, 466468, 466468, 466468, 466468, 466468, + 466468, 466468, 466468, 466468, 466468, 466468, 466468, 466468, + 466468, 466468, 466468, 466468, 466468, 466468, 466468, 466468, + + 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, + 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, + 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, + -359251, -359251, -359251, -359251, -359251, -359251, -359251, -359251, + -359251, -359251, -359251, -359251, -359251, -359251, -359251, -359251, + -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, + -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, + 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, + 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, + -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, + -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, + 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, + 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, + 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, + + 2725464, 2725464, 2725464, 2725464, 2725464, 2725464, 2725464, 2725464, + 1024112, 1024112, 1024112, 1024112, 1024112, 1024112, 1024112, 1024112, + -1079900, -1079900, -1079900, -1079900, -1079900, -1079900, -1079900, -1079900, + 3585928, 3585928, 3585928, 3585928, 3585928, 3585928, 3585928, 3585928, + -549488, -549488, -549488, -549488, -549488, -549488, -549488, -549488, + -1119584, -1119584, -1119584, -1119584, -1119584, -1119584, -1119584, -1119584, + 2619752, 2619752, 2619752, 2619752, 2619752, 2619752, 2619752, 2619752, + -2108549, -2108549, -2108549, -2108549, -2108549, -2108549, -2108549, -2108549, + -2118186, -2118186, -2118186, -2118186, -2118186, -2118186, -2118186, -2118186, + -3859737, -3859737, -3859737, -3859737, -3859737, -3859737, -3859737, -3859737, + -1399561, -1399561, -1399561, -1399561, -1399561, -1399561, -1399561, -1399561, + -3277672, -3277672, -3277672, -3277672, -3277672, -3277672, -3277672, -3277672, + 1757237, 1757237, 1757237, 1757237, 1757237, 1757237, 1757237, 1757237, + -19422, -19422, -19422, -19422, -19422, -19422, -19422, -19422, + 4010497, 4010497, 4010497, 4010497, 4010497, 4010497, 4010497, 4010497, + 280005, 280005, 280005, 280005, 280005, 280005, 280005, 280005, + + 2706023, 2706023, 2706023, 2706023, 95776, 95776, 95776, 95776, + 3077325, 3077325, 3077325, 3077325, 3530437, 3530437, 3530437, 3530437, + -1661693, -1661693, -1661693, -1661693, -3592148, -3592148, -3592148, -3592148, + -2537516, -2537516, -2537516, -2537516, 3915439, 3915439, 3915439, 3915439, + -3861115, -3861115, -3861115, -3861115, -3043716, -3043716, -3043716, -3043716, + 3574422, 3574422, 3574422, 3574422, -2867647, -2867647, -2867647, -2867647, + 3539968, 3539968, 3539968, 3539968, -300467, -300467, -300467, -300467, + 2348700, 2348700, 2348700, 2348700, -539299, -539299, -539299, -539299, + -1699267, -1699267, -1699267, -1699267, -1643818, -1643818, -1643818, -1643818, + 3505694, 3505694, 3505694, 3505694, -3821735, -3821735, -3821735, -3821735, + 3507263, 3507263, 3507263, 3507263, -2140649, -2140649, -2140649, -2140649, + -1600420, -1600420, -1600420, -1600420, 3699596, 3699596, 3699596, 3699596, + 811944, 811944, 811944, 811944, 531354, 531354, 531354, 531354, + 954230, 954230, 954230, 954230, 3881043, 3881043, 3881043, 3881043, + 3900724, 3900724, 3900724, 3900724, -2556880, -2556880, -2556880, -2556880, + 2071892, 2071892, 2071892, 2071892, -2797779, -2797779, -2797779, -2797779, + + -3930395, -3930395, -1528703, -1528703, -3677745, -3677745, -3041255, -3041255, + -1452451, -1452451, 3475950, 3475950, 2176455, 2176455, -1585221, -1585221, + -1257611, -1257611, 1939314, 1939314, -4083598, -4083598, -1000202, -1000202, + -3190144, -3190144, -3157330, -3157330, -3632928, -3632928, 126922, 126922, + 3412210, 3412210, -983419, -983419, 2147896, 2147896, 2715295, 2715295, + -2967645, -2967645, -3693493, -3693493, -411027, -411027, -2477047, -2477047, + -671102, -671102, -1228525, -1228525, -22981, -22981, -1308169, -1308169, + -381987, -381987, 1349076, 1349076, 1852771, 1852771, -1430430, -1430430, + -3343383, -3343383, 264944, 264944, 508951, 508951, 3097992, 3097992, + 44288, 44288, -1100098, -1100098, 904516, 904516, 3958618, 3958618, + -3724342, -3724342, -8578, -8578, 1653064, 1653064, -3249728, -3249728, + 2389356, 2389356, -210977, -210977, 759969, 759969, -1316856, -1316856, + 189548, 189548, -3553272, -3553272, 3159746, 3159746, -1851402, -1851402, + -2409325, -2409325, -177440, -177440, 1315589, 1315589, 1341330, 1341330, + 1285669, 1285669, -1584928, -1584928, -812732, -812732, -1439742, -1439742, + -3019102, -3019102, -3881060, -3881060, -3628969, -3628969, 3839961, 3839961, + + 2091667, 3407706, 2316500, 3817976, -3342478, 2244091, -2446433, -3562462, + 266997, 2434439, -1235728, 3513181, -3520352, -3759364, -1197226, -3193378, + 900702, 1859098, 909542, 819034, 495491, -1613174, -43260, -522500, + -655327, -3122442, 2031748, 3207046, -3556995, -525098, -768622, -3595838, + 342297, 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, 1595974, + -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, 1903435, -1050970, + -1333058, 1237275, -3318210, -1430225, -451100, 1312455, 3306115, -1962642, + -1279661, 1917081, -2546312, -1374803, 1500165, 777191, 2235880, 3406031, + -542412, -2831860, -1671176, -1846953, -2584293, -3724270, 594136, -3776993, + -2013608, 2432395, 2454455, -164721, 1957272, 3369112, 185531, -1207385, + -3183426, 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, 472078, + -426683, 1723600, -1803090, 1910376, -1667432, -1104333, -260646, -3833893, + -2939036, -2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687, + -554416, 3919660, -48306, -1362209, 3937738, 1400424, -846154, 1976782 + }; + + private static final int[] MONT_ZETAS_FOR_VECTOR_INVERSE_NTT = new int[]{ + -1976782, 846154, -1400424, -3937738, 1362209, 48306, -3919660, 554416, + 3545687, -1612842, 976891, -183443, 2286327, 420899, 2235985, 2939036, + 3833893, 260646, 1104333, 1667432, -1910376, 1803090, -1723600, 426683, + -472078, -1717735, 975884, -2213111, -269760, -3866901, -3523897, 3038916, + 1799107, 3694233, -1652634, -810149, -3014001, -1616392, -162844, 3183426, + 1207385, -185531, -3369112, -1957272, 164721, -2454455, -2432395, 2013608, + 3776993, -594136, 3724270, 2584293, 1846953, 1671176, 2831860, 542412, + -3406031, -2235880, -777191, -1500165, 1374803, 2546312, -1917081, 1279661, + 1962642, -3306115, -1312455, 451100, 1430225, 3318210, -1237275, 1333058, + 1050970, -1903435, -1869119, 2994039, 3548272, -2635921, -1250494, 3767016, + -1595974, -2486353, -1247620, -4055324, -1265009, 2590150, -2691481, -2842341, + -203044, -1735879, 3342277, -3437287, -4108315, 2437823, -286988, -342297, + 3595838, 768622, 525098, 3556995, -3207046, -2031748, 3122442, 655327, + 522500, 43260, 1613174, -495491, -819034, -909542, -1859098, -900702, + 3193378, 1197226, 3759364, 3520352, -3513181, 1235728, -2434439, -266997, + 3562462, 2446433, -2244091, 3342478, -3817976, -2316500, -3407706, -2091667, + + -3839961, -3839961, 3628969, 3628969, 3881060, 3881060, 3019102, 3019102, + 1439742, 1439742, 812732, 812732, 1584928, 1584928, -1285669, -1285669, + -1341330, - 1341330, -1315589, -1315589, 177440, 177440, 2409325, 2409325, + 1851402, 1851402, -3159746, -3159746, 3553272, 3553272, -189548, -189548, + 1316856, 1316856, -759969, -759969, 210977, 210977, -2389356, -2389356, + 3249728, 3249728, -1653064, -1653064, 8578, 8578, 3724342, 3724342, + -3958618, -3958618, -904516, -904516, 1100098, 1100098, -44288, -44288, + -3097992, -3097992, -508951, -508951, -264944, -264944, 3343383, 3343383, + 1430430, 1430430, -1852771, -1852771, -1349076, -1349076, 381987, 381987, + 1308169, 1308169, 22981, 22981, 1228525, 1228525, 671102, 671102, + 2477047, 2477047, 411027, 411027, 3693493, 3693493, 2967645, 2967645, + -2715295, -2715295, -2147896, -2147896, 983419, 983419, -3412210, -3412210, + -126922, -126922, 3632928, 3632928, 3157330, 3157330, 3190144, 3190144, + 1000202, 1000202, 4083598, 4083598, -1939314, -1939314, 1257611, 1257611, + 1585221, 1585221, -2176455, -2176455, -3475950, -3475950, 1452451, 1452451, + 3041255, 3041255, 3677745, 3677745, 1528703, 1528703, 3930395, 3930395, + + 2797779, 2797779, 2797779, 2797779, -2071892, -2071892, -2071892, -2071892, + 2556880, 2556880, 2556880, 2556880, -3900724, -3900724, -3900724, -3900724, + -3881043, -3881043, -3881043, -3881043, -954230, -954230, -954230, -954230, + -531354, -531354, -531354, -531354, -811944, -811944, -811944, -811944, + -3699596, -3699596, -3699596, -3699596, 1600420, 1600420, 1600420, 1600420, + 2140649, 2140649, 2140649, 2140649, -3507263, -3507263, -3507263, -3507263, + 3821735, 3821735, 3821735, 3821735, -3505694, -3505694, -3505694, -3505694, + 1643818, 1643818, 1643818, 1643818, 1699267, 1699267, 1699267, 1699267, + 539299, 539299, 539299, 539299, -2348700, -2348700, -2348700, -2348700, + 300467, 300467, 300467, 300467, -3539968, -3539968, -3539968, -3539968, + 2867647, 2867647, 2867647, 2867647, -3574422, -3574422, -3574422, -3574422, + 3043716, 3043716, 3043716, 3043716, 3861115, 3861115, 3861115, 3861115, + -3915439, -3915439, -3915439, -3915439, 2537516, 2537516, 2537516, 2537516, + 3592148, 3592148, 3592148, 3592148, 1661693, 1661693, 1661693, 1661693, + -3530437, -3530437, -3530437, -3530437, -3077325, -3077325, -3077325, -3077325, + -95776, -95776, -95776, -95776, -2706023, -2706023, -2706023, -2706023, + + -280005, -280005, -280005, -280005, -280005, -280005, -280005, -280005, + -4010497, -4010497, -4010497, -4010497, -4010497, -4010497, -4010497, -4010497, + 19422, 19422, 19422, 19422, 19422, 19422, 19422, 19422, + -1757237, -1757237, -1757237, -1757237, -1757237, -1757237, -1757237, -1757237, + 3277672, 3277672, 3277672, 3277672, 3277672, 3277672, 3277672, 3277672, + 1399561, 1399561, 1399561, 1399561, 1399561, 1399561, 1399561, 1399561, + 3859737, 3859737, 3859737, 3859737, 3859737, 3859737, 3859737, 3859737, + 2118186, 2118186, 2118186, 2118186, 2118186, 2118186, 2118186, 2118186, + 2108549, 2108549, 2108549, 2108549, 2108549, 2108549, 2108549, 2108549, + -2619752, -2619752, -2619752, -2619752, -2619752, -2619752, -2619752, -2619752, + 1119584, 1119584, 1119584, 1119584, 1119584, 1119584, 1119584, 1119584, + 549488, 549488, 549488, 549488, 549488, 549488, 549488, 549488, + -3585928, -3585928, -3585928, -3585928, -3585928, -3585928, -3585928, -3585928, + 1079900, 1079900, 1079900, 1079900, 1079900, 1079900, 1079900, 1079900, + -1024112, -1024112, -1024112, -1024112, -1024112, -1024112, -1024112, -1024112, + -2725464, -2725464, -2725464, -2725464, -2725464, -2725464, -2725464, -2725464, + + -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, + -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, + -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, + -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, + 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, + 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, + -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, + -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, + 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, + 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, + 359251, 359251, 359251, 359251, 359251, 359251, 359251, 359251, + 359251, 359251, 359251, 359251, 359251, 359251, 359251, 359251, + -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, + -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, + -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, + -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, + + -466468, -466468, -466468, -466468, -466468, -466468, -466468, -466468, + -466468, -466468, -466468, -466468, -466468, -466468, -466468, -466468, + -466468, -466468, -466468, -466468, -466468, -466468, -466468, -466468, + -466468, -466468, -466468, -466468, -466468, -466468, -466468, -466468, + 876248, 876248, 876248, 876248, 876248, 876248, 876248, 876248, + 876248, 876248, 876248, 876248, 876248, 876248, 876248, 876248, + 876248, 876248, 876248, 876248, 876248, 876248, 876248, 876248, + 876248, 876248, 876248, 876248, 876248, 876248, 876248, 876248, + 777960, 777960, 777960, 777960, 777960, 777960, 777960, 777960, + 777960, 777960, 777960, 777960, 777960, 777960, 777960, 777960, + 777960, 777960, 777960, 777960, 777960, 777960, 777960, 777960, + 777960, 777960, 777960, 777960, 777960, 777960, 777960, 777960, + -237124, -237124, -237124, -237124, -237124, -237124, -237124, -237124, + -237124, -237124, -237124, -237124, -237124, -237124, -237124, -237124, + -237124, -237124, -237124, -237124, -237124, -237124, -237124, -237124, + -237124, -237124, -237124, -237124, -237124, -237124, -237124, -237124, + + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847 + }; + + // Constants defined for each security level + private final int level; + private final int tau; + private final int lambda; + private final int gamma1; + private final int gamma2; + private final int mlDsa_k; + private final int mlDsa_l; + private final int eta; + private final int beta; + private final int omega; + + // Second-class constants derived from above values + // log_2(gamma1) + private final int gamma1Bits; + // mlDsa_l * (eta + 1) * 256 / 8 + private final int s1PackedLength; + // mlDsa_k * (eta + 1) * 256 / 8 + private final int s2PackedLength; + // mlDsa_k * ML_DSA_D * 256 / 8 + private final int t0PackedLength; + // log_2(eta) + 1 + private final int s1s2CoeffSize; + // rho_size + t1_size + private final int publicKeyLength; + // c_tilde_size + z_size + h_size + private final int signatureLength; + // mlDsa_k * log_2((q-1)/(2*gamma2) - 1) * 256 / 8 + private final int wCoeffSize; + + public ML_DSA(int security_level) { + switch (security_level) { + case ML_DSA_44: + level = 2; + tau = 39; + lambda = 128; + gamma1 = 1 << 17; + gamma1Bits = 17; + gamma2 = (ML_DSA_Q - 1) / 88; + mlDsa_k = 4; + mlDsa_l = 4; + eta = 2; + beta = 78; + omega = 80; + publicKeyLength = 1312; + signatureLength = 2420; + s1PackedLength = 384; + s2PackedLength = 384; + t0PackedLength = 1664; + s1s2CoeffSize = 3; + wCoeffSize = 6; + break; + case ML_DSA_65: + level = 3; + tau = 49; + lambda = 192; + gamma1 = 1 << 19; + gamma2 = (ML_DSA_Q - 1) / 32; + mlDsa_k = 6; + mlDsa_l = 5; + eta = 4; + beta = 196; + omega = 55; + publicKeyLength = 1952; + signatureLength = 3293; + s1PackedLength = 640; + s2PackedLength = 768; + t0PackedLength = 2496; + s1s2CoeffSize = 4; + wCoeffSize = 4; + gamma1Bits = 19; + break; + case ML_DSA_87: + level = 4; + tau = 60; + lambda = 256; + gamma1 = 1 << 19; + gamma1Bits = 19; + gamma2 = (ML_DSA_Q - 1) / 32; + mlDsa_k = 8; + mlDsa_l = 7; + eta = 2; + beta = 120; + omega = 75; + publicKeyLength = 2592; + signatureLength = 4595; + s1PackedLength = 672; + s2PackedLength = 768; + t0PackedLength = 3328; + s1s2CoeffSize = 3; + wCoeffSize = 4; + break; + default: + throw new IllegalArgumentException("Wrong security level"); + } + } + + public record ML_DSA_PrivateKey(byte[] rho, byte[] k, byte[] tr, + int[][] s1, int[][] s2, int[][] t0) { + void destroy() { + Arrays.fill(k, (byte)0); + for (var b : s1) { + Arrays.fill(b, (byte) 0); + } + for (var b : s2) { + Arrays.fill(b, (byte) 0); + } + for (var b : t0) { + Arrays.fill(b, (byte) 0); + } + } + } + + public record ML_DSA_PublicKey(byte[] rho, int[][] t1) { + } + + public record ML_DSA_KeyPair(ML_DSA_PrivateKey privateKey, + ML_DSA_PublicKey publicKey) { + } + + public record ML_DSA_Signature(byte[] commitmentHash, + int[][] response, boolean[][] hint) { + } + + /* + Key validity checks + */ + public Object checkPublicKey(byte[] pk) throws InvalidKeyException { + int pk_size = 32 + (mlDsa_k * 32 * (23 - ML_DSA_D)); + if (pk.length != pk_size) { + throw new InvalidKeyException("Incorrect public key size"); + } + return null; + } + + public Object checkPrivateKey(byte[] sk) throws InvalidKeyException { + int eta_bits = eta == 4 ? 4 : 3; + + //SK size is 128 + 32 * ((l + k) * bitlen(2*eta) + d*k) + int sk_size = 128 + 32 * ((mlDsa_l + mlDsa_k) * eta_bits + ML_DSA_D * mlDsa_k); + if (sk.length != sk_size) { + throw new InvalidKeyException("Incorrect private key size"); + } + return null; + } + + //Internal functions in Section 6 of specification + public ML_DSA_KeyPair generateKeyPairInternal(byte[] randomBytes) { + //Initialize hash functions + var hash = new SHAKE256(0); + var crHash = new SHAKE256(TR_LEN); + + //Expand seed + hash.update(randomBytes); + hash.update((byte)mlDsa_k); + hash.update((byte)mlDsa_l); + byte[] rho = hash.squeeze(A_SEED_LEN); + byte[] rhoPrime = hash.squeeze(S1S2_SEED_LEN); + byte[] k = hash.squeeze(K_LEN); + hash.reset(); + + //Sample A + int[][][] keygenA = generateA(rho); //A is in NTT domain + + //Sample S1 and S2 + int[][] s1 = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + int[][] s2 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + //hash is reset before being used in sampleS1S2 + sampleS1S2(s1, s2, hash, rhoPrime); + + //Compute t and tr + mlDsaVectorNtt(s1); //s1 now in NTT domain + int[][] As1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + matrixVectorPointwiseMultiply(As1, keygenA, s1); + mlDsaVectorInverseNtt(s1); //take s1 out of NTT domain + + mlDsaVectorInverseNtt(As1); + int[][] t = vectorAddPos(As1, s2); + int[][] t0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] t1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + power2Round(t, t0, t1); + + //Encode PK and SK + ML_DSA_PublicKey pk = new ML_DSA_PublicKey(rho, t1); + byte[] publicKeyBytes = pkEncode(pk); + crHash.update(publicKeyBytes); + byte[] tr = crHash.digest(); + ML_DSA_PrivateKey sk = new ML_DSA_PrivateKey(rho, k, tr, s1, s2, t0); + + return new ML_DSA_KeyPair(sk, pk); + } + + private static int[][] deepClone(int[][] array) { + int[][] clone = new int[array.length][]; + for (int i = 0; i < array.length; i++) { + clone[i] = array[i].clone(); + } + return clone; + } + + // This is similar to the generateKeyPairInternal method. Instead of + // generating from a seed, it uses stored fields inside the private key + // to calculate the public key. It performs several checks during the + // calculation to make sure the private key is a valid one. Otherwise, + // an IllegalArgumentException is thrown. + public ML_DSA_PublicKey privKeyToPubKey(ML_DSA_PrivateKey sk) { + // Sample A + int[][][] keygenA = generateA(sk.rho); //A is in NTT domain + + // Compute t and tr + // make a copy of sk.s1 and modify it. Although we can also + // take it out of NTT domain later, it was modified for a while. + var s1 = deepClone(sk.s1); + mlDsaVectorNtt(s1); //s1 now in NTT domain + int[][] As1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + matrixVectorPointwiseMultiply(As1, keygenA, s1); + + mlDsaVectorInverseNtt(As1); + int[][] t = vectorAddPos(As1, sk.s2); + int[][] t0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] t1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + power2Round(t, t0, t1); + if (!Arrays.deepEquals(t0, sk.t0)) { + throw new IllegalArgumentException("t0 does not patch"); + } + + var crHash = new SHAKE256(TR_LEN); + + ML_DSA_PublicKey pk = new ML_DSA_PublicKey(sk.rho, t1); + byte[] publicKeyBytes = pkEncode(pk); + crHash.update(publicKeyBytes); + byte[] tr = crHash.digest(); + if (!Arrays.equals(tr, sk.tr)) { + throw new IllegalArgumentException("tr does not patch"); + } + + //Encode PK + return new ML_DSA_PublicKey(sk.rho, t1); + } + + public ML_DSA_Signature signInternal(byte[] message, byte[] rnd, byte[] skBytes) { + //Decode private key and initialize hash function + ML_DSA_PrivateKey sk = skDecode(skBytes); + var hash = new SHAKE256(0); + + //Do some NTTs + mlDsaVectorNtt(sk.s1()); + mlDsaVectorNtt(sk.s2()); + mlDsaVectorNtt(sk.t0()); + int[][][] aHat = generateA(sk.rho()); + + //Compute mu + hash.update(sk.tr()); + hash.update(message); + byte[] mu = hash.squeeze(MU_LEN); + hash.reset(); + + //Compute rho' + hash.update(sk.k()); + hash.update(rnd); + hash.update(mu); + byte[] rhoDoublePrime = hash.squeeze(MASK_SEED_LEN); + hash.reset(); + + //Initialize vectors used in loop + int[][] z = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + boolean[][] h = booleanMatrixAlloc(mlDsa_k, ML_DSA_N); + byte[] commitmentHash = new byte[lambda/4]; + int[][] y = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + int[][] yy = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + int[][] w = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] w0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] w1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] w_ct0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[] c = new int[ML_DSA_N]; + int[][] cs1 = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + int[][] cs2 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] ct0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + + int kappa = 0; + while (true) { + expandMask(y, rhoDoublePrime, kappa); + + //Save non-ntt version of y for later use + for (int i = 0; i < y.length; i++) { + System.arraycopy(y[i], 0, yy[i], 0, ML_DSA_N); + } + + //Compute w and w1 + mlDsaVectorNtt(y); //y is now in NTT domain + matrixVectorPointwiseMultiply(w, aHat, y); + mlDsaVectorInverseNtt(w); //w is now in normal domain + decompose(w, w0, w1); + + //Get commitment hash + hash.update(mu); + hash.update(simpleBitPack(wCoeffSize, w1)); + commitmentHash = hash.squeeze(lambda/4); + hash.reset(); + + //Get z and r0 + sampleInBall(c, commitmentHash); + mlDsaNtt(c); //c is now in NTT domain + nttConstMultiply(cs1, c, sk.s1()); + nttConstMultiply(cs2, c, sk.s2()); + mlDsaVectorInverseNtt(cs1); + mlDsaVectorInverseNtt(cs2); + z = vectorAdd(z, yy, cs1); + + //w0 = w0 - cs2 (this is r0 in the spec) + vectorSub(w0, cs2, false); + + //Update z and h + kappa += mlDsa_l; + if (vectorNormBound(z, gamma1 - beta) || + vectorNormBound(w0, gamma2 - beta)) { + continue; + } else { + nttConstMultiply(ct0, c, sk.t0()); + mlDsaVectorInverseNtt(ct0); + w = vectorSub(w, cs2, false); + int hint_weight = makeHint(h, w, vectorAdd(w_ct0, w, ct0)); + if (vectorNormBound(ct0, gamma2) || (hint_weight > omega)) { + continue; + } + } + sk.destroy(); + return new ML_DSA_Signature(commitmentHash, z, h); + } + } + + public boolean verifyInternal(byte[] pkBytes, byte[] message, byte[] sigBytes) + throws SignatureException { + //Decode sig and initialize hash + ML_DSA_Signature sig = sigDecode(sigBytes); + var hash = new SHAKE256(0); + + //Decode pk + ML_DSA_PublicKey pk = pkDecode(pkBytes); + + //Expand A + int[][][] aHat = generateA(pk.rho()); + + //Generate tr + hash.update(pkBytes); + byte[] tr = hash.squeeze(TR_LEN); + hash.reset(); + + //Generate mu + hash.update(tr); + hash.update(message); + byte[] mu = hash.squeeze(MU_LEN); + hash.reset(); + + //Get verifiers challenge + int[] cHat = new int[ML_DSA_N]; + sampleInBall(cHat, sig.commitmentHash()); + mlDsaNtt(cHat); + + //Compute response norm and put it in NTT domain + boolean zNorm = vectorNormBound(sig.response(), gamma1 - beta); + mlDsaVectorNtt(sig.response()); + + //Reconstruct signer's commitment + int[][] aHatZ = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + matrixVectorPointwiseMultiply(aHatZ, aHat, sig.response()); + + int[][] t1Hat = vectorConstMul(1 << ML_DSA_D, pk.t1()); + mlDsaVectorNtt(t1Hat); + + int[][] ct1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + nttConstMultiply(ct1, cHat, t1Hat); + + int[][] wApprox = vectorSub(aHatZ, ct1, true); + mlDsaVectorInverseNtt(wApprox); + int[][] w1Prime = useHint(sig.hint(), wApprox); + + //Hash signer's commitment + hash.update(mu); + hash.update(simpleBitPack(wCoeffSize, w1Prime)); + byte[] cTildePrime = hash.squeeze(lambda/4); + + //Check verify conditions + boolean hashEq = MessageDigest.isEqual(sig.commitmentHash(), cTildePrime); + return !zNorm && hashEq; + } + + /* + Data conversion functions in Section 7.1 of specification + */ + + // Bit-pack the t1 and w1 vector into a byte array. + // The coefficients of the polynomials in the vector should be + // nonnegative and less than 2^bitsPerCoeff . + public byte[] simpleBitPack(int bitsPerCoeff, int[][] vector) { + byte[] result = new byte[(mlDsa_k * ML_DSA_N * bitsPerCoeff) / 8]; + int acc = 0; + int shift = 0; + int i = 0; + for (int[] poly : vector) { + for (int m = 0; m < ML_DSA_N; m++) { + acc += (poly[m] << shift); + shift += bitsPerCoeff; + while (shift >= 8) { + result[i++] = (byte) acc; + acc >>= 8; + shift -= 8; + } + } + } // Shift must now be 0 so we have all output bits + return result; + } + + public void bitPack(int[][] vector, int bitsPerCoeff, int maxValue, + byte[] output, int offset) { + int vecLen = vector.length; + int acc = 0; + int shift = 0; + for (int[] poly : vector) { + for (int m = 0; m < ML_DSA_N; m++) { + acc += (maxValue - poly[m]) << shift; + shift += bitsPerCoeff; + while (shift >= 8) { + output[offset++] = (byte) acc; + acc >>= 8; + shift -= 8; + } + } + } + } + + //This is simpleBitUnpack from FIPS 204. Since it is only called on the + //vector t1 we can optimize for that case + public int[][] t1Unpack(byte[] v) { + int[][] t1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + for (int i = 0; i < mlDsa_k; i++) { + for (int j = 0; j < ML_DSA_N / 4; j++) { + int tOffset = j*4; + int vOffset = (i*320) + (j*5); + t1[i][tOffset] = (v[vOffset] & 0xFF) + + ((v[vOffset+1] << 8) & 0x3FF); + t1[i][tOffset+1] = ((v[vOffset+1] >> 2) & 0x3F) + + ((v[vOffset+2] << 6) & 0x3FF); + t1[i][tOffset+2] = ((v[vOffset+2] >> 4) & 0xF) + + ((v[vOffset+3] << 4) & 0x3FF); + t1[i][tOffset+3] = ((v[vOffset+3] >> 6) & 0x3) + + ((v[vOffset+4] << 2) & 0x3FF); + } + } + return t1; + } + + public int[][] bitUnpack(int[][] result, byte[] v, int offset, int dim, + int maxValue, int bitsPerCoeff) { + + switch (bitsPerCoeff) { + case 3 -> { bitUnpackGeneral(result, v, offset, dim, maxValue, 3); } + case 4 -> { bitUnpackGeneral(result, v, offset, dim, maxValue, 4); } + case 13 -> { bitUnpackGeneral(result, v, offset, dim, maxValue, 13); } + case 18 -> { bitUnpack18(result, v, offset, dim, maxValue); } + case 20 -> { bitUnpack20(result, v, offset, dim, maxValue); } + default -> throw new RuntimeException( + "Wrong bitsPerCoeff value in bitUnpack (" + bitsPerCoeff + ")."); + } + return result; + } + public void bitUnpackGeneral(int[][] result, + byte[] v, int offset, int dim, int maxValue, int bitsPerCoeff) { + + int mask = (1 << bitsPerCoeff) - 1; + int top = 0; + int shift = 0; + int acc = 0; + for (int i = 0; i < dim; i++) { + for (int j = 0; j < ML_DSA_N; j++) { + while (top - shift < bitsPerCoeff) { + acc += ((v[offset++] & 0xff) << top); + top += 8; + } + result[i][j] = maxValue - ((acc >> shift) & mask); + shift += bitsPerCoeff; + while (shift >= 8) { + top -= 8; + shift -= 8; + acc >>>= 8; + } + } + } + } + public void bitUnpack18(int [][] result, byte[] v, int offset, + int dim, int maxValue) { + + int vIndex = offset; + for (int i = 0; i < dim; i++) { + for (int j = 0; j < ML_DSA_N; j += 4) { + result[i][j] = maxValue - ((v[vIndex] & 0xff) + + ((v[vIndex + 1] & 0xff) << 8) + + ((v[vIndex + 2] & 0x3) << 16)); + result[i][j + 1] = maxValue - (((v[vIndex + 2] >> 2) & 0x3f) + + ((v[vIndex + 3] & 0xff) << 6) + + ((v[vIndex + 4] & 0xf) << 14)); + result[i][j + 2] = maxValue - (((v[vIndex + 4] >> 4) & 0xf) + + ((v[vIndex + 5] & 0xff) << 4) + + ((v[vIndex + 6] & 0x3f) << 12)); + result[i][j + 3] = maxValue - (((v[vIndex + 6] >> 6) & 0x3) + + ((v[vIndex + 7] & 0xff) << 2) + + ((v[vIndex + 8] & 0xff) << 10)); + vIndex += 9; + } + } + } + + public void bitUnpack20(int[][] result, byte[] v, int offset, + int dim, int maxValue) { + int vIndex = offset; + + for (int i = 0; i < dim; i++) { + for (int j = 0; j < ML_DSA_N; j += 2) { + result[i][j] = maxValue - ((v[vIndex] & 0xff) + + ((v[vIndex + 1] & 0xff) << 8) + + ((v[vIndex + 2] & 0xf) << 16)); + result[i][j + 1] = maxValue - (((v[vIndex + 2] >> 4) & 0xf) + + ((v[vIndex + 3] & 0xff) << 4) + + ((v[vIndex + 4] & 0xff) << 12)); + vIndex += 5; + } + } + } + + private void hintBitPack(boolean[][] h, byte[] buffer, int offset) { + int idx = 0; + for (int i = 0; i < mlDsa_k; i++) { + for (int j = 0; j < ML_DSA_N; j++) { + if (h[i][j]) { + buffer[offset + idx] = (byte)j; + idx++; + } + } + buffer[offset + omega + i] = (byte)idx; + } + } + + private boolean[][] hintBitUnpack(byte[] y, int offset) { + boolean[][] h = booleanMatrixAlloc(mlDsa_k, ML_DSA_N); + int idx = 0; + for (int i = 0; i < mlDsa_k; i++) { + int j = y[offset + omega + i]; + if (j < idx || j > omega) { + return null; + } + int first = idx; + while (idx < j) { + if (idx > first) { + if ((y[offset + idx - 1] & 0xff) >= (y[offset + idx] & 0xff)) { + return null; + } + } + int hintIndex = y[offset + idx] & 0xff; + h[i][hintIndex] = true; + idx++; + } + } + + while (idx < omega) { + if (y[offset + idx] != 0) { + return null; + } + idx++; + } + return h; + } + + /* + Encoding functions as specified in Section 7.2 of the specification + */ + + public byte[] pkEncode(ML_DSA_PublicKey key) { + byte[] t1Packed = simpleBitPack(10, key.t1); + byte[] publicKeyBytes = new byte[A_SEED_LEN + t1Packed.length]; + System.arraycopy(key.rho, 0, publicKeyBytes, 0, A_SEED_LEN); + System.arraycopy(t1Packed, 0, publicKeyBytes, A_SEED_LEN, t1Packed.length); + + return publicKeyBytes; + } + + public ML_DSA_PublicKey pkDecode(byte[] pk) { + byte[] rho = Arrays.copyOfRange(pk, 0, A_SEED_LEN); + byte[] v = Arrays.copyOfRange(pk, A_SEED_LEN, pk.length); + int[][] t1 = t1Unpack(v); + return new ML_DSA_PublicKey(rho, t1); + } + + public byte[] skEncode(ML_DSA_PrivateKey key) { + + byte[] skBytes = new byte[A_SEED_LEN + K_LEN + key.tr.length + + s1PackedLength + s2PackedLength + t0PackedLength]; + + int pos = 0; + System.arraycopy(key.rho, 0, skBytes, pos, A_SEED_LEN); + pos += A_SEED_LEN; + System.arraycopy(key.k, 0, skBytes, pos, K_LEN); + pos += K_LEN; + System.arraycopy(key.tr, 0, skBytes, pos, TR_LEN); + pos += TR_LEN; + + bitPack(key.s1, s1s2CoeffSize, eta, skBytes, pos); + pos += s1PackedLength; + bitPack(key.s2, s1s2CoeffSize, eta, skBytes, pos); + pos += s2PackedLength; + bitPack(key.t0, T0_COEFF_SIZE, 1 << 12, skBytes, pos); + + return skBytes; + } + + public ML_DSA_PrivateKey skDecode(byte[] sk) { + byte[] rho = new byte[A_SEED_LEN]; + System.arraycopy(sk, 0, rho, 0, A_SEED_LEN); + + byte[] k = new byte[K_LEN]; + System.arraycopy(sk, A_SEED_LEN, k, 0, K_LEN); + + byte[] tr = new byte[TR_LEN]; + System.arraycopy(sk, A_SEED_LEN + K_LEN, tr, 0, TR_LEN); + + //Parse s1 + int start = A_SEED_LEN + K_LEN + TR_LEN; + int end = start + (32 * mlDsa_l * s1s2CoeffSize); + int[][] s1 = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + bitUnpack(s1, sk, start, mlDsa_l, eta, s1s2CoeffSize); + + //Parse s2 + start = end; + end += 32 * s1s2CoeffSize * mlDsa_k; + int[][] s2 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + bitUnpack(s2, sk, start, mlDsa_k, eta, s1s2CoeffSize); + + //Parse t0 + start = end; + int[][] t0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + bitUnpack(t0, sk, start, mlDsa_k, 1 << 12, T0_COEFF_SIZE); + + return new ML_DSA_PrivateKey(rho, k, tr, s1, s2, t0); + } + + public byte[] sigEncode(ML_DSA_Signature sig) { + int cSize = lambda / 4; + int zSize = mlDsa_l * 32 * (1 + gamma1Bits); + + byte[] sigBytes = new byte[cSize + zSize + omega + mlDsa_k]; + + System.arraycopy(sig.commitmentHash, 0, sigBytes, 0, cSize); + bitPack(sig.response, gamma1Bits + 1, gamma1, sigBytes, cSize); + hintBitPack(sig.hint, sigBytes, cSize + zSize); + + return sigBytes; + } + + public ML_DSA_Signature sigDecode(byte[] sig) throws SignatureException { + + int cSize = lambda / 4; + int zSize = mlDsa_l * 32 * (1 + gamma1Bits); + + int sigLen = cSize + zSize + omega + mlDsa_k; + if (sig.length != sigLen) { + throw new SignatureException("Incorrect signature length"); + } + + //Decode cTilde + byte[] cTilde = Arrays.copyOfRange(sig, 0, lambda/4); + + //Decode z + int start = cSize; + int end = start + zSize; + int[][] z = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + bitUnpack(z, sig, start, mlDsa_l, gamma1, gamma1Bits + 1); + + //Decode h + start = end; + boolean[][] h = hintBitUnpack(sig, start); + if (h == null) { + throw new SignatureException("Invalid hints encoding"); + } + + return new ML_DSA_Signature(cTilde, z, h); + } + + /* + Auxiliary functions defined in Section 7.3 of specification + */ + + private class Shake256Slicer { + SHAKE256 xof; + byte[] block; + int byteOffset; + int current; + int bitsInCurrent; + int bitsPerCall; + int bitMask; + + Shake256Slicer(SHAKE256 xof, int bitsPerCall) { + this.xof = xof; + //BitsPerCall can only be 4 (when called from sampleS1S2), + //or 8 (when called from sampleInBall) + this.bitsPerCall = bitsPerCall; + bitMask = (1 << bitsPerCall) - 1; + current = 0; + byteOffset = SHAKE256_BLOCK_SIZE; + bitsInCurrent = 0; + block = new byte[SHAKE256_BLOCK_SIZE]; + } + + void reset() { + xof.reset(); + current = 0; + byteOffset = SHAKE256_BLOCK_SIZE; + bitsInCurrent = 0; + } + + int squeezeBits() { + while (bitsInCurrent < bitsPerCall) { + if (byteOffset == SHAKE256_BLOCK_SIZE) { + xof.squeeze(block, 0, SHAKE256_BLOCK_SIZE); + byteOffset = 0; + } + current += ((block[byteOffset++] & 0xff) << bitsInCurrent); + bitsInCurrent += 8; + } + int result = current & bitMask; + current >>= bitsPerCall; + bitsInCurrent -= bitsPerCall; + return result; + } + } + + private void sampleInBall(int[] c, byte[] rho) { + var xof = new SHAKE256(0); + Shake256Slicer slicer = new Shake256Slicer(xof, 8); + xof.update(rho); + + long parity = 0; + for (int i = 0; i < 8; i++) { + long sample = slicer.squeezeBits(); + parity |= sample << 8 * i; + } + + Arrays.fill(c, 0); + + int k = 8; + for (int i = 256 - tau; i < 256; i++) { + //Get random index < i + int j = slicer.squeezeBits(); + while (j > i) { + j = slicer.squeezeBits(); + } + + //Swap c[i] and c[j], set c[j] based on parity + c[i] = c[j]; + c[j] = (int) (1 - 2 * (parity & 1)); + parity >>= 1; + } + } + + private int[][][] generateA(byte[] seed) { + + // Manually do multidimensional array initialization for performance + int[][][] a = new int[mlDsa_k][][]; + for (int i = 0; i < mlDsa_k; i++) { + a[i] = new int[mlDsa_l][]; + } + + int nrPar = 2; + int rhoLen = seed.length; + byte[] seedBuf = new byte[SHAKE128_BLOCK_SIZE]; + System.arraycopy(seed, 0, seedBuf, 0, seed.length); + seedBuf[rhoLen + 2] = 0x1F; + seedBuf[SHAKE128_BLOCK_SIZE - 1] = (byte)0x80; + byte[][] xofBufArr = new byte[nrPar][SHAKE128_BLOCK_SIZE]; + int[] iIndex = new int[nrPar]; + int[] jIndex = new int[nrPar]; + + int[] parsedBuf = new int[SHAKE128_BLOCK_SIZE / 3]; + + int parInd = 0; + boolean allDone; + int[] ofs = new int[nrPar]; + Arrays.fill(ofs, 0); + int[][] aij = new int[nrPar][]; + try { + Shake128Parallel parXof = new Shake128Parallel(xofBufArr); + + for (int i = 0; i < mlDsa_k; i++) { + for (int j = 0; j < mlDsa_l; j++) { + xofBufArr[parInd] = seedBuf.clone(); + xofBufArr[parInd][rhoLen] = (byte) j; + xofBufArr[parInd][rhoLen + 1] = (byte) i; + iIndex[parInd] = i; + jIndex[parInd] = j; + ofs[parInd] = 0; + aij[parInd] = new int[ML_DSA_N]; + parInd++; + + if ((parInd == nrPar) || + ((i == mlDsa_k - 1) && (j == mlDsa_l - 1))) { + parXof.reset(xofBufArr); + + allDone = false; + while (!allDone) { + allDone = true; + parXof.squeezeBlock(); + for (int k = 0; k < parInd; k++) { + int parsedOfs = 0; + int tmp; + if (ofs[k] < ML_DSA_N) { + for (int l = 0; l < SHAKE128_BLOCK_SIZE; l += 3) { + byte[] rawBuf = xofBufArr[k]; + parsedBuf[l / 3] = (rawBuf[l] & 0xFF) + + ((rawBuf[l + 1] & 0xFF) << 8) + + ((rawBuf[l + 2] & 0x7F) << 16); + } + } + while ((ofs[k] < ML_DSA_N) && + (parsedOfs < SHAKE128_BLOCK_SIZE / 3)) { + tmp = parsedBuf[parsedOfs++]; + if (tmp < ML_DSA_Q) { + aij[k][ofs[k]] = tmp; + ofs[k]++; + } + } + if (ofs[k] < ML_DSA_N) { + allDone = false; + } + } + } + + for (int k = 0; k < parInd; k++) { + a[iIndex[k]][jIndex[k]] = aij[k]; + } + parInd = 0; + } + } + } + } catch (InvalidAlgorithmParameterException e) { + // This should never happen since xofBufArr is of the correct size + throw new RuntimeException("Internal error."); + } + + return a; + } + + private void sampleS1S2(int[][] s1, int[][] s2, SHAKE256 xof, byte[] rhoPrime) { + byte[] seed = new byte[S1S2_SEED_LEN + 2]; + System.arraycopy(rhoPrime, 0, seed, 0, S1S2_SEED_LEN); + + Shake256Slicer slicer = new Shake256Slicer(xof, 4); + for (int i = 0; i < mlDsa_l; i++) { + seed[S1S2_SEED_LEN] = (byte) i; + seed[S1S2_SEED_LEN + 1] = 0; + slicer.reset(); + xof.update(seed); + if (eta == 2) { + for (int j = 0; j < ML_DSA_N; j++) { + int sample; + do { + sample = slicer.squeezeBits(); + } while (sample > 14); + // 2 - sample mod 5 + s1[i][j] = eta - sample + (205 * sample >> 10) * 5; + } + } else { // eta == 4 + for (int j = 0; j < ML_DSA_N; j++) { + int sample; + do { + sample = slicer.squeezeBits(); + } while (sample > 2 * eta); + s1[i][j] = eta - sample; + } + } + } + for (int i = 0; i < mlDsa_k; i++) { + seed[S1S2_SEED_LEN] = (byte) (mlDsa_l + i); + seed[S1S2_SEED_LEN + 1] = 0; + slicer.reset(); + xof.update(seed); + if (eta == 2) { + for (int j = 0; j < ML_DSA_N; j++) { + int sample; + do { + sample = slicer.squeezeBits(); + } while (sample > 14); + s2[i][j] = eta - sample + (205 * sample >> 10) * 5; + } + } else { + for (int j = 0; j < ML_DSA_N; j++) { + int sample; + do { + sample = slicer.squeezeBits(); + } while (sample > 2 * eta); + s2[i][j] = eta - sample; + } + } + } + } + + private void expandMask(int[][] result, byte[] rho, int mu) { + var xof = new SHAKE256(0); + + int c = 1 + gamma1Bits; + byte[] v = new byte[mlDsa_l * 32 * c]; + for (int r = 0; r < mlDsa_l; r++) { + int a = mu + r; + byte[] n = {(byte) a, (byte) (a >> 8)}; + + xof.update(rho); + xof.update(n); + xof.squeeze(v, r * 32 * c, 32 * c); + xof.reset(); + } + bitUnpack(result, v, 0, mlDsa_l, gamma1, c); + } + + /* + Auxiliary functions defined in section 7.4 of specification + */ + + private void power2Round(int[][] input, int[][] lowPart, int[][] highPart) { + for (int i = 0; i < mlDsa_k; i++) { + for (int m = 0; m < ML_DSA_N; m++) { + int rplus = input[i][m]; + int r0 = input[i][m] & D_MASK; + int r00 = (1 << (ML_DSA_D - 1)) - r0 ; // 2^d/2 - r+ + r0 -= (r00 >> 31) & (1 << ML_DSA_D); //0 if r+ < 2^d/2 + lowPart[i][m] = r0; + highPart[i][m] = (rplus - r0) >> ML_DSA_D; + } + } + } + + private void decompose(int[][] input, int[][] lowPart, int[][] highPart) { + int multiplier = (gamma2 == 95232 ? 22 : 8); + for (int i = 0; i < mlDsa_k; i++) { + mlDsaDecomposePoly(input[i], lowPart[i], + highPart[i], gamma2 * 2, multiplier); + } + } + + private int[][] highBits(int[][] input) { + int[][] lowPart = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] highPart = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + decompose(input, lowPart, highPart); + return highPart; + } + + //Creates the hint polynomial and returns its hamming weight + private int makeHint(boolean[][] res, int[][] z, int[][] r) { + int hammingWeight = 0; + int[][] r1 = highBits(r); + int[][] v1 = highBits(z); + for (int i = 0; i < mlDsa_k; i++) { + for (int j = 0; j < ML_DSA_N; j++) { + if (r1[i][j] != v1[i][j]) { + res[i][j] = true; + hammingWeight++; + } else { + res[i][j] = false; + } + } + } + return hammingWeight; + } + + private int[][] useHint(boolean[][] h, int[][] r) { + int m = (ML_DSA_Q - 1) / (2*gamma2); + int[][] lowPart = r; + int[][] highPart = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + decompose(r, lowPart, highPart); + + for (int i = 0; i < mlDsa_k; i++) { + for (int j = 0; j < ML_DSA_N; j++) { + if (h[i][j]) { + highPart[i][j] += lowPart[i][j] > 0 ? 1 : -1; + } + highPart[i][j] = ((highPart[i][j] % m) + m) % m; + } + } + return highPart; + } + + /* + NTT functions as specified in Section 7.5 of specification + */ + + public static void mlDsaNtt(int[] coeffs) { + assert coeffs.length == ML_DSA_N; + implDilithiumAlmostNtt(coeffs, MONT_ZETAS_FOR_VECTOR_NTT); + implDilithiumMontMulByConstant(coeffs, MONT_R_MOD_Q); + } + + @IntrinsicCandidate + static int implDilithiumAlmostNtt(int[] coeffs, int[] zetas) { + implDilithiumAlmostNttJava(coeffs); + return 1; + } + + static void implDilithiumAlmostNttJava(int[] coeffs) { + int dimension = ML_DSA_N; + int m = 0; + for (int l = dimension / 2; l > 0; l /= 2) { + for (int s = 0; s < dimension; s += 2 * l) { + for (int j = s; j < s + l; j++) { + int tmp = montMul(MONT_ZETAS_FOR_NTT[m], coeffs[j + l]); + coeffs[j + l] = coeffs[j] - tmp; + coeffs[j] = coeffs[j] + tmp; + } + m++; + } + } + } + + public static void mlDsaInverseNtt(int[] coeffs) { + assert coeffs.length == ML_DSA_N; + implDilithiumAlmostInverseNtt(coeffs, MONT_ZETAS_FOR_VECTOR_INVERSE_NTT); + implDilithiumMontMulByConstant(coeffs, MONT_DIM_INVERSE); + } + + @IntrinsicCandidate + static int implDilithiumAlmostInverseNtt(int[] coeffs, int[] zetas) { + implDilithiumAlmostInverseNttJava(coeffs); + return 1; + } + + static void implDilithiumAlmostInverseNttJava(int[] coeffs) { + int dimension = ML_DSA_N; + int m = MONT_ZETAS_FOR_NTT.length - 1; + for (int l = 1; l < dimension; l *= 2) { + for (int s = 0; s < dimension; s += 2 * l) { + for (int j = s; j < s + l; j++) { + int tmp = coeffs[j]; + coeffs[j] = (tmp + coeffs[j + l]); + coeffs[j + l] = montMul(tmp - coeffs[j + l], + -MONT_ZETAS_FOR_NTT[m]); + } + m--; + } + } + } + + void mlDsaVectorNtt(int[][] vector) { + for (int[] ints : vector) { + mlDsaNtt(ints); + } + } + + void mlDsaVectorInverseNtt(int[][] vector) { + for (int[] ints : vector) { + mlDsaInverseNtt(ints); + } + } + + public static void mlDsaNttMultiply(int[] product, int[] coeffs1, int[] coeffs2) { + assert (coeffs1.length == ML_DSA_N) && (coeffs2.length == ML_DSA_N); + implDilithiumNttMult(product, coeffs1, coeffs2); + } + + + @IntrinsicCandidate + static int implDilithiumNttMult(int[] product, int[] coeffs1, int[] coeffs2) { + implDilithiumNttMultJava(product, coeffs1, coeffs2); + return 1; + } + + static void implDilithiumNttMultJava(int[] product, int[] coeffs1, int[] coeffs2) { + for (int i = 0; i < ML_DSA_N; i++) { + product[i] = montMul(coeffs1[i], toMont(coeffs2[i])); + } + } + + @IntrinsicCandidate + static int implDilithiumMontMulByConstant(int[] coeffs, int constant) { + implDilithiumMontMulByConstantJava(coeffs, constant); + return 1; + } + + static void implDilithiumMontMulByConstantJava(int[] coeffs, int constant) { + for (int i = 0; i < ML_DSA_N; i++) { + coeffs[i] = montMul((coeffs[i]), constant); + } + } + + public static void mlDsaDecomposePoly(int[] input, int[] lowPart, int[] highPart, + int twoGamma2, int multiplier) { + assert (input.length == ML_DSA_N) && (lowPart.length == ML_DSA_N) + && (highPart.length == ML_DSA_N); + implDilithiumDecomposePoly(input, lowPart, highPart,twoGamma2, multiplier); + } + + @IntrinsicCandidate + static int implDilithiumDecomposePoly(int[] input, int[] lowPart, int[] highPart, + int twoGamma2, int multiplier) { + decomposePolyJava(input, lowPart, highPart, twoGamma2, multiplier); + return 1; + } + + static void decomposePolyJava(int[] input, int[] lowPart, int[] highPart, + int twoGamma2, int multiplier) { + int dilithiumBarrettAddend = 5373807; + for (int m = 0; m < ML_DSA_N; m++) { + int rplus = input[m]; + rplus -= ((rplus + dilithiumBarrettAddend) >> 23) * ML_DSA_Q; + rplus += ((rplus >> 31) & ML_DSA_Q); + + int quotient = (rplus * multiplier) >> 22; + int r0 = rplus - quotient * twoGamma2; + int mask = (twoGamma2 - r0) >> 22; + r0 -= (mask & twoGamma2); + quotient += (mask & 1); + mask = (twoGamma2 / 2 - r0) >> 31; + r0 -= (mask & twoGamma2); + quotient += (mask & 1); + + int r1 = rplus - r0 - (ML_DSA_Q - 1); + r1 = (r1 | (-r1)) >> 31; // 0 if rplus - r0 == (dilithium_q - 1), -1 otherwise + r0 += ~r1; + // quotient = (rplus - r0) / twoGamma2; + r1 = r1 & quotient; + + lowPart[m] = r0; + highPart[m] = r1; + } + } + + private void matrixVectorPointwiseMultiply(int[][] res, int[][][] matrix, + int[][] vector) { + + int resulti[] = new int[ML_DSA_N]; + int[] product = new int[ML_DSA_N]; + for (int i = 0; i < mlDsa_k; i++) { + for (int m = 0; m < ML_DSA_N; m++) { + resulti[m] = 0; + } + for (int j = 0; j < mlDsa_l; j++) { + mlDsaNttMultiply(product, matrix[i][j], vector[j]); + for (int m = 0; m < ML_DSA_N; m++) { + resulti[m] += product[m]; + } + } + for (int m = 0; m < ML_DSA_N; m++) { + res[i][m] = montMul(resulti[m], MONT_R_MOD_Q); + } + } + } + + private void nttConstMultiply(int[][] res, int[] a, int[][] b) { + for (int i = 0; i < b.length; i++) { + mlDsaNttMultiply(res[i], a, b[i]); + } + } + + private int[][] vectorConstMul(int c, int[][] vec) { + int[][] res = integerMatrixAlloc(vec.length, vec[0].length); + for (int i = 0; i < vec.length; i++) { + for (int j = 0; j < vec[0].length; j++) { + res[i][j] = montMul(c, toMont(vec[i][j])); + } + } + return res; // -q < res[i][j] < q + } + + // Adds two vectors of polynomials + // The coefficients in the input should be between -MONT_Q and MONT_Q . + // The coefficients in the output will be nonnegative and less than MONT_Q + int[][] vectorAddPos(int[][] vec1, int[][] vec2) { + int dim = vec1.length; + int[][] result = integerMatrixAlloc(dim, ML_DSA_N); + for (int i = 0; i < dim; i++) { + for (int m = 0; m < ML_DSA_N; m++) { + int r = vec1[i][m] + vec2[i][m]; // -2 * MONT_Q < r < 2 * MONT_Q + r += (((r >> 31) & (2 * MONT_Q)) - MONT_Q); // -MONT_Q < r < MONT_Q + r += ((r >> 31) & MONT_Q); // 0 <= r < MONT_Q + result[i][m] = r; + } + } + return result; + } + + int[][] vectorAdd(int[][] result, int[][] vec1, int[][] vec2) { + for (int i = 0; i < result.length; i++) { + for (int j = 0; j < ML_DSA_N; j++) { + int tmp = vec1[i][j] + vec2[i][j]; + result[i][j] = tmp; + } + } + return result; + } + + int[][] vectorSub(int[][] vec1, int[][] vec2, boolean needsAdjustment) { + int dim = vec1.length; + for (int i = 0; i < dim; i++) { + for (int j = 0; j < ML_DSA_N; j++) { + int tmp = vec1[i][j] - vec2[i][j]; + if (needsAdjustment) { + if (tmp <= -ML_DSA_Q) { + tmp += ML_DSA_Q; + } else if (tmp >= ML_DSA_Q) { + tmp -= ML_DSA_Q; + } + } + vec1[i][j] = tmp; + } + } + return vec1; + } + + //Precondition: 2^-31 <= r1 <= 2^31 - 5 * 2^20, and bound < q - 5234431 + //Computes whether the infinity norm of a vector is >= bound + boolean vectorNormBound(int[][] vec, int bound) { + boolean res = false; + for (int i = 0; i < vec.length; i++) { + for (int j = 0; j < ML_DSA_N; j++) { + int r1 = vec[i][j]; + r1 = r1 - ((r1 + (5 << 20)) >> 23) * ML_DSA_Q; + r1 = r1 - ((r1 >> 31) & r1) * 2; + res |= (r1 >= bound); + } + } + return res; + } + + // precondition: -2^31 * MONT_Q <= a, b < 2^31, -2^31 < a * b < 2^31 * MONT_Q + // computes a * b * 2^-32 mod MONT_Q + // the result is greater than -MONT_Q and less than MONT_Q + // See e.g. Algorithm 3 in https://eprint.iacr.org/2018/039.pdf + private static int montMul(int b, int c) { + long a = (long) b * (long) c; + int aHigh = (int) (a >> MONT_R_BITS); + int aLow = (int) a; + int m = MONT_Q_INV_MOD_R * aLow; // signed low product + + // subtract signed high product + return (aHigh - (int) (((long)m * MONT_Q) >> MONT_R_BITS)); + } + + static int toMont(int a) { + return montMul(a, MONT_R_SQUARE_MOD_Q); + } + + // For multidimensional array initialization, manually allocating each entry is + // faster than doing the entire initialization in one go + static boolean[][] booleanMatrixAlloc(int first, int second) { + boolean[][] res = new boolean[first][]; + for (int i = 0; i < first; i++) { + res[i] = new boolean[second]; + } + return res; + } + + static int[][] integerMatrixAlloc(int first, int second) { + int[][] res = new int[first][]; + for (int i = 0; i < first; i++) { + res[i] = new int[second]; + } + return res; + } +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/ML_DSA_Impls.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/ML_DSA_Impls.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/ML_DSA_Impls.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/ML_DSA_Impls.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,272 @@ +/* + * 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. 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.provider; + +import sun.security.jca.JCAUtil; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.util.KeyChoices; +import sun.security.x509.NamedX509Key; + +import java.security.*; +import java.security.SecureRandom; +import java.util.Arrays; + +public class ML_DSA_Impls { + + private static final int SEED_LEN = 32; + + public static byte[] seedToExpanded(String pname, byte[] seed) { + var impl = new ML_DSA(name2int(pname)); + var sk = impl.generateKeyPairInternal(seed).privateKey(); + try { + return impl.skEncode(sk); + } finally { + sk.destroy(); + } + } + + public static NamedX509Key privKeyToPubKey(NamedPKCS8Key npk) { + var dsa = new ML_DSA(name2int(npk.getParams().getName())); + return new NamedX509Key(npk.getAlgorithm(), + npk.getParams().getName(), + dsa.pkEncode(dsa.privKeyToPubKey(dsa.skDecode(npk.getExpanded())))); + } + + public enum Version { + DRAFT, FINAL + } + + // This implementation works in FIPS 204 final. If for some reason + // (for example, interop with an old version, or running an old test), + // set the version to an older one. The following VM option is required: + // + // --add-exports java.base/sun.security.provider=ALL-UNNAMED + public static Version version = Version.FINAL; + + static int name2int(String pname) { + if (pname.endsWith("44")) { + return 2; + } else if (pname.endsWith("65")) { + return 3; + } else if (pname.endsWith("87")) { + return 5; + } else { + // should not happen + throw new ProviderException("Unknown name " + pname); + } + } + + public sealed static class KPG + extends NamedKeyPairGenerator permits KPG2, KPG3, KPG5 { + + public KPG() { + // ML-DSA-65 is default + super("ML-DSA", "ML-DSA-65", "ML-DSA-44", "ML-DSA-87"); + } + + public KPG(String pname) { + super("ML-DSA", pname); + } + + @Override + protected byte[][] implGenerateKeyPair(String pname, SecureRandom random) { + byte[] seed = new byte[SEED_LEN]; + var r = random != null ? random : JCAUtil.getDefSecureRandom(); + r.nextBytes(seed); + + ML_DSA mlDsa = new ML_DSA(name2int(pname)); + ML_DSA.ML_DSA_KeyPair kp = mlDsa.generateKeyPairInternal(seed); + var expanded = mlDsa.skEncode(kp.privateKey()); + + try { + return new byte[][]{ + mlDsa.pkEncode(kp.publicKey()), + KeyChoices.writeToChoice( + KeyChoices.getPreferred("mldsa"), + seed, expanded), + expanded + }; + } finally { + kp.privateKey().destroy(); + Arrays.fill(seed, (byte) 0); + } + } + } + + public final static class KPG2 extends KPG { + public KPG2() { + super("ML-DSA-44"); + } + } + + public final static class KPG3 extends KPG { + public KPG3() { + super("ML-DSA-65"); + } + } + + public final static class KPG5 extends KPG { + public KPG5() { + super("ML-DSA-87"); + } + } + + public sealed static class KF extends NamedKeyFactory permits KF2, KF3, KF5 { + public KF() { + super("ML-DSA", "ML-DSA-44", "ML-DSA-65", "ML-DSA-87"); + } + public KF(String pname) { + super("ML-DSA", pname); + } + + @Override + protected byte[] implExpand(String pname, byte[] input) + throws InvalidKeyException { + return KeyChoices.choiceToExpanded(pname, SEED_LEN, input, + ML_DSA_Impls::seedToExpanded); + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + var nk = toNamedKey(key); + if (nk instanceof NamedPKCS8Key npk) { + var type = KeyChoices.getPreferred("mldsa"); + if (KeyChoices.typeOfChoice(npk.getRawBytes()) != type) { + var encoding = KeyChoices.choiceToChoice( + type, + npk.getParams().getName(), + SEED_LEN, npk.getRawBytes(), + ML_DSA_Impls::seedToExpanded); + nk = NamedPKCS8Key.internalCreate( + npk.getAlgorithm(), + npk.getParams().getName(), + encoding, + npk.getExpanded().clone()); + if (npk != key) { // npk is neither input or output + npk.destroy(); + } + } + } + return nk; + } + } + + public final static class KF2 extends KF { + public KF2() { + super("ML-DSA-44"); + } + } + + public final static class KF3 extends KF { + public KF3() { + super("ML-DSA-65"); + } + } + + public final static class KF5 extends KF { + public KF5() { + super("ML-DSA-87"); + } + } + + public sealed static class SIG extends NamedSignature permits SIG2, SIG3, SIG5 { + public SIG() { + super("ML-DSA", new KF()); + } + public SIG(String pname) { + super("ML-DSA", new KF(pname)); + } + + @Override + protected byte[] implSign(String pname, byte[] skBytes, + Object sk2, byte[] msg, SecureRandom sr) { + var size = name2int(pname); + var r = sr != null ? sr : JCAUtil.getDefSecureRandom(); + byte[] rnd = new byte[32]; + r.nextBytes(rnd); + var mlDsa = new ML_DSA(size); + if (version == Version.FINAL) { + // FIPS 204 Algorithm 2 ML-DSA.Sign prepend {0, len(ctx)} + // to message before passing it to Sign_internal. + var m = new byte[msg.length + 2]; + System.arraycopy(msg, 0, m, 2, msg.length); // len(ctx) = 0 + msg = m; + } + ML_DSA.ML_DSA_Signature sig = mlDsa.signInternal(msg, rnd, skBytes); + return mlDsa.sigEncode(sig); + } + + @Override + protected boolean implVerify(String pname, byte[] pkBytes, + Object pk2, byte[] msg, byte[] sigBytes) + throws SignatureException { + var size = name2int(pname); + var mlDsa = new ML_DSA(size); + if (version == Version.FINAL) { + // FIPS 204 Algorithm 3 ML-DSA.Verify prepend {0, len(ctx)} + // to message before passing it to Verify_internal. + var m = new byte[msg.length + 2]; + System.arraycopy(msg, 0, m, 2, msg.length); // len(ctx) = 0 + msg = m; + } + return mlDsa.verifyInternal(pkBytes, msg, sigBytes); + } + + @Override + protected Object implCheckPublicKey(String pname, byte[] pk) + throws InvalidKeyException { + + ML_DSA mlDsa = new ML_DSA(name2int(pname)); + return mlDsa.checkPublicKey(pk); + } + + @Override + protected Object implCheckPrivateKey(String pname, byte[] sk) + throws InvalidKeyException { + + ML_DSA mlDsa = new ML_DSA(name2int(pname)); + return mlDsa.checkPrivateKey(sk); + } + } + + public final static class SIG2 extends SIG { + public SIG2() { + super("ML-DSA-44"); + } + } + + public final static class SIG3 extends SIG { + public SIG3() { + super("ML-DSA-65"); + } + } + + public final static class SIG5 extends SIG { + public SIG5() { + super("ML-DSA-87"); + } + } +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/NamedKEM.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/NamedKEM.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/NamedKEM.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/NamedKEM.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,218 @@ +/* + * 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. 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.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; + +/// A base class for all `KEM` implementations that can be +/// configured with a named parameter set. See [NamedKeyPairGenerator] +/// for more details. +public abstract class NamedKEM implements KEMSpi { + + private final String fname; // family name + private final NamedKeyFactory fac; + + /// Creates a new `NamedKEM` object. + /// + /// @param fname the family name + /// @param fac the `KeyFactory` used to translate foreign keys and + /// perform key validation + protected NamedKEM(String fname, NamedKeyFactory fac) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + this.fname = fname; + this.fac = fac; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, + AlgorithmParameterSpec spec, SecureRandom secureRandom) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (spec != null) { + throw new InvalidAlgorithmParameterException( + "The " + fname + " algorithm does not take any parameters"); + } + // translate also check the key + var nk = (NamedX509Key) fac.toNamedKey(publicKey); + var pk = nk.getRawBytes(); + return getKeyConsumerImpl(this, nk.getParams(), pk, + implCheckPublicKey(nk.getParams().getName(), pk), secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator( + PrivateKey privateKey, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (spec != null) { + throw new InvalidAlgorithmParameterException( + "The " + fname + " algorithm does not take any parameters"); + } + // translate also check the key + var nk = (NamedPKCS8Key) fac.toNamedKey(privateKey); + var sk = nk.getExpanded(); + return getKeyConsumerImpl(this, nk.getParams(), sk, + implCheckPrivateKey(nk.getParams().getName(), sk), null); + } + + // We don't have a flag on whether key is public key or private key. + // The correct method should always be called. + private record KeyConsumerImpl(NamedKEM kem, String pname, int sslen, + int clen, byte[] key, Object k2, SecureRandom sr) + implements KEMSpi.EncapsulatorSpi, KEMSpi.DecapsulatorSpi { + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, + String algorithm) throws DecapsulateException { + if (encapsulation.length != clen) { + throw new DecapsulateException("Invalid key encapsulation message length"); + } + var ss = kem.implDecapsulate(pname, key, k2, encapsulation); + try { + return new SecretKeySpec(ss, + from, to - from, algorithm); + } finally { + Arrays.fill(ss, (byte)0); + } + } + + @Override + public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) { + var enc = kem.implEncapsulate(pname, key, k2, sr); + try { + return new KEM.Encapsulated( + new SecretKeySpec(enc[1], + from, to - from, algorithm), + enc[0], + null); + } finally { + Arrays.fill(enc[1], (byte)0); + } + } + + @Override + public int engineSecretSize() { + return sslen; + } + + @Override + public int engineEncapsulationSize() { + return clen; + } + } + + private static KeyConsumerImpl getKeyConsumerImpl(NamedKEM kem, + NamedParameterSpec nps, byte[] key, Object k2, SecureRandom sr) { + String pname = nps.getName(); + return new KeyConsumerImpl(kem, pname, kem.implSecretSize(pname), kem.implEncapsulationSize(pname), + key, k2, sr); + } + + /// User-defined encap function. + /// + /// @param pname parameter name + /// @param pk public key in raw bytes + /// @param pk2 parsed public key, `null` if none. See [#implCheckPublicKey]. + /// @param sr SecureRandom object, `null` if not initialized + /// @return the key encapsulation message and the shared key (in this order) + /// @throws ProviderException if there is an internal error + protected abstract byte[][] implEncapsulate(String pname, byte[] pk, Object pk2, SecureRandom sr); + + /// User-defined decap function. + /// + /// @param pname parameter name + /// @param sk private key in raw bytes + /// @param sk2 parsed private key, `null` if none. See [#implCheckPrivateKey]. + /// @param encap the key encapsulation message + /// @return the shared key + /// @throws ProviderException if there is an internal error + /// @throws DecapsulateException if there is another error + protected abstract byte[] implDecapsulate(String pname, byte[] sk, Object sk2, byte[] encap) + throws DecapsulateException; + + /// User-defined function returning shared secret key length. + /// + /// @param pname parameter name + /// @return shared secret key length + /// @throws ProviderException if there is an internal error + protected abstract int implSecretSize(String pname); + + /// User-defined function returning key encapsulation message length. + /// + /// @param pname parameter name + /// @return key encapsulation message length + /// @throws ProviderException if there is an internal error + protected abstract int implEncapsulationSize(String pname); + + /// User-defined function to validate a public key. + /// + /// This method will be called in `newEncapsulator`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implEncapsulate] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param pname parameter name + /// @param pk public key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPublicKey(String pname, byte[] pk) throws InvalidKeyException { + return null; + } + + /// User-defined function to validate a private key. + /// + /// This method will be called in `newDecapsulator`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implDecapsulate] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param pname parameter name + /// @param sk private key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPrivateKey(String pname, byte[] sk) throws InvalidKeyException { + return null; + } +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,319 @@ +/* + * 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. 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.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.util.KeyUtil; +import sun.security.util.RawKeySpec; +import sun.security.x509.NamedX509Key; + +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.NamedParameterSpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; + +/// A base class for all `KeyFactory` implementations that can be +/// configured with a named parameter set. See [NamedKeyPairGenerator] +/// for more details. +/// +/// This factory supports reading and writing to RAW formats: +/// +/// 1. It reads from a RAW key using `translateKey` if `key.getFormat` is "RAW". +/// 2. It writes to a RAW [EncodedKeySpec] if `getKeySpec(key, EncodedKeySpec.class)` +/// is called. The format of the output is "RAW" and the algorithm is +/// intentionally left unspecified. +/// 3. It reads from and writes to the internal type [RawKeySpec]. +/// +/// When reading from a RAW format, it needs enough info to derive the +/// parameter set name. +public abstract class NamedKeyFactory extends KeyFactorySpi { + + private final String fname; // family name + private final String[] pnames; // allowed parameter set name (at least one) + + /// Creates a new `NamedKeyFactory` object. + /// + /// @param fname the family name + /// @param pnames the standard parameter set names, at least one is needed. + protected NamedKeyFactory(String fname, String... pnames) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + if (pnames == null || pnames.length == 0) { + throw new AssertionError("pnames cannot be null or empty"); + } + this.fname = fname; + this.pnames = pnames; + } + + private String checkName(String pname) throws InvalidKeyException { + for (var n : pnames) { + if (n.equalsIgnoreCase(pname)) { + // return the stored standard name + return n; + } + } + throw new InvalidKeyException("Unsupported parameter set name: " + pname); + } + + @Override + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + return switch (keySpec) { + case X509EncodedKeySpec xspec -> { + try { + yield fromX509(xspec.getEncoded()); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } + } + case RawKeySpec rks -> { + if (pnames.length == 1) { + yield new NamedX509Key(fname, pnames[0], rks.getKeyArr()); + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } + case EncodedKeySpec espec when espec.getFormat().equalsIgnoreCase("RAW") -> { + if (pnames.length == 1) { + yield new NamedX509Key(fname, pnames[0], espec.getEncoded()); + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; + } + + @Override + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException { + return switch (keySpec) { + case PKCS8EncodedKeySpec pspec -> { + var bytes = pspec.getEncoded(); + try { + yield fromPKCS8(bytes); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } finally { + Arrays.fill(bytes, (byte) 0); + } + } + case RawKeySpec rks -> { + if (pnames.length == 1) { + var raw = rks.getKeyArr(); + try { + yield fromRaw(pnames[0], raw); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException("Invalid key input", e); + } + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } + case EncodedKeySpec espec when espec.getFormat().equalsIgnoreCase("RAW") -> { + if (pnames.length == 1) { + var raw = espec.getEncoded(); + try { + yield fromRaw(pnames[0], raw); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException("Invalid key input", e); + } + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; + } + + private PrivateKey fromRaw(String pname, byte[] raw) + throws InvalidKeyException { + return NamedPKCS8Key.internalCreate( + fname, pname, raw, implExpand(pname, raw)); + } + + private PrivateKey fromPKCS8(byte[] bytes) + throws InvalidKeyException { + var k = new NamedPKCS8Key(fname, bytes, this::implExpand); + checkName(k.getParams().getName()); + return k; + } + + private PublicKey fromX509(byte[] bytes) + throws InvalidKeyException { + var k = new NamedX509Key(fname, bytes); + checkName(k.getParams().getName()); + return k; + } + + private static class RawEncodedKeySpec extends EncodedKeySpec { + public RawEncodedKeySpec(byte[] encodedKey) { + super(encodedKey); + } + + @Override + public String getFormat() { + return "RAW"; + } + } + + @Override + protected T engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException { + try { + key = toNamedKey(key); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } + // key is now either NamedPKCS8Key or NamedX509Key of permitted param set + if (key instanceof NamedPKCS8Key nk) { + byte[] bytes = null; + try { + if (keySpec == PKCS8EncodedKeySpec.class) { + return keySpec.cast( + new PKCS8EncodedKeySpec(bytes = key.getEncoded())); + } else if (keySpec == RawKeySpec.class) { + return keySpec.cast(new RawKeySpec(nk.getRawBytes())); + } else if (keySpec.isAssignableFrom(EncodedKeySpec.class)) { + return keySpec.cast( + new RawEncodedKeySpec(nk.getRawBytes())); + } else { + throw new InvalidKeySpecException("Unsupported type: " + keySpec); + } + } finally { + if (bytes != null) { + Arrays.fill(bytes, (byte)0); + } + } + } else if (key instanceof NamedX509Key nk) { + if (keySpec == X509EncodedKeySpec.class + && key.getFormat().equalsIgnoreCase("X.509")) { + return keySpec.cast(new X509EncodedKeySpec(key.getEncoded())); + } else if (keySpec == RawKeySpec.class) { + return keySpec.cast(new RawKeySpec(nk.getRawBytes())); + } else if (keySpec.isAssignableFrom(EncodedKeySpec.class)) { + return keySpec.cast(new RawEncodedKeySpec(nk.getRawBytes())); + } else { + throw new InvalidKeySpecException("Unsupported type: " + keySpec); + } + } + throw new AssertionError("No " + keySpec.getName() + " for " + key.getClass()); + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + // The base toNamedKey only makes sure key is translated into a NamedKey. + // the key material is still the same as the input. + return toNamedKey(key); + } + + protected Key toNamedKey(Key key) throws InvalidKeyException { + if (key == null) { + throw new InvalidKeyException("Key must not be null"); + } + if (key instanceof NamedX509Key nk) { + checkName(nk.getParams().getName()); + return key; + } + if (key instanceof NamedPKCS8Key nk) { + checkName(nk.getParams().getName()); + return key; + } + var format = key.getFormat(); + if (format == null) { + throw new InvalidKeyException("Unextractable key"); + } else if (format.equalsIgnoreCase("RAW")) { + var kAlg = key.getAlgorithm(); + if (key instanceof PrivateKey || key instanceof PublicKey) { + String pname; + // Three cases that we can find the parameter set name from a RAW key: + // 1. getParams() returns one + // 2. getAlgorithm() returns param set name (some provider does this) + // 3. getAlgorithm() returns family name but this KF is for param set name + if (KeyUtil.getParams(key) instanceof NamedParameterSpec nps) { + pname = checkName(nps.getName()); + } else { + if (kAlg.equalsIgnoreCase(fname)) { + if (pnames.length == 1) { + pname = pnames[0]; + } else { + throw new InvalidKeyException("No parameter set info"); + } + } else { + pname = checkName(kAlg); + } + } + var raw = key.getEncoded(); + return key instanceof PrivateKey + ? fromRaw(pname, raw) + : new NamedX509Key(fname, pname, raw); + } else { + throw new InvalidKeyException("Unsupported key type: " + key.getClass()); + } + } else if (format.equalsIgnoreCase("PKCS#8") && key instanceof PrivateKey) { + var bytes = key.getEncoded(); + try { + return fromPKCS8(bytes); + } finally { + Arrays.fill(bytes, (byte) 0); + } + } else if (format.equalsIgnoreCase("X.509") && key instanceof PublicKey) { + return fromX509(key.getEncoded()); + } else { + throw new InvalidKeyException("Unsupported key format: " + key.getFormat()); + } + } + + /// User-defined function to generate the expanded format of + /// a [NamedPKCS8Key] from its encoding format. + /// + /// This method is called when the key factory is constructing a private + /// key. The ownership of the result is fully granted to the caller. + /// + /// @param pname the parameter set name + /// @param input the encoding, could be any format + /// @return the expanded key, not null + /// @throws InvalidKeyException if `input` is invalid + protected abstract byte[] implExpand(String pname, byte[] input) + throws InvalidKeyException; +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,214 @@ +/* + * 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. 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.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.KeyPair; +import java.security.KeyPairGeneratorSpi; +import java.security.ProviderException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; + +/// A base class for all `KeyPairGenerator` implementations that can be +/// configured with a named parameter set. +/// +/// Together with [NamedKeyFactory], [NamedKEM], and [NamedSignature], these +/// classes form a compact framework designed to support any public key +/// algorithm standardized with named parameter sets. In this scenario, +/// the algorithm name is the "family name" and each standardized parameter +/// set has a "parameter set name". Implementations of these classes are able +/// to instantiate a `KeyPairGenerator`, `KeyFactory`, or `KEM` or `Signature` +/// object using either the family name or a parameter set name. All keys used +/// in this context will be of the type [NamedPKCS8Key] or [NamedX509Key], +/// with `getAlgorithm` returning the family name, and `getParams` returning +/// the parameter set name as a [NamedParameterSpec] object. +/// +/// A `NamedKeyPairGenerator` or `NamedKeyFactory` implementation must include +/// a zero-argument public constructor that calls `super(fname, pnames)`, where +/// `fname` is the family name of the algorithm and `pnames` are its supported +/// parameter set names. `pnames` must contain at least one element. For an +/// implementation of `NamedKeyPairGenerator`, the first element becomes its +/// default parameter set, i.e. the parameter set used by generated keys unless +/// [#initialize(AlgorithmParameterSpec, java.security.SecureRandom)] +/// is called on a different parameter set. +/// +/// A `NamedKEM` or `NamedSignature` implementation must include a zero-argument +/// public constructor that calls `super(fname, factory)`, where `fname` is the +/// family name of the algorithm and `factory` is the `NamedKeyFactory` object +/// that is used to translate foreign keys. `factory` only recognizes +/// parameter sets supported by this implementation. +/// +/// An implementation must implement all abstract methods. For all these +/// methods, the implementation must relinquish any "ownership" of any input +/// and output array argument. Precisely, the implementation must not retain +/// any reference to a returning array so that it won't be able to modify its +/// content later. Similarly, the implementation must not modify any input +/// array argument and must not retain any reference to an input array argument +/// after the call. +/// +/// Also, an implementation must not keep any extra copy of a private key in +/// any format. For key generation, the only copy is the one returned in the +/// [#implGenerateKeyPair] call. For all other methods, it must not make +/// a copy of the input private key. A `KEM` implementation also must not +/// keep a copy of the shared secret key, no matter if it's an encapsulator +/// or a decapsulator. Only the code that owns these sensitive data can +/// choose to perform cleanup when it determines they are no longer needed. +/// +/// The `NamedSignature` and `NamedKEM` classes provide `implCheckPublicKey` +/// and `implCheckPrivateKey` methods that allow an implementation to validate +/// a key before using it. An implementation may return a parsed key in +/// a local type, and this parsed key will be passed to an operational method +/// (For example, `implSign`) later. An implementation must not retain +/// a reference of the parsed key. +/// +/// The private key, represented as a byte array when used in `NamedKEM` or +/// `NamedSignature`, is referred to as its expanded format. For some +/// algorithms, this format may differ from the +/// [key material][NamedPKCS8Key#getRawBytes()] inside a PKCS #8 file. For example, +/// [FIPS 204](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf) +/// Table 2 defines the ML-DSA-65 private key as a 4032-byte array, which is +/// used in the ML-DSA.Sign function in Algorithm 2, representing the +/// expanded format. However, in +/// [RFC 9881](https://datatracker.ietf.org/doc/html/rfc9881#name-private-key-format), +/// a private key can be encoded into a CHOICE of three formats, none in the +/// same as the FIPS 204 format. The choices are defined in +/// [sun.security.util.KeyChoices]. A `NamedKeyPairGenerator` implementation +/// should return both the expanded key and a preferred encoding in its +/// [#implGenerateKeyPair] method. +/// +/// A `NamedKeyFactory` must override the `implExpand` method to derive +/// the expanded format from an encoding format, or return `null` if there +/// is no difference. +/// +/// Implementations may support multiple encoding formats. +/// +/// A `NamedKeyFactory` must not modify the encoding when generating a key +/// from a `KeySpec` object, ensuring that when re-encoded, the key retains +/// its original encoding format. +/// +/// A `NamedKeyFactory` can choose a different encoding format when +/// `translateKey` is called. +/// +/// When constructing a [NamedX509Key] or [NamedPKCS8Key] object from raw key +/// bytes, the key bytes are directly referenced within the object, so the +/// caller must not modify them afterward. Similarly, the key's `getRawBytes` +/// method returns direct references to the underlying raw key bytes, meaning +/// the caller must not alter the contents of the returned value. +/// +/// Together, these measures ensure the classes are as efficient as possible, +/// preventing unnecessary array cloning and potential data leaks. While these +/// classes should not be considered immutable, strictly adhering to the rules +/// above will ensure data integrity is maintained. +/// +/// Note: A limitation of `NamedKeyPairGenerator` and `NamedKeyFactory` is +/// that the keys generated by their implementations will always be of type +/// `NamedX509Key` or `NamedPKCS8Key`. Existing implementations of algorithms +/// like EdDSA and XDH have been generating keys implementing `EdECKey` or +/// `XECKey` interfaces, and they are not rewritten with this framework. +/// `NamedParameterSpec` fields not implemented with this framework include +/// Ed25519, Ed448, X25519, and X448. +public abstract class NamedKeyPairGenerator extends KeyPairGeneratorSpi { + + private final String fname; // family name + private final String[] pnames; // allowed parameter set names (at least one) + + protected String pname; // parameter set name, if can be determined + private SecureRandom secureRandom; + + /// Creates a new `NamedKeyPairGenerator` object. + /// + /// @param fname the family name + /// @param pnames supported parameter set names, at least one is needed. + /// If multiple, the first one becomes the default parameter set name. + protected NamedKeyPairGenerator(String fname, String... pnames) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + if (pnames == null || pnames.length == 0) { + throw new AssertionError("pnames cannot be null or empty"); + } + this.fname = fname; + this.pnames = pnames; + } + + private String checkName(String pname) throws InvalidAlgorithmParameterException { + for (var n : pnames) { + if (n.equalsIgnoreCase(pname)) { + // return the stored standard pname + return n; + } + } + throw new InvalidAlgorithmParameterException( + "Unsupported parameter set name: " + pname); + } + + @Override + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException { + if (params instanceof NamedParameterSpec spec) { + pname = checkName(spec.getName()); + } else { + throw new InvalidAlgorithmParameterException( + "Unsupported AlgorithmParameterSpec: " + params); + } + this.secureRandom = random; + } + + @Override + public void initialize(int keysize, SecureRandom random) { + if (keysize != -1) { + // User can call initialize(-1, sr) to provide a SecureRandom + // without touching the parameter set currently used + throw new InvalidParameterException("keysize not supported"); + } + this.secureRandom = random; + } + + @Override + public KeyPair generateKeyPair() { + String tmpName = pname != null ? pname : pnames[0]; + var keys = implGenerateKeyPair(tmpName, secureRandom); + return new KeyPair(new NamedX509Key(fname, tmpName, keys[0]), + NamedPKCS8Key.internalCreate(fname, tmpName, keys[1], + keys.length == 2 ? null : keys[2])); + } + + /// User-defined key pair generator. + /// + /// @param pname parameter set name + /// @param sr `SecureRandom` object, `null` if not initialized + /// @return the public key, the private key in its encoding format, and + /// the private key in its expanded format (in this order) in + /// raw bytes. If the expanded format of the private key is the + /// same as its encoding format, the 3rd element must be omitted. + /// @throws ProviderException if there is an internal error + protected abstract byte[][] implGenerateKeyPair(String pname, SecureRandom sr); +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/NamedSignature.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/NamedSignature.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/NamedSignature.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/NamedSignature.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,217 @@ +/* + * 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. 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.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import java.io.ByteArrayOutputStream; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.SignatureSpi; +import java.security.spec.AlgorithmParameterSpec; + +/// A base class for all `Signature` implementations that can be +/// configured with a named parameter set. See [NamedKeyPairGenerator] +/// for more details. +/// +/// This class does not work with preHash signatures. +public abstract class NamedSignature extends SignatureSpi { + + private final String fname; // family name + private final NamedKeyFactory fac; + + private final ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + // init with... + private String pname; + private byte[] secKey; + private byte[] pubKey; + + private Object sk2; + private Object pk2; + + /// Creates a new `NamedSignature` object. + /// + /// @param fname the family name + /// @param fac the `KeyFactory` used to translate foreign keys and + /// perform key validation + protected NamedSignature(String fname, NamedKeyFactory fac) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + this.fname = fname; + this.fac = fac; + } + + @Override + protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { + // translate also check the key + var nk = (NamedX509Key) fac.toNamedKey(publicKey); + pname = nk.getParams().getName(); + pubKey = nk.getRawBytes(); + pk2 = implCheckPublicKey(pname, pubKey); + secKey = null; + bout.reset(); + } + + @Override + protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { + // translate also check the key + var nk = (NamedPKCS8Key) fac.toNamedKey(privateKey); + pname = nk.getParams().getName(); + secKey = nk.getExpanded(); + sk2 = implCheckPrivateKey(pname, secKey); + pubKey = null; + bout.reset(); + } + + @Override + protected void engineUpdate(byte b) throws SignatureException { + bout.write(b); + } + + @Override + protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { + bout.write(b, off, len); + } + + @Override + protected byte[] engineSign() throws SignatureException { + if (secKey != null) { + var msg = bout.toByteArray(); + bout.reset(); + return implSign(pname, secKey, sk2, msg, appRandom); + } else { + throw new SignatureException("No private key"); + } + } + + @Override + protected boolean engineVerify(byte[] sig) throws SignatureException { + if (pubKey != null) { + var msg = bout.toByteArray(); + bout.reset(); + return implVerify(pname, pubKey, pk2, msg, sig); + } else { + throw new SignatureException("No public key"); + } + } + + @Override + @Deprecated + protected void engineSetParameter(String param, Object value) + throws InvalidParameterException { + throw new InvalidParameterException("setParameter() not supported"); + } + + @Override + @Deprecated + protected Object engineGetParameter(String param) throws InvalidParameterException { + throw new InvalidParameterException("getParameter() not supported"); + } + + @Override + protected void engineSetParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidAlgorithmParameterException( + "The " + fname + " algorithm does not take any parameters"); + } + } + + @Override + protected AlgorithmParameters engineGetParameters() { + return null; + } + + /// User-defined sign function. + /// + /// @param pname parameter name + /// @param sk private key in raw bytes + /// @param sk2 parsed private key, `null` if none. See [#implCheckPrivateKey]. + /// @param msg the message + /// @param sr SecureRandom object, `null` if not initialized + /// @return the signature + /// @throws ProviderException if there is an internal error + /// @throws SignatureException if there is another error + protected abstract byte[] implSign(String pname, byte[] sk, Object sk2, + byte[] msg, SecureRandom sr) throws SignatureException; + + /// User-defined verify function. + /// + /// @param pname parameter name + /// @param pk public key in raw bytes + /// @param pk2 parsed public key, `null` if none. See [#implCheckPublicKey]. + /// @param msg the message + /// @param sig the signature + /// @return true if verified + /// @throws ProviderException if there is an internal error + /// @throws SignatureException if there is another error + protected abstract boolean implVerify(String pname, byte[] pk, Object pk2, + byte[] msg, byte[] sig) throws SignatureException; + + /// User-defined function to validate a public key. + /// + /// This method will be called in `initVerify`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implVerify] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param pname parameter name + /// @param pk public key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPublicKey(String pname, byte[] pk) throws InvalidKeyException { + return null; + } + + /// User-defined function to validate a private key. + /// + /// This method will be called in `initSign`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implSign] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param pname parameter name + /// @param sk private key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPrivateKey(String pname, byte[] sk) throws InvalidKeyException { + return null; + } +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/SHA3.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/SHA3.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/SHA3.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/SHA3.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, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,17 @@ package sun.security.provider; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; import java.security.ProviderException; import java.util.Arrays; import java.util.Objects; +import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.IntrinsicCandidate; -import static sun.security.provider.ByteArrayAccess.b2lLittle; -import static sun.security.provider.ByteArrayAccess.l2bLittle; + +import static java.lang.Math.min; /** * This class implements the Secure Hash Algorithm SHA-3 developed by @@ -45,10 +49,10 @@ * @since 9 * @author Valerie Peng */ -abstract class SHA3 extends DigestBase { +public abstract class SHA3 extends DigestBase { private static final int WIDTH = 200; // in bytes, e.g. 1600 bits - private static final int DM = 5; // dimension of lanes + private static final int DM = 5; // dimension of state matrix private static final int NR = 24; // number of rounds @@ -64,20 +68,39 @@ 0x8000000000008080L, 0x80000001L, 0x8000000080008008L, }; + // The starting byte combining the 2 or 4-bit domain separator and + // leading bits of the 10*1 padding, see Table 6 in B.2 of FIPS PUB 202 + // for examples private final byte suffix; - private byte[] state = new byte[WIDTH]; - private long[] lanes = new long[DM*DM]; + + // the state matrix flattened into an array + private long[] state = new long[DM*DM]; + + // The byte offset in the state where the next squeeze() will start. + // -1 indicates that either we are in the absorbing phase (only + // update() calls were made so far) in an extendable-output function (XOF) + // or the class was initialized as a hash. + // The first squeeze() call (after a possibly empty sequence of update() + // calls) will set it to 0 at its start. + // When a squeeze() call uses up all available bytes from this state + // and so a new keccak() call is made, squeezeOffset is reset to 0. + protected int squeezeOffset = -1; + + static final VarHandle asLittleEndian + = MethodHandles.byteArrayViewVarHandle(long[].class, + ByteOrder.LITTLE_ENDIAN).withInvokeExactBehavior(); /** * Creates a new SHA-3 object. */ - SHA3(String name, int digestLength, byte suffix, int c) { + private SHA3(String name, int digestLength, byte suffix, int c) { super(name, digestLength, (WIDTH - c)); this.suffix = suffix; } private void implCompressCheck(byte[] b, int ofs) { Objects.requireNonNull(b); + Preconditions.checkIndex(ofs + blockSize - 1, b.length, Preconditions.AIOOBE_FORMATTER); } /** @@ -91,10 +114,21 @@ @IntrinsicCandidate private void implCompress0(byte[] b, int ofs) { - for (int i = 0; i < buffer.length; i++) { - state[i] ^= b[ofs++]; - } - keccak(); + for (int i = 0; i < blockSize / 8; i++) { + state[i] ^= (long) asLittleEndian.get(b, ofs); + ofs += 8; + } + + keccak(); + } + + void finishAbsorb() { + int numOfPadding = + setPaddingBytes(suffix, buffer, (int)(bytesProcessed % blockSize)); + if (numOfPadding < 1) { + throw new ProviderException("Incorrect pad size: " + numOfPadding); + } + implCompress(buffer, 0); } /** @@ -102,35 +136,127 @@ * DigestBase calls implReset() when necessary. */ void implDigest(byte[] out, int ofs) { - int numOfPadding = - setPaddingBytes(suffix, buffer, (int)(bytesProcessed % buffer.length)); - if (numOfPadding < 1) { - throw new ProviderException("Incorrect pad size: " + numOfPadding); + // Moving this allocation to the block where it is used causes a little + // performance drop, that is why it is here. + byte[] byteState = new byte[8]; + if (engineGetDigestLength() == 0) { + // This is an XOF, so the digest() call is illegal. + throw new ProviderException("Calling digest() is not allowed in an XOF"); } - implCompress(buffer, 0); - int availableBytes = buffer.length; + + finishAbsorb(); + + int availableBytes = blockSize; int numBytes = engineGetDigestLength(); + while (numBytes > availableBytes) { - System.arraycopy(state, 0, out, ofs, availableBytes); + for (int i = 0; i < availableBytes / 8; i++) { + asLittleEndian.set(out, ofs, state[i]); + ofs += 8; + } numBytes -= availableBytes; - ofs += availableBytes; keccak(); } - System.arraycopy(state, 0, out, ofs, numBytes); + int numLongs = numBytes / 8; + + for (int i = 0; i < numLongs; i++) { + asLittleEndian.set(out, ofs, state[i]); + ofs += 8; + } + if (numBytes % 8 != 0) { + asLittleEndian.set(byteState, 0, state[numLongs]); + System.arraycopy(byteState, 0, out, ofs, numBytes % 8); + } + } + + void implSqueeze(byte[] output, int offset, int numBytes) { + // Moving this allocation to the block where it is used causes a little + // performance drop, that is why it is here. + byte[] byteState = new byte[8]; + if (engineGetDigestLength() != 0) { + // This is not an XOF, so the squeeze() call is illegal. + throw new ProviderException("Squeezing is only allowed in XOF mode."); + } + + if (squeezeOffset == -1) { + finishAbsorb(); + squeezeOffset = 0; + } + + int availableBytes = blockSize - squeezeOffset; + + while (numBytes > availableBytes) { + int longOffset = squeezeOffset / 8; + int bytesToCopy = 0; + + if (longOffset * 8 < squeezeOffset) { + asLittleEndian.set(byteState, 0, state[longOffset]); + longOffset++; + bytesToCopy = longOffset * 8 - squeezeOffset; + System.arraycopy(byteState, 8 - bytesToCopy, + output, offset, bytesToCopy); + offset += bytesToCopy; + } + for (int i = longOffset; i < blockSize / 8; i++) { + asLittleEndian.set(output, offset, state[i]); + offset += 8; + } + keccak(); + squeezeOffset = 0; + numBytes -= availableBytes; + availableBytes = blockSize; + } + // now numBytes <= availableBytes + int longOffset = squeezeOffset / 8; + + if (longOffset * 8 < squeezeOffset) { + asLittleEndian.set(byteState, 0, state[longOffset]); + int bytesToCopy = min((longOffset + 1) * 8 - squeezeOffset, numBytes); + System.arraycopy(byteState, squeezeOffset - 8 * longOffset, + output, offset, bytesToCopy); + longOffset++; + numBytes -= bytesToCopy; + offset += bytesToCopy; + squeezeOffset += bytesToCopy; + + if (numBytes == 0) return; + } + + int numLongs = numBytes / 8; + + for (int i = longOffset; i < longOffset + numLongs; i++) { + asLittleEndian.set(output, offset, state[i]); + offset += 8; + numBytes -= 8; + squeezeOffset += 8; + } + + if (numBytes > 0) { + asLittleEndian.set(byteState, 0, state[squeezeOffset / 8]); + System.arraycopy(byteState, 0, output, offset, numBytes); + squeezeOffset += numBytes; + } + } + + byte[] implSqueeze(int numBytes) { + byte[] result = new byte[numBytes]; + implSqueeze(result, 0, numBytes); + return result; } /** * Resets the internal state to start a new hash. */ void implReset() { - Arrays.fill(state, (byte)0); - Arrays.fill(lanes, 0L); + Arrays.fill(state, 0L); + squeezeOffset = -1; } /** * Utility function for padding the specified data based on the - * pad10*1 algorithm (section 5.1) and the 2-bit suffix "01" required - * for SHA-3 hash (section 6.1). + * pad10*1 algorithm (section 5.1) and the 2-bit suffix "01" or 4-bit + * suffix "1111" required for SHA-3 hash functions (section 6.1) and + * extendable-output functions (section 6.1) respectively. */ private static int setPaddingBytes(byte suffix, byte[] in, int len) { if (len != in.length) { @@ -145,47 +271,24 @@ } /** - * Utility function for transforming the specified byte array 's' - * into array of lanes 'm' as defined in section 3.1.2. - */ - private static void bytes2Lanes(byte[] s, long[] m) { - int sOfs = 0; - // Conversion traverses along x-axis before y-axis - for (int y = 0; y < DM; y++, sOfs += 40) { - b2lLittle(s, sOfs, m, DM*y, 40); - } - } - - /** - * Utility function for transforming the specified array of - * lanes 'm' into a byte array 's' as defined in section 3.1.3. - */ - private static void lanes2Bytes(long[] m, byte[] s) { - int sOfs = 0; - // Conversion traverses along x-axis before y-axis - for (int y = 0; y < DM; y++, sOfs += 40) { - l2bLittle(m, DM*y, s, sOfs, 40); - } - } - - /** * The function Keccak as defined in section 5.2 with * rate r = 1600 and capacity c. */ private void keccak() { - // convert the 200-byte state into 25 lanes - bytes2Lanes(state, lanes); + keccak(state); + } + public static void keccak(long[] stateArr) { long a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12; long a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24; // move data into local variables - a0 = lanes[0]; a1 = lanes[1]; a2 = lanes[2]; a3 = lanes[3]; a4 = lanes[4]; - a5 = lanes[5]; a6 = lanes[6]; a7 = lanes[7]; a8 = lanes[8]; a9 = lanes[9]; - a10 = lanes[10]; a11 = lanes[11]; a12 = lanes[12]; a13 = lanes[13]; a14 = lanes[14]; - a15 = lanes[15]; a16 = lanes[16]; a17 = lanes[17]; a18 = lanes[18]; a19 = lanes[19]; - a20 = lanes[20]; a21 = lanes[21]; a22 = lanes[22]; a23 = lanes[23]; a24 = lanes[24]; + a0 = stateArr[0]; a1 = stateArr[1]; a2 = stateArr[2]; a3 = stateArr[3]; a4 = stateArr[4]; + a5 = stateArr[5]; a6 = stateArr[6]; a7 = stateArr[7]; a8 = stateArr[8]; a9 = stateArr[9]; + a10 = stateArr[10]; a11 = stateArr[11]; a12 = stateArr[12]; a13 = stateArr[13]; a14 = stateArr[14]; + a15 = stateArr[15]; a16 = stateArr[16]; a17 = stateArr[17]; a18 = stateArr[18]; a19 = stateArr[19]; + a20 = stateArr[20]; a21 = stateArr[21]; a22 = stateArr[22]; a23 = stateArr[23]; a24 = stateArr[24]; - // process the lanes through step mappings + // process the stateArr through step mappings for (int ir = 0; ir < NR; ir++) { // Step mapping Theta as defined in section 3.2.1. long c0 = a0^a5^a10^a15^a20; @@ -287,20 +390,16 @@ a0 ^= RC_CONSTANTS[ir]; } - lanes[0] = a0; lanes[1] = a1; lanes[2] = a2; lanes[3] = a3; lanes[4] = a4; - lanes[5] = a5; lanes[6] = a6; lanes[7] = a7; lanes[8] = a8; lanes[9] = a9; - lanes[10] = a10; lanes[11] = a11; lanes[12] = a12; lanes[13] = a13; lanes[14] = a14; - lanes[15] = a15; lanes[16] = a16; lanes[17] = a17; lanes[18] = a18; lanes[19] = a19; - lanes[20] = a20; lanes[21] = a21; lanes[22] = a22; lanes[23] = a23; lanes[24] = a24; - - // convert the resulting 25 lanes back into 200-byte state - lanes2Bytes(lanes, state); + stateArr[0] = a0; stateArr[1] = a1; stateArr[2] = a2; stateArr[3] = a3; stateArr[4] = a4; + stateArr[5] = a5; stateArr[6] = a6; stateArr[7] = a7; stateArr[8] = a8; stateArr[9] = a9; + stateArr[10] = a10; stateArr[11] = a11; stateArr[12] = a12; stateArr[13] = a13; stateArr[14] = a14; + stateArr[15] = a15; stateArr[16] = a16; stateArr[17] = a17; stateArr[18] = a18; stateArr[19] = a19; + stateArr[20] = a20; stateArr[21] = a21; stateArr[22] = a22; stateArr[23] = a23; stateArr[24] = a24; } public Object clone() throws CloneNotSupportedException { SHA3 copy = (SHA3) super.clone(); copy.state = copy.state.clone(); - copy.lanes = new long[DM*DM]; return copy; } @@ -339,4 +438,104 @@ super("SHA3-512", 64, (byte)0x06, 128); } } + + public abstract static class SHA3XOF extends SHA3 { + public SHA3XOF(String name, int digestLength, byte offset, int c) { + super(name, digestLength, offset, c); + } + public void update(byte in) { + if (squeezeOffset != -1) { + throw new ProviderException("update() after squeeze() is not allowed."); + } + engineUpdate(in); + } + public void update(byte[] in, int off, int len) { + if (squeezeOffset != -1) { + throw new ProviderException("update() after squeeze() is not allowed."); + } + engineUpdate(in, off, len); + } + + public void update(byte[] in) { + if (squeezeOffset != -1) { + throw new ProviderException("update() after squeeze() is not allowed."); + } + engineUpdate(in, 0, in.length); + } + + public byte[] digest() { + return engineDigest(); + } + + public void squeeze(byte[] output, int offset, int numBytes) { + implSqueeze(output, offset, numBytes); + } + public byte[] squeeze(int numBytes) { + return implSqueeze(numBytes); + } + + public void reset() { + engineReset(); + // engineReset (final in DigestBase) skips implReset if there's + // no update. This works for MessageDigest, since digest() always + // resets. But for XOF, squeeze() may be called without update, + // and still modifies state. So we always call implReset here + // to ensure correct behavior. + implReset(); + } + } + + public static final class SHAKE128Hash extends SHA3 { + public SHAKE128Hash() { + super("SHAKE128-256", 32, (byte) 0x1F, 32); + } + } + + public static final class SHAKE256Hash extends SHA3 { + public SHAKE256Hash() { + super("SHAKE256-512", 64, (byte) 0x1F, 64); + } + } + + + /* + * The SHAKE128 extendable output function. + */ + public static final class SHAKE128 extends SHA3XOF { + // d is the required number of output bytes. + // If this constructor is used with d > 0, the squeezing methods + // will throw a ProviderException. + public SHAKE128(int d) { + super("SHAKE128", d, (byte) 0x1F, 32); + } + + // If this constructor is used to get an instance of the class, then, + // after the last update, one can get the generated bytes using the + // squeezing methods. + // Calling digest method will throw a ProviderException. + public SHAKE128() { + super("SHAKE128", 0, (byte) 0x1F, 32); + } + } + + /* + * The SHAKE256 extendable output function. + */ + public static final class SHAKE256 extends SHA3XOF { + // d is the required number of output bytes. + // If this constructor is used with d > 0, the squeezing methods will + // throw a ProviderException. + public SHAKE256(int d) { + super("SHAKE256", d, (byte) 0x1F, 64); + } + + // If this constructor is used to get an instance of the class, then, + // after the last update, one can get the generated bytes using the + // squeezing methods. + // Calling a digest method will throw a ProviderException. + public SHAKE256() { + super("SHAKE256", 0, (byte) 0x1F, 64); + } + } + } diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,108 @@ +/* + * 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.provider; + +import jdk.internal.vm.annotation.IntrinsicCandidate; + +import java.security.InvalidAlgorithmParameterException; +import java.util.Arrays; + +import static sun.security.provider.ByteArrayAccess.b2lLittle; +import static sun.security.provider.ByteArrayAccess.l2bLittle; + +import static sun.security.provider.SHA3.keccak; + +/* + * This class is for making it possible that NRPAR (= 2) (rather restricted) + * SHAKE computations execute in parallel. + * The restrictions are: + * 1. The messages processed should be such that the absorb phase should + * execute a single keccak() call and the byte arrays passed to the constructor + * (or reset() method) of this class should be the message padded with the + * appropriate padding described in + * https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf. + * 2. The only available way for extracting data is the squeeze() method + * that extracts exactly 1 block of data of each computation, delivering it + * in the arrays that were passed to the class in the constructor (or the + * reset() call). + */ +public class SHA3Parallel { + private int blockSize = 0; + private static final int DM = 5; // dimension of lanesArr + private byte[][] buffers; + private long[][] lanesArr; + private static final int NRPAR = 2; + + private SHA3Parallel(byte[][] buffers, int blockSize) throws InvalidAlgorithmParameterException { + if ((buffers.length != NRPAR) || (buffers[0].length < blockSize)) { + throw new InvalidAlgorithmParameterException("Bad buffersize."); + } + this.buffers = buffers; + this.blockSize = blockSize; + lanesArr = new long[NRPAR][]; + for (int i = 0; i < NRPAR; i++) { + lanesArr[i] = new long[DM * DM]; + b2lLittle(buffers[i], 0, lanesArr[i], 0, blockSize); + } + } + + public void reset(byte[][] buffers) throws InvalidAlgorithmParameterException { + if ((buffers.length != NRPAR) || (buffers[0].length < blockSize)) { + throw new InvalidAlgorithmParameterException("Bad buffersize."); + } + this.buffers = buffers; + for (int i = 0; i < NRPAR; i++) { + Arrays.fill(lanesArr[i], 0L); + b2lLittle(buffers[i], 0, lanesArr[i], 0, blockSize); + } + } + + public int squeezeBlock() { + int retVal = doubleKeccak(lanesArr[0], lanesArr[1]); + for (int i = 0; i < NRPAR; i++) { + l2bLittle(lanesArr[i], 0, buffers[i], 0, blockSize); + } + return retVal; + } + + @IntrinsicCandidate + private static int doubleKeccak(long[] lanes0, long[] lanes1) { + doubleKeccakJava(lanes0, lanes1); + return 1; + } + + private static int doubleKeccakJava(long[] lanes0, long[] lanes1) { + keccak(lanes0); + keccak(lanes1); + return 1; + } + + public static final class Shake128Parallel extends SHA3Parallel { + public Shake128Parallel(byte[][] buf) throws InvalidAlgorithmParameterException { + super(buf, 168); + } + } +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/SHAKE256.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/SHAKE256.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/SHAKE256.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/SHAKE256.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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.provider; - -/* - * The SHAKE256 extendable output function. - */ -public final class SHAKE256 extends SHA3 { - public SHAKE256(int d) { - super("SHAKE256", d, (byte) 0x1F, 64); - } - - public void update(byte in) { - engineUpdate(in); - } - public void update(byte[] in, int off, int len) { - engineUpdate(in, off, len); - } - - public byte[] digest() { - return engineDigest(); - } - - public void reset() { - engineReset(); - } -} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/SunEntries.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/SunEntries.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/provider/SunEntries.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/provider/SunEntries.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -189,20 +189,33 @@ attrs.clear(); attrs.put("ImplementedIn", "Software"); addWithAlias(p, "Signature", "HSS/LMS", "sun.security.provider.HSS", attrs); + + add(p, "Signature", "ML-DSA", "sun.security.provider.ML_DSA_Impls$SIG", attrs); + addWithAlias(p, "Signature", "ML-DSA-44", "sun.security.provider.ML_DSA_Impls$SIG2", attrs); + addWithAlias(p, "Signature", "ML-DSA-65", "sun.security.provider.ML_DSA_Impls$SIG3", attrs); + addWithAlias(p, "Signature", "ML-DSA-87", "sun.security.provider.ML_DSA_Impls$SIG5", attrs); + /* * Key Pair Generator engines */ attrs.clear(); attrs.put("ImplementedIn", "Software"); - attrs.put("KeySize", "2048"); // for DSA KPG and APG only String dsaKPGImplClass = "sun.security.provider.DSAKeyPairGenerator$"; dsaKPGImplClass += (useLegacyDSA? "Legacy" : "Current"); + attrs.put("KeySize", "2048"); addWithAlias(p, "KeyPairGenerator", "DSA", dsaKPGImplClass, attrs); + attrs.remove("KeySize"); + + add(p, "KeyPairGenerator", "ML-DSA", "sun.security.provider.ML_DSA_Impls$KPG", attrs); + addWithAlias(p, "KeyPairGenerator", "ML-DSA-44", "sun.security.provider.ML_DSA_Impls$KPG2", attrs); + addWithAlias(p, "KeyPairGenerator", "ML-DSA-65", "sun.security.provider.ML_DSA_Impls$KPG3", attrs); + addWithAlias(p, "KeyPairGenerator", "ML-DSA-87", "sun.security.provider.ML_DSA_Impls$KPG5", attrs); /* * Algorithm Parameter Generator engines */ + attrs.put("KeySize", "2048"); addWithAlias(p, "AlgorithmParameterGenerator", "DSA", "sun.security.provider.DSAParameterGenerator", attrs); attrs.remove("KeySize"); @@ -221,6 +234,11 @@ addWithAlias(p, "KeyFactory", "HSS/LMS", "sun.security.provider.HSS$KeyFactoryImpl", attrs); + add(p, "KeyFactory", "ML-DSA", "sun.security.provider.ML_DSA_Impls$KF", attrs); + addWithAlias(p, "KeyFactory", "ML-DSA-44", "sun.security.provider.ML_DSA_Impls$KF2", attrs); + addWithAlias(p, "KeyFactory", "ML-DSA-65", "sun.security.provider.ML_DSA_Impls$KF3", attrs); + addWithAlias(p, "KeyFactory", "ML-DSA-87", "sun.security.provider.ML_DSA_Impls$KF5", attrs); + /* * Digest engines */ @@ -251,6 +269,10 @@ "sun.security.provider.SHA3$SHA384", attrs); addWithAlias(p, "MessageDigest", "SHA3-512", "sun.security.provider.SHA3$SHA512", attrs); + addWithAlias(p, "MessageDigest", "SHAKE128-256", + "sun.security.provider.SHA3$SHAKE128Hash", attrs); + addWithAlias(p, "MessageDigest", "SHAKE256-512", + "sun.security.provider.SHA3$SHAKE256Hash", attrs); /* * Certificates diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -46,7 +46,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(); diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java 2026-10-19 12:10:20.000000000 +0000 @@ -55,7 +55,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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/ssl/SSLExtension.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/ssl/SSLExtension.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/ssl/SSLExtension.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,7 +143,7 @@ SupportedGroupsExtension.chOnLoadConsumer, null, null, - SupportedGroupsExtension.chOnTradAbsence, + SupportedGroupsExtension.chOnTradeAbsence, SupportedGroupsExtension.sgsStringizer), EE_SUPPORTED_GROUPS (0x000A, "supported_groups", SSLHandshake.ENCRYPTED_EXTENSIONS, @@ -434,7 +434,7 @@ KeyShareExtension.chOnLoadConsumer, null, null, - KeyShareExtension.chOnTradAbsence, + KeyShareExtension.chOnTradeAbsence, KeyShareExtension.chStringizer), SH_KEY_SHARE (0x0033, "key_share", SSLHandshake.SERVER_HELLO, @@ -487,7 +487,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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/util/HostnameChecker.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/util/HostnameChecker.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/util/HostnameChecker.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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,14 +140,19 @@ } 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))) { @@ -158,8 +163,7 @@ } } throw new CertificateException("No subject alternative " + - "names matching " + "IP address " + - expectedIP + " found"); + "names matching IP address " + expectedIP + " found"); } /** diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/util/KeyChoices.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/util/KeyChoices.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/util/KeyChoices.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/util/KeyChoices.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,289 @@ +/* + * 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.util; + +import java.security.*; +import java.util.Arrays; +import java.util.Locale; +import java.util.function.BiFunction; + +/** + * The content of an ML-KEM or ML-DSA private key is defined as a CHOICE + * among three different representations. For example: + *

+ *  ML-KEM-1024-PrivateKey ::= CHOICE {
+ *       seed [0] OCTET STRING (SIZE (64)),
+ *       expandedKey OCTET STRING (SIZE (3168)),
+ *       both SEQUENCE {
+ *           seed OCTET STRING (SIZE (64)),
+ *           expandedKey OCTET STRING (SIZE (3168))
+ *           }
+ *       }
+ * 
+ * This class supports reading, writing, and converting between them. + *

+ * Current code follows RFC 9935 and RFC 9881. + */ +public final class KeyChoices { + + public enum Type { SEED, EXPANDED_KEY, BOTH } + + private record Choice(Type type, byte[] seed, byte[] expanded) {} + + /** + * Gets the preferred choice type for an algorithm, defined as an + * overridable security property "jdk..pkcs8.encoding". + * + * @param name "mlkem" or "mldsa". + * @throws IllegalArgumentException if property is invalid value + * @return the type + */ + public static Type getPreferred(String name) { + var prop = SecurityProperties.privilegedGetOverridable( + "jdk." + name + ".pkcs8.encoding"); + if (prop == null) { + return Type.SEED; + } + return switch (prop.toLowerCase(Locale.ROOT)) { + case "seed" -> Type.SEED; + case "expandedkey" -> Type.EXPANDED_KEY; + case "both" -> Type.BOTH; + default -> throw new IllegalArgumentException("Unknown format: " + prop); + }; + } + + /** + * Writes one of the ML-KEM or ML-DSA private key formats. + *

+ * This method does not check the length of the inputs or whether + * they match each other. The caller must make sure `seed` and/or + * `expanded` are provided if `type` requires any of them. + * + * @param type preferred output choice type + * @param seed the seed, could be null + * @param expanded the expanded key, could be null + * @return one of the choices + */ + public static byte[] writeToChoice(Type type, byte[] seed, byte[] expanded) { + byte[] skOctets; + // Ensures using one-byte len in DER + assert seed == null || seed.length < 128; + // Ensures using two-byte len in DER + assert expanded == null || expanded.length > 256 && expanded.length < 60000; + + return switch (type) { + case SEED -> { + assert seed != null; + skOctets = new byte[seed.length + 2]; + skOctets[0] = (byte)0x80; + skOctets[1] = (byte) seed.length; + System.arraycopy(seed, 0, skOctets, 2, seed.length); + yield skOctets; + } + case EXPANDED_KEY -> { + assert expanded != null; + skOctets = new byte[expanded.length + 4]; + skOctets[0] = 0x04; + writeShortLength(skOctets, 1, expanded.length); + System.arraycopy(expanded, 0, skOctets, 4, expanded.length); + yield skOctets; + } + case BOTH -> { + assert seed != null; + assert expanded != null; + skOctets = new byte[10 + seed.length + expanded.length]; + skOctets[0] = 0x30; + writeShortLength(skOctets, 1, 6 + seed.length + expanded.length); + skOctets[4] = 0x04; + skOctets[5] = (byte)seed.length; + System.arraycopy(seed, 0, skOctets, 6, seed.length); + skOctets[6 + seed.length] = 0x04; + writeShortLength(skOctets, 7 + seed.length, expanded.length); + System.arraycopy(expanded, 0, skOctets, 10 + seed.length, expanded.length); + yield skOctets; + } + }; + } + + /** + * Gets the type of input. + * + * @param input input bytes + * @return the type + * @throws InvalidKeyException if input is invalid + */ + public static Type typeOfChoice(byte[] input) throws InvalidKeyException { + if (input.length < 1) { + throw new InvalidKeyException("Empty key"); + } + return switch (input[0]) { + case (byte) 0x80 -> Type.SEED; + case 0x04 -> Type.EXPANDED_KEY; + case 0x30 -> Type.BOTH; + default -> throw new InvalidKeyException("Wrong tag: " + input[0]); + }; + } + + /** + * Splits one of the ML-KEM or ML-DSA private key formats into + * seed and expandedKey, if exists. + * + * @param seedLen correct seed length + * @param input input bytes + * @return a {@code Choice} object. Byte arrays inside are newly allocated + * @throws InvalidKeyException if input is invalid + */ + private static Choice readFromChoice(int seedLen, byte[] input) + throws InvalidKeyException { + if (input.length < seedLen + 2) { + throw new InvalidKeyException("Too short"); + } + return switch (input[0]) { + case (byte) 0x80 -> { + // 80 SEED_LEN + if (input[1] != seedLen && input.length != seedLen + 2) { + throw new InvalidKeyException("Invalid seed"); + } + yield new Choice(Type.SEED, + Arrays.copyOfRange(input, 2, seedLen + 2), null); + } + case 0x04 -> { + // 04 82 nn nn + if (readShortLength(input, 1) != input.length - 4) { + throw new InvalidKeyException("Invalid expandedKey"); + } + yield new Choice(Type.EXPANDED_KEY, + null, Arrays.copyOfRange(input, 4, input.length)); + } + case 0x30 -> { + // 30 82 mm mm 04 SEED_LEN 04 82 nn nn + if (input.length < 6 + seedLen + 4) { + throw new InvalidKeyException("Too short"); + } + if (readShortLength(input, 1) != input.length - 4 + || input[4] != 0x04 + || input[5] != (byte)seedLen + || input[seedLen + 6] != 0x04 + || readShortLength(input, seedLen + 7) + != input.length - 10 - seedLen) { + throw new InvalidKeyException("Invalid both"); + } + yield new Choice(Type.BOTH, + Arrays.copyOfRange(input, 6, 6 + seedLen), + Arrays.copyOfRange(input, seedLen + 10, input.length)); + } + default -> throw new InvalidKeyException("Wrong tag: " + input[0]); + }; + } + + /** + * Reads from any encoding and write to the specified type. + * + * @param type preferred output choice type + * @param pname parameter set name + * @param seedLen seed length + * @param input the input encoding + * @param expander function to calculate expanded from seed, could be null + * if there is already expanded in input + * @return the preferred encoding + * @throws InvalidKeyException if input is invalid or does not have enough + * information to generate the output + */ + public static byte[] choiceToChoice(Type type, String pname, + int seedLen, byte[] input, + BiFunction expander) + throws InvalidKeyException { + var choice = readFromChoice(seedLen, input); + try { + if (type != Type.EXPANDED_KEY && choice.type == Type.EXPANDED_KEY) { + throw new InvalidKeyException( + "key contains not enough info to translate"); + } + var expanded = (choice.expanded == null && type != Type.SEED) + ? expander.apply(pname, choice.seed) + : choice.expanded; + return writeToChoice(type, choice.seed, expanded); + } finally { + if (choice.seed != null) { + Arrays.fill(choice.seed, (byte) 0); + } + if (choice.expanded != null) { + Arrays.fill(choice.expanded, (byte) 0); + } + } + } + + /** + * Reads from any choice of encoding and return the expanded format. + * + * @param pname parameter set name + * @param seedLen seed length + * @param input input encoding + * @param expander function to calculate expanded from seed, could be null + * if there is already expanded in input + * @return the expanded key + * @throws InvalidKeyException if input is invalid + */ + public static byte[] choiceToExpanded(String pname, + int seedLen, byte[] input, + BiFunction expander) + throws InvalidKeyException { + var choice = readFromChoice(seedLen, input); + if (choice.type == Type.BOTH) { + var calculated = expander.apply(pname, choice.seed); + if (!Arrays.equals(choice.expanded, calculated)) { + throw new InvalidKeyException("seed and expandedKey do not match"); + } + Arrays.fill(calculated, (byte)0); + } + try { + if (choice.expanded != null) { + return choice.expanded; + } + return expander.apply(pname, choice.seed); + } finally { + if (choice.seed != null) { + Arrays.fill(choice.seed, (byte)0); + } + } + } + + // Reads a 2 bytes length from DER encoding + private static int readShortLength(byte[] input, int from) + throws InvalidKeyException { + if (input[from] != (byte)0x82) { + throw new InvalidKeyException("Unexpected length"); + } + return ((input[from + 1] & 0xff) << 8) + (input[from + 2] & 0xff); + } + + // Writes a 2 bytes length to DER encoding + private static void writeShortLength(byte[] input, int from, int value) { + input[from] = (byte)0x82; + input[from + 1] = (byte) (value >> 8); + input[from + 2] = (byte) (value); + } +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/util/KeyUtil.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/util/KeyUtil.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/util/KeyUtil.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/util/KeyUtil.java 2026-10-19 12:10:20.000000000 +0000 @@ -26,9 +26,13 @@ package sun.security.util; import java.math.BigInteger; +import java.security.AccessController; import java.security.AlgorithmParameters; import java.security.InvalidKeyException; import java.security.Key; +import java.security.PrivilegedAction; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.SecureRandom; import java.security.interfaces.*; import java.security.spec.*; @@ -186,13 +190,13 @@ */ public static final String fullDisplayAlgName(Key key) { String result = key.getAlgorithm(); - if (key instanceof ECKey) { - ECParameterSpec paramSpec = ((ECKey) key).getParams(); + if (key instanceof PrivateKey || key instanceof PublicKey) { + AlgorithmParameterSpec paramSpec = getParams(key); if (paramSpec instanceof NamedCurve nc) { result += " (" + nc.getNameAndAliases()[0] + ")"; + } else if (paramSpec instanceof NamedParameterSpec nps) { + result = nps.getName(); } - } else if (key instanceof EdECKey) { - result = ((EdECKey) key).getParams().getName(); } return result; } @@ -426,5 +430,30 @@ return t; } + @SuppressWarnings({"deprecation", "removal"}) + public static AlgorithmParameterSpec getParams(Key key) { + try { + var m = key.getClass().getMethod("getParams"); + if (!m.isAccessible()) { + PrivilegedAction pa = () -> { + m.setAccessible(true); + return null; + }; + AccessController.doPrivileged(pa); + } + var result = m.invoke(key); + if (result instanceof AlgorithmParameterSpec spec) { + return spec; + } + } catch (NoSuchMethodException e) { + } catch (ReflectiveOperationException e) { + } + return null; + } + + public static boolean isSupportedKeyAgreementOutputAlgorithm(String alg) { + return alg.equalsIgnoreCase("TlsPremasterSecret") + || alg.equalsIgnoreCase("Generic"); + } } diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/util/KnownOIDs.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/util/KnownOIDs.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/util/KnownOIDs.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/util/KnownOIDs.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, 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 @@ -152,8 +152,8 @@ SHA3_256("2.16.840.1.101.3.4.2.8", "SHA3-256"), SHA3_384("2.16.840.1.101.3.4.2.9", "SHA3-384"), SHA3_512("2.16.840.1.101.3.4.2.10", "SHA3-512"), - SHAKE128("2.16.840.1.101.3.4.2.11"), - SHAKE256("2.16.840.1.101.3.4.2.12"), + SHAKE128_256("2.16.840.1.101.3.4.2.11", "SHAKE128-256", "SHAKE128"), + SHAKE256_512("2.16.840.1.101.3.4.2.12", "SHAKE256-512", "SHAKE256"), HmacSHA3_224("2.16.840.1.101.3.4.2.13", "HmacSHA3-224"), HmacSHA3_256("2.16.840.1.101.3.4.2.14", "HmacSHA3-256"), HmacSHA3_384("2.16.840.1.101.3.4.2.15", "HmacSHA3-384"), @@ -178,6 +178,14 @@ SHA3_256withRSA("2.16.840.1.101.3.4.3.14", "SHA3-256withRSA"), SHA3_384withRSA("2.16.840.1.101.3.4.3.15", "SHA3-384withRSA"), SHA3_512withRSA("2.16.840.1.101.3.4.3.16", "SHA3-512withRSA"), + ML_DSA_44("2.16.840.1.101.3.4.3.17", "ML-DSA-44"), + ML_DSA_65("2.16.840.1.101.3.4.3.18", "ML-DSA-65"), + ML_DSA_87("2.16.840.1.101.3.4.3.19", "ML-DSA-87"), + + // kems 2.16.840.1.101.3.4.4.* + ML_KEM_512("2.16.840.1.101.3.4.4.1", "ML-KEM-512"), + ML_KEM_768("2.16.840.1.101.3.4.4.2", "ML-KEM-768"), + ML_KEM_1024("2.16.840.1.101.3.4.4.3", "ML-KEM-1024"), // RSASecurity // PKCS1 1.2.840.113549.1.1.* diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/util/SignatureUtil.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/util/SignatureUtil.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/util/SignatureUtil.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/util/SignatureUtil.java 2026-10-19 12:10:20.000000000 +0000 @@ -33,7 +33,9 @@ import java.security.spec.*; import java.util.Locale; +import sun.security.pkcs.NamedPKCS8Key; import sun.security.rsa.RSAUtil; +import sun.security.util.KeyUtil; import jdk.internal.access.SharedSecrets; import sun.security.x509.AlgorithmId; @@ -197,7 +199,7 @@ static { try { sha512 = new AlgorithmId(ObjectIdentifier.of(KnownOIDs.SHA_512)); - shake256 = new AlgorithmId(ObjectIdentifier.of(KnownOIDs.SHAKE256)); + shake256 = new AlgorithmId(ObjectIdentifier.of(KnownOIDs.SHAKE256_512)); shake256$512 = new AlgorithmId( ObjectIdentifier.of(KnownOIDs.SHAKE256_LEN), new DerValue((byte) 2, new byte[]{2, 0})); // int 512 @@ -273,7 +275,7 @@ return signatureAlgorithm.substring(0, with); } else { throw new IllegalArgumentException( - "Unknown algorithm: " + signatureAlgorithm); + "Cannot extract digest algorithm from " + signatureAlgorithm); } } @@ -386,8 +388,8 @@ public static AlgorithmId fromSignature(Signature sigEngine, PrivateKey key) throws SignatureException { try { - if (key instanceof EdECKey) { - return AlgorithmId.get(((EdECKey) key).getParams().getName()); + if (KeyUtil.getParams(key) instanceof NamedParameterSpec nps) { + return AlgorithmId.get(nps.getName()); } AlgorithmParameters params = null; @@ -427,6 +429,14 @@ public static void checkKeyAndSigAlgMatch(PrivateKey key, String sAlg) { String kAlg = key.getAlgorithm().toUpperCase(Locale.ENGLISH); sAlg = checkName(sAlg); + if (key instanceof NamedPKCS8Key n8k) { + if (!sAlg.equalsIgnoreCase(n8k.getAlgorithm()) + && !sAlg.equalsIgnoreCase(n8k.getParams().getName())) { + throw new IllegalArgumentException( + "key algorithm not compatible with signature algorithm"); + } + return; + } switch (sAlg) { case "RSASSA-PSS" -> { if (!kAlg.equals("RSASSA-PSS") diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java 2026-10-19 12:10:20.000000000 +0000 @@ -38,12 +38,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) @@ -56,10 +53,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) @@ -72,10 +68,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) @@ -89,9 +84,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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/validator/SymantecTLSPolicy.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/validator/SymantecTLSPolicy.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/validator/SymantecTLSPolicy.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/AlgorithmId.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/x509/AlgorithmId.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/AlgorithmId.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,10 +126,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 { @@ -162,38 +187,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); @@ -647,30 +644,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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/DNSName.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/x509/DNSName.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/DNSName.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/IPAddressName.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/x509/IPAddressName.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/IPAddressName.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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.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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/NamedX509Key.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/x509/NamedX509Key.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/NamedX509Key.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/x509/NamedX509Key.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,120 @@ +/* + * 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. 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.x509; + +import sun.security.util.BitArray; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.Serial; +import java.security.InvalidKeyException; +import java.security.KeyRep; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.security.spec.NamedParameterSpec; + +/// Represents a public key from an algorithm family that is specialized +/// with a named parameter set. +/// +/// This key is generated by either a [sun.security.provider.NamedKeyPairGenerator] +/// or [sun.security.provider.NamedKeyFactory]. Its [#getAlgorithm] method +/// returns the algorithm family name, while its [#getParams()] method returns +/// the parameter set name as a [NamedParameterSpec] object. The algorithm +/// identifier in the X.509 encoding of the key is always a single OID derived +/// from the parameter set name. +/// +/// @see sun.security.provider.NamedKeyPairGenerator +public final class NamedX509Key extends X509Key { + @Serial + private static final long serialVersionUID = 1L; + + private final String fname; + private final transient NamedParameterSpec paramSpec; + private final byte[] rawBytes; + + /// Ctor from family name, parameter set name, raw key bytes. + /// Key bytes won't be cloned, caller must relinquish ownership + public NamedX509Key(String fname, String pname, byte[] rawBytes) { + this.fname = fname; + this.paramSpec = new NamedParameterSpec(pname); + try { + this.algid = AlgorithmId.get(pname); + } catch (NoSuchAlgorithmException e) { + throw new ProviderException(e); + } + this.rawBytes = rawBytes; + + setKey(new BitArray(rawBytes.length * 8, rawBytes)); + } + + /// Ctor from family name, and X.509 bytes. Input byte array + /// is copied. Caller can modify it after the method call. + public NamedX509Key(String fname, byte[] encoded) throws InvalidKeyException { + this.fname = fname; + decode(encoded); + this.paramSpec = new NamedParameterSpec(algid.getName()); + if (algid.encodedParams != null) { + throw new InvalidKeyException("algorithm identifier has params"); + } + this.rawBytes = getKey().toByteArray(); + } + + @Override + public String toString() { + // Do not modify: this can be used by earlier JDKs that + // do not have the getParams() method + return paramSpec.getName() + " public key"; + } + + /// Returns the reference to the internal key. Caller must not modify + /// the content or keep a reference. + public byte[] getRawBytes() { + return rawBytes; + } + + public NamedParameterSpec getParams() { + return paramSpec; + } + + @Override + public String getAlgorithm() { + return fname; + } + + @java.io.Serial + private Object writeReplace() throws java.io.ObjectStreamException { + return new KeyRep(KeyRep.Type.PUBLIC, getAlgorithm(), getFormat(), + getEncoded()); + } + + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "NamedX509Key keys are not directly deserializable"); + } +} diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/URIName.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/security/x509/URIName.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/security/x509/URIName.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.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, 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 @@ -154,10 +154,15 @@ var cands = ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR)) .getCandidateLocales("", locale); for (int i = 1; i < cands.size() ; i++) { - String[] parentNames = super.getDisplayNameArray(id, cands.get(i)); + var loc = cands.get(i); + String[] parentNames = super.getDisplayNameArray(id, loc); if (parentNames != null && !parentNames[index].isEmpty()) { - names[index] = parentNames[index]; - return; + // Long names in ROOT locale should not be copied, as they can be generated + // with the fallback mechanisms below + if (!loc.equals(Locale.ROOT) || index % 2 == 0) { + names[index] = parentNames[index]; + return; + } } } } diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java 2026-10-19 12:10:20.000000000 +0000 @@ -105,6 +105,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(); @@ -321,7 +324,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; @@ -378,7 +382,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-21-21.0.12.1+1/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java openjdk-21-21.0.13+9/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java --- openjdk-21-21.0.12.1+1/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/conf/security/java.security openjdk-21-21.0.13+9/src/java.base/share/conf/security/java.security --- openjdk-21-21.0.12.1+1/src/java.base/share/conf/security/java.security 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -1393,23 +1393,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 @@ -1658,3 +1653,28 @@ # be used instead. The default size limit is 20MiB. # This property may be overridden by a System property of the same name. com.sun.security.crl.maxSize = 20971520 + +# +# PKCS #8 encoding format for newly created ML-KEM and ML-DSA private keys +# +# RFC 9935 and RFC 9881 define three possible formats for a private key: +# a seed (64 bytes for ML-KEM, 32 bytes for ML-DSA), an expanded private key, +# or a sequence containing both. +# +# The following security properties determine the encoding format used when a +# new keypair is generated with a KeyPairGenerator, and the output of the +# translateKey method on an existing key using a ML-KEM or ML-DSA KeyFactory. +# +# Valid values for these properties are "seed", "expandedKey", and "both" +# (case-insensitive). The default is "seed". +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +# Note: These properties are currently used by the SunJCE (for ML-KEM) and SUN +# (for ML-DSA) providers in the JDK Reference implementation. They are not +# guaranteed to be supported by other implementations or third-party security +# providers. +# +#jdk.mlkem.pkcs8.encoding = seed +#jdk.mldsa.pkcs8.encoding = seed diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/data/cacerts/luxtrustglobalrootca openjdk-21-21.0.13+9/src/java.base/share/data/cacerts/luxtrustglobalrootca --- openjdk-21-21.0.12.1+1/src/java.base/share/data/cacerts/luxtrustglobalrootca 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/data/tzdata/VERSION openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/VERSION --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/VERSION 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/data/tzdata/africa openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/africa --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/africa 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/data/tzdata/asia openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/asia --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/asia 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/data/tzdata/australasia openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/australasia --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/australasia 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/data/tzdata/backward openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/backward --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/backward 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/data/tzdata/europe openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/europe --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/europe 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/data/tzdata/leapseconds openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/leapseconds --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/leapseconds 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/data/tzdata/northamerica openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/northamerica --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/northamerica 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/data/tzdata/southamerica openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/southamerica --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/southamerica 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/data/tzdata/tzmappings.override openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/tzmappings.override --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/tzmappings.override 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/tzmappings.override 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,44 @@ +# +# Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# + +# 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-21-21.0.12.1+1/src/java.base/share/data/tzdata/zone.tab openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/zone.tab --- openjdk-21-21.0.12.1+1/src/java.base/share/data/tzdata/zone.tab 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/data/tzdata/zone.tab 2026-10-19 12:10:20.000000000 +0000 @@ -139,20 +139,20 @@ CA +4339-07923 America/Toronto Eastern - ON & QC (most areas) CA +6344-06828 America/Iqaluit Eastern - NU (most areas) CA +484531-0913718 America/Atikokan EST - ON (Atikokan), NU (Coral H) -CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba +CA +4953-09709 America/Winnipeg EST - ON (west), Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) -CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W) +CA +5333-11328 America/Edmonton CST - AB, BC(E), NT(E), SK(W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) -CA +682059-1334300 America/Inuvik Mountain - NT (west) +CA +682059-1334300 America/Inuvik CST - NT (west) +CA +4916-12307 America/Vancouver MST - BC (most areas) CA +4906-11631 America/Creston MST - BC (Creston) CA +5546-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson) CA +6043-13503 America/Whitehorse MST - Yukon (east) CA +6404-13925 America/Dawson MST - Yukon (west) -CA +4916-12307 America/Vancouver Pacific - BC (most areas) CC -1210+09655 Indian/Cocos CD -0418+01518 Africa/Kinshasa Dem. Rep. of Congo (west) CD -1140+02728 Africa/Lubumbashi Dem. Rep. of Congo (east) diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/lib/security/default.policy openjdk-21-21.0.13+9/src/java.base/share/lib/security/default.policy --- openjdk-21-21.0.12.1+1/src/java.base/share/lib/security/default.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/lib/security/default.policy 2026-10-19 12:10:20.000000000 +0000 @@ -19,6 +19,7 @@ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util"; permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc"; + permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.util"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.ref"; permission java.lang.RuntimePermission "modifyThread"; permission java.net.SocketPermission "*","connect,resolve"; diff -Nru openjdk-21-21.0.12.1+1/src/java.base/share/native/libjava/Reference.c openjdk-21-21.0.13+9/src/java.base/share/native/libjava/Reference.c --- openjdk-21-21.0.12.1+1/src/java.base/share/native/libjava/Reference.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/native/libjli/java.c openjdk-21-21.0.13+9/src/java.base/share/native/libjli/java.c --- openjdk-21-21.0.12.1+1/src/java.base/share/native/libjli/java.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/share/native/libjli/java.c 2026-10-19 12:10:20.000000000 +0000 @@ -988,7 +988,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-21-21.0.12.1+1/src/java.base/share/native/libjli/jli_util.c openjdk-21-21.0.13+9/src/java.base/share/native/libjli/jli_util.c --- openjdk-21-21.0.12.1+1/src/java.base/share/native/libjli/jli_util.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/share/native/libverify/check_code.c openjdk-21-21.0.13+9/src/java.base/share/native/libverify/check_code.c --- openjdk-21-21.0.12.1+1/src/java.base/share/native/libverify/check_code.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.base/unix/native/libjava/TimeZone_md.c openjdk-21-21.0.13+9/src/java.base/unix/native/libjava/TimeZone_md.c --- openjdk-21-21.0.12.1+1/src/java.base/unix/native/libjava/TimeZone_md.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -113,7 +113,7 @@ { static const char *zidir = "zoneinfo/"; - char *pos = strstr((const char *)str, zidir); + char* pos = strstr(str, zidir); if (pos == NULL) { return NULL; } @@ -369,33 +369,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) { @@ -448,10 +430,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-21-21.0.12.1+1/src/java.base/unix/native/libnet/NetworkInterface.c openjdk-21-21.0.13+9/src/java.base/unix/native/libnet/NetworkInterface.c --- openjdk-21-21.0.12.1+1/src/java.base/unix/native/libnet/NetworkInterface.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/unix/native/libnet/NetworkInterface.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, 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 @@ -201,7 +201,7 @@ netif *ifs, *curr; jboolean isCopy; const char* name_utf; - char *colonP; + const char* colonP; jobject obj = NULL; if (name != NULL) { diff -Nru openjdk-21-21.0.12.1+1/src/java.base/unix/native/libnio/ch/Net.c openjdk-21-21.0.13+9/src/java.base/unix/native/libnio/ch/Net.c --- openjdk-21-21.0.12.1+1/src/java.base/unix/native/libnio/ch/Net.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.base/unix/native/libnio/ch/Net.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -910,13 +910,13 @@ errno = 0; result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n); if (result < 0) { - handleSocketError(env, errno); + handleSocketErrorWithMessage(env, errno, "getsockopt failed"); return JNI_FALSE; } else if (error) { - handleSocketError(env, error); + handleSocketErrorWithMessage(env, error, "connect failed"); return JNI_FALSE; } else if ((poller.revents & POLLHUP) != 0) { - handleSocketError(env, ENOTCONN); + handleSocketErrorWithMessage(env, ENOTCONN, "peer closed connection after accepting"); return JNI_FALSE; } // connected diff -Nru openjdk-21-21.0.12.1+1/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java openjdk-21-21.0.13+9/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java --- openjdk-21-21.0.12.1+1/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2021, 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; @@ -1328,19 +1327,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-21-21.0.12.1+1/src/java.desktop/macosx/classes/sun/lwawt/macosx/CImage.java openjdk-21-21.0.13+9/src/java.desktop/macosx/classes/sun/lwawt/macosx/CImage.java --- openjdk-21-21.0.12.1+1/src/java.desktop/macosx/classes/sun/lwawt/macosx/CImage.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.desktop/macosx/native/libawt_lwawt/awt/CImage.m openjdk-21-21.0.13+9/src/java.desktop/macosx/native/libawt_lwawt/awt/CImage.m --- openjdk-21-21.0.12.1+1/src/java.desktop/macosx/native/libawt_lwawt/awt/CImage.m 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m openjdk-21-21.0.13+9/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m --- openjdk-21-21.0.12.1+1/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m openjdk-21-21.0.13+9/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m --- openjdk-21-21.0.12.1+1/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/shaders.metal openjdk-21-21.0.13+9/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/shaders.metal --- openjdk-21-21.0.12.1+1/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/shaders.metal 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java openjdk-21-21.0.13+9/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java --- openjdk-21-21.0.12.1+1/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java openjdk-21-21.0.13+9/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java --- openjdk-21-21.0.12.1+1/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java 2026-10-19 12:10:20.000000000 +0000 @@ -1257,9 +1257,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-21-21.0.12.1+1/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java openjdk-21-21.0.13+9/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java --- openjdk-21-21.0.12.1+1/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -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-21-21.0.12.1+1/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java openjdk-21-21.0.13+9/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java --- openjdk-21-21.0.12.1+1/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -304,9 +304,12 @@ EventListener l = (EventListener)s.readObject(); String name = (String) listenerTypeOrNull; ReflectUtil.checkPackageAccess(name); - @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-21-21.0.12.1+1/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c openjdk-21-21.0.13+9/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c --- openjdk-21-21.0.12.1+1/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.desktop/share/native/libfontmanager/freetypeScaler.c openjdk-21-21.0.13+9/src/java.desktop/share/native/libfontmanager/freetypeScaler.c --- openjdk-21-21.0.12.1+1/src/java.desktop/share/native/libfontmanager/freetypeScaler.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.desktop/share/native/libfontmanager/freetypeScaler.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, 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 @@ -850,10 +850,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-21-21.0.12.1+1/src/java.instrument/share/native/libinstrument/JPLISAgent.c openjdk-21-21.0.13+9/src/java.instrument/share/native/libinstrument/JPLISAgent.c --- openjdk-21-21.0.12.1+1/src/java.instrument/share/native/libinstrument/JPLISAgent.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c openjdk-21-21.0.13+9/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c --- openjdk-21-21.0.12.1+1/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java openjdk-21-21.0.13+9/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java --- openjdk-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -78,7 +78,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-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java openjdk-21-21.0.13+9/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java --- openjdk-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -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-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java openjdk-21-21.0.13+9/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java --- openjdk-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java openjdk-21-21.0.13+9/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java --- openjdk-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -137,7 +137,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-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java openjdk-21-21.0.13+9/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java --- openjdk-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -109,6 +109,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 VersionHelper.isSerialDataAllowed(); + } + + /** * Encode an object in LDAP attributes. * Supports binding Referenceable or Reference, Serializable, * and DirContext. diff -Nru openjdk-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/naming/internal/NamingManagerHelper.java openjdk-21-21.0.13+9/src/java.naming/share/classes/com/sun/naming/internal/NamingManagerHelper.java --- openjdk-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/naming/internal/NamingManagerHelper.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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; } @@ -256,7 +256,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++) { @@ -265,7 +266,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; } @@ -275,7 +276,8 @@ } private static Object processURL(Object refInfo, Name name, - Context nameCtx, Hashtable environment) + Context nameCtx, Hashtable environment, + Predicate> factoryFilter) throws NamingException { Object answer; @@ -286,7 +288,7 @@ String scheme = getURLScheme(url); if (scheme != null) { answer = getURLObject(scheme, refInfo, name, nameCtx, - environment); + environment, factoryFilter); if (answer != null) { return answer; } @@ -302,7 +304,7 @@ String scheme = getURLScheme(urls[i]); if (scheme != null) { answer = getURLObject(scheme, refInfo, name, nameCtx, - environment); + environment, factoryFilter); if (answer != null) return answer; } @@ -344,11 +346,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" @@ -359,6 +366,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-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java openjdk-21-21.0.13+9/src/java.naming/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java --- openjdk-21-21.0.12.1+1/src/java.naming/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,21 @@ 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.security.AccessController; +import java.security.PrivilegedAction; +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 +57,135 @@ 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"; + static final List LDAP_DISABLED_URL_SCHEMES_LIST; + + static { + PrivilegedAction act + = () -> System.getProperty(LDAP_DISABLED_URL_SCHEMES_PROP, + DEFAULT_LDAP_DISABLED_URL_SCHEMES); + @SuppressWarnings("removal") + String schemes = AccessController.doPrivileged(act); + String[] protocols = 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-21-21.0.12.1+1/src/java.naming/share/classes/module-info.java openjdk-21-21.0.13+9/src/java.naming/share/classes/module-info.java --- openjdk-21-21.0.12.1+1/src/java.naming/share/classes/module-info.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java openjdk-21-21.0.13+9/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java --- openjdk-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2021, 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")); @@ -145,33 +145,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, @@ -203,6 +221,7 @@ static class AuthInfo { final boolean fromcache; final String scheme; + final URI requestor; int retries; PasswordAuthentication credentials; // used in request CacheEntry cacheEntry; // if used @@ -210,19 +229,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; } @@ -231,7 +255,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; @@ -240,34 +266,45 @@ @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(); 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; @@ -303,16 +340,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 { @@ -325,16 +363,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"); } @@ -355,8 +394,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-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/CheckFilename.java openjdk-21-21.0.13+9/src/java.net.http/share/classes/jdk/internal/net/http/CheckFilename.java --- openjdk-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/CheckFilename.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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\u00B9", "COM\u00B2", "COM\u00B3", "CON", "CONIN$", + "CONOUT$", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", + "LPT9", "LPT\u00B9", "LPT\u00B2", "LPT\u00B3", "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-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java openjdk-21-21.0.13+9/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java --- openjdk-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -1709,8 +1709,8 @@ } private void initFilters() { - addFilter(AuthenticationFilter.class); addFilter(RedirectFilter.class); + addFilter(AuthenticationFilter.class); if (this.cookieHandler != null) { addFilter(CookieFilter.class); } diff -Nru openjdk-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/RedirectFilter.java openjdk-21-21.0.13+9/src/java.net.http/share/classes/jdk/internal/net/http/RedirectFilter.java --- openjdk-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/RedirectFilter.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java openjdk-21-21.0.13+9/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java --- openjdk-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java 2026-10-19 12:10:20.000000000 +0000 @@ -381,7 +381,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-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/ResponseContent.java openjdk-21-21.0.13+9/src/java.net.http/share/classes/jdk/internal/net/http/ResponseContent.java --- openjdk-21-21.0.12.1+1/src/java.net.http/share/classes/jdk/internal/net/http/ResponseContent.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.prefs/unix/native/libprefs/FileSystemPreferences.c openjdk-21-21.0.13+9/src/java.prefs/unix/native/libprefs/FileSystemPreferences.c --- openjdk-21-21.0.12.1+1/src/java.prefs/unix/native/libprefs/FileSystemPreferences.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.prefs/unix/native/libprefs/FileSystemPreferences.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, 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 @@ -73,7 +73,6 @@ int fd, rc; int result[2] = {0, 0}; jintArray javaResult = NULL; - int old_umask; FLOCK fl; if (!fname) @@ -92,10 +91,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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -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 { @@ -590,34 +592,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, @@ -670,44 +681,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 { @@ -827,45 +800,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 /** @@ -1411,14 +1345,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, @@ -1426,36 +1357,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, @@ -1463,26 +1371,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, @@ -1549,13 +1437,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, @@ -1563,36 +1449,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, @@ -1600,27 +1463,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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -931,39 +931,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) { - System.out.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 { @@ -1021,79 +988,35 @@ public final byte[] unwrap(byte[] inBuf, int offset, int len, MessageProp msgProp) - throws GSSException { - - if (DEBUG) { - System.out.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) { + System.out.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 { @@ -1147,31 +1070,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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/MessageToken_v2.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/jgss/krb5/MessageToken_v2.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/MessageToken_v2.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/WrapToken_v2.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/jgss/krb5/WrapToken_v2.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/jgss/krb5/WrapToken_v2.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java 2026-10-19 12:10:20.000000000 +0000 @@ -509,7 +509,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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -53,11 +53,14 @@ private boolean DEBUG = Krb5.DEBUG; - 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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2021, 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 @@ -342,7 +342,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 && ( @@ -355,7 +355,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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/ETypeInfo2.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/krb5/internal/ETypeInfo2.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/ETypeInfo2.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java openjdk-21-21.0.13+9/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java --- openjdk-21-21.0.12.1+1/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -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-21-21.0.12.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java openjdk-21-21.0.13+9/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java --- openjdk-21-21.0.12.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java openjdk-21-21.0.13+9/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java --- openjdk-21-21.0.12.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -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-21-21.0.12.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java openjdk-21-21.0.13+9/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java --- openjdk-21-21.0.12.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java openjdk-21-21.0.13+9/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java --- openjdk-21-21.0.12.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java openjdk-21-21.0.13+9/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java --- openjdk-21-21.0.12.1+1/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/RowSetResourceBundle.properties openjdk-21-21.0.13+9/src/java.sql.rowset/share/classes/com/sun/rowset/RowSetResourceBundle.properties --- openjdk-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/RowSetResourceBundle.properties 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -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-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java openjdk-21-21.0.13+9/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java --- openjdk-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java openjdk-21-21.0.13+9/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java --- openjdk-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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,27 @@ package com.sun.rowset.internal; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; 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 +54,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 +97,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 +127,96 @@ * @see XmlReaderContentHandler */ public void readXML(WebRowSet caller, java.io.InputStream iStream) throws SQLException { + readXml(caller, new InputSource(iStream)); + } + + /** + * 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 { - InputSource is = new InputSource(iStream); - DefaultHandler dh = new XmlErrorHandler(); + boolean validating = validationEnabled(); - 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()); + SAXParserFactory spf = SAXParserFactory.newDefaultNSInstance(); + spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + if (validating) { + spf.setSchema(getSchemaPrivileged()); + } + + 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); + } + } + /** + * 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); } - // Will be here if trying to write beyond the RowSet limits + SchemaFactory sf = SchemaFactory.newDefaultInstance(); + sf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + return sf.newSchema(stdSchema); + } - catch (ArrayIndexOutOfBoundsException aie) { - throw new SQLException(resBundle.handleGetObject("wrsxmlreader.invalidcp").toString()); + @SuppressWarnings("removal") + private Schema getSchemaPrivileged() throws SAXException { + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public Schema run() throws SAXException { + return getSchema(); + } + }); + } catch (PrivilegedActionException e) { + throw (SAXException) e.getException(); } + } - catch (Throwable e) { - throw new SQLException(MessageFormat.format(resBundle.handleGetObject("wrsxmlreader.readxml").toString() , e.getMessage())); - } + /** + * 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 + */ + @SuppressWarnings("removal") + private static boolean validationEnabled() { + return !"false".equalsIgnoreCase( + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public String run() { + return System.getProperty(VALIDATION_PROPERTY, "true"); + } + }).trim()); } /** diff -Nru openjdk-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java openjdk-21-21.0.13+9/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java --- openjdk-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlErrorHandler.java openjdk-21-21.0.13+9/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlErrorHandler.java --- openjdk-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlErrorHandler.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java openjdk-21-21.0.13+9/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java --- openjdk-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -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 @@ -743,6 +822,8 @@ } break; case RowTag: + case ModTag: + case InsDelTag: try { rs.insertRow(); rs.moveToCurrentRow(); @@ -752,6 +833,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())); @@ -763,6 +846,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) { @@ -780,33 +865,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: @@ -826,10 +898,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(); @@ -843,6 +912,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 @@ -862,6 +944,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); /** @@ -1028,10 +1117,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); @@ -1043,7 +1134,7 @@ rs.setConcurrency(getIntegerValue(s)); break; case DatasourceTag: - if (nullValue) + if (nullValue || s == null || s.isEmpty()) rs.setDataSourceName(null); else rs.setDataSourceName(s); @@ -1130,14 +1221,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); @@ -1306,8 +1397,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 @@ -1317,12 +1407,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: @@ -1331,7 +1415,7 @@ private void insertValue(String s) throws SQLException { - if (getNullValue()) { + if (s == null || getNullValue()) { rs.updateNull(idx); return; } diff -Nru openjdk-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlResolver.java openjdk-21-21.0.13+9/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlResolver.java --- openjdk-21-21.0.12.1+1/src/java.sql.rowset/share/classes/com/sun/rowset/internal/XmlResolver.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2022, 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 @@ -1028,10 +1028,10 @@ "smaller templates." }, - {ErrorMsg.DESERIALIZE_TRANSLET_ERR, "When Java security is enabled, " - + "support for deserializing TemplatesImpl is disabled. This can be " - + "overridden by setting the jdk.xml.enableTemplatesImplDeserialization" - + " system property to true."}, + {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 " diff -Nru openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2022, 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 @@ -169,12 +169,11 @@ public static final String OUTLINE_ERR_METHOD_TOO_BIG = "OUTLINE_ERR_METHOD_TOO_BIG"; - public static final String DESERIALIZE_TRANSLET_ERR = "DESERIALIZE_TRANSLET_ERR"; - public static final String XPATH_LIMIT = "XPATH_LIMIT"; 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-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2021, 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 @@ -61,6 +61,7 @@ import javax.xml.transform.URIResolver; import jdk.xml.internal.JdkConstants; import jdk.xml.internal.SecuritySupport; +import jdk.xml.internal.JdkXmlFeatures; /** @@ -272,6 +273,14 @@ } } + 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); @@ -286,7 +295,7 @@ _uriResolver = (URIResolver) is.readObject(); } - _tfactory = new TransformerFactoryImpl(); + _tfactory = tfactory; } diff -Nru openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/SchemaNamespaceSupport.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/SchemaNamespaceSupport.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/SchemaNamespaceSupport.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/MultipleScopeNamespaceSupport.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/MultipleScopeNamespaceSupport.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/MultipleScopeNamespaceSupport.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathContext.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathContext.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathContext.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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,7 @@ import javax.xml.transform.ErrorListener; import javax.xml.transform.SourceLocator; import javax.xml.transform.URIResolver; +import jdk.xml.internal.JdkXmlFeatures; import org.xml.sax.XMLReader; /** @@ -56,7 +57,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 +96,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 +135,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 = new JdkXmlFeatures(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-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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: Sep 2017 + * @LastModified: June 2026 */ public class FuncSystemProperty extends FunctionOneArg { @@ -95,7 +98,7 @@ warn(xctxt, XPATHErrorResources.WG_DONT_DO_ANYTHING_WITH_NS, new Object[]{ namespace, fullName }); //"Don't currently do anything with namespace "+namespace+" in property: "+fullName); - + checkSysPropAccess(xctxt, fullName); try { result = SecuritySupport.getSystemProperty(propName); @@ -118,6 +121,7 @@ } else { + checkSysPropAccess(xctxt, fullName); try { result = SecuritySupport.getSystemProperty(fullName); @@ -155,6 +159,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-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2022, 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 @@ -38,7 +38,7 @@ * * @author Ramesh Mandava * - * @LastModified: June 2025 + * @LastModified: June 2026 */ public class XPathFactoryImpl extends XPathFactory { @@ -192,6 +192,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-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -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; @@ -95,6 +95,7 @@ xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); } + xpathSupport.setJdkXmlFeatures(featureManager); xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); XObject xobj; diff -Nru openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java openjdk-21-21.0.13+9/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2022, 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: Jul 2022 + * @LastModified: June 2026 */ public class XPATHErrorResources extends ListResourceBundle { @@ -328,6 +328,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 @@ -869,6 +870,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-21-21.0.12.1+1/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java openjdk-21-21.0.13+9/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -395,4 +402,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-21-21.0.12.1+1/src/java.xml/share/classes/jdk/xml/internal/JdkXmlFeatures.java openjdk-21-21.0.13+9/src/java.xml/share/classes/jdk/xml/internal/JdkXmlFeatures.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/jdk/xml/internal/JdkXmlFeatures.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -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-21-21.0.12.1+1/src/java.xml/share/classes/module-info.java openjdk-21-21.0.13+9/src/java.xml/share/classes/module-info.java --- openjdk-21-21.0.12.1+1/src/java.xml/share/classes/module-info.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/java.xml/share/classes/module-info.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 @@ -701,7 +701,7 @@ * 9 * * - * jdk.xml.extensionClassLoader + * {@systemProperty jdk.xml.extensionClassLoader} * Sets a non-null ClassLoader instance to be used for loading XSLTC java * extension functions. * @@ -715,7 +715,7 @@ * 9 * * - * jdk.xml.xpathExprGrpLimit + * {@systemProperty jdk.xml.xpathExprGrpLimit} * Limits the number of groups an XPath expression can contain. * * yes @@ -732,14 +732,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 @@ -749,6 +749,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 if XSLT and XPath extension functions are to be allowed. * @@ -808,6 +830,24 @@ * Method 2 * 9 * + * + * {@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 + * + * [7] + * 7 + * * * *

    @@ -838,6 +878,10 @@ * are as shown in the table Processors. *

    * [6] Indicates the initial release the property is introduced. + *

    + * [7] 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. @@ -912,7 +956,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-21-21.0.12.1+1/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c openjdk-21-21.0.13+9/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c --- openjdk-21-21.0.12.1+1/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2015, 2018 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 @@ -140,13 +140,14 @@ memset(&sb, 0, sizeof(struct stat64)); /* - * 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 = stat64(p, &sb); + res = lstat64(p, &sb); if (res != 0) { /* save errno */ res = errno; @@ -155,7 +156,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-21-21.0.12.1+1/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c openjdk-21-21.0.13+9/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c --- openjdk-21-21.0.12.1+1/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.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 @@ -143,13 +143,14 @@ memset(&sb, 0, sizeof(struct stat64)); /* - * 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 = stat64(p, &sb); + res = lstat64(p, &sb); if (res != 0) { /* save errno */ res = errno; @@ -158,7 +159,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-21-21.0.12.1+1/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c openjdk-21-21.0.13+9/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c --- openjdk-21-21.0.12.1+1/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, 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 @@ -186,13 +186,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; @@ -201,7 +202,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-21-21.0.12.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java openjdk-21-21.0.13+9/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java --- openjdk-21-21.0.12.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -78,9 +78,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 { @@ -102,23 +101,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); } } @@ -860,6 +868,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 { @@ -960,6 +971,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-21-21.0.12.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java openjdk-21-21.0.13+9/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java --- openjdk-21-21.0.12.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,8 @@ import static sun.security.pkcs11.TemplateManager.*; import sun.security.pkcs11.wrapper.*; +import sun.security.util.KeyUtil; + import static sun.security.pkcs11.wrapper.PKCS11Constants.*; /** @@ -168,9 +170,9 @@ if (algorithm == null) { throw new NoSuchAlgorithmException("Algorithm must not be null"); } - if (!algorithm.equals("TlsPremasterSecret")) { - throw new NoSuchAlgorithmException - ("Only supported for algorithm TlsPremasterSecret"); + if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) { + throw new NoSuchAlgorithmException( + "Unsupported secret key algorithm: " + algorithm); } return nativeGenerateSecret(algorithm); } diff -Nru openjdk-21-21.0.12.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java openjdk-21-21.0.13+9/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java --- openjdk-21-21.0.12.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java 2026-10-19 12:10:20.000000000 +0000 @@ -945,7 +945,7 @@ params = new DSAParameterSpec(res[0], res[1], res[2]); } - protected DSAParams getParams() { + public DSAParams getParams() { fetchValues(); return params; } @@ -1248,7 +1248,7 @@ } } - protected ECParameterSpec getParams() { + public ECParameterSpec getParams() { fetchValues(); return params; } diff -Nru openjdk-21-21.0.12.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java openjdk-21-21.0.13+9/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java --- openjdk-21-21.0.12.1+1/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.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, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,6 +206,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); @@ -219,22 +220,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 { @@ -274,20 +264,19 @@ throw new NoSuchAlgorithmException("Algorithm must not be null"); } - if (algorithm.equals("TlsPremasterSecret")) { + if (KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) { // For now, only perform native derivation for TlsPremasterSecret - // as that is required for FIPS compliance. + // and Generic algorithms. TlsPremasterSecret is required for + // FIPS compliance and Generic is required for input to KDF. // For other algorithms, there are unresolved issues regarding // how this should work in JCE plus a Solaris truncation bug. // (bug not yet filed). return nativeGenerateSecret(algorithm); } - if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") && - !AllowKDF.VALUE) { - - throw new NoSuchAlgorithmException("Unsupported secret key " - + "algorithm: " + algorithm); + if (!AllowKDF.VALUE) { + throw new NoSuchAlgorithmException( + "Unsupported secret key algorithm: " + algorithm); } byte[] secret = engineGenerateSecret(); @@ -301,8 +290,6 @@ keyLen = 24; } else if (algorithm.equalsIgnoreCase("Blowfish")) { keyLen = Math.min(56, secret.length); - } else if (algorithm.equalsIgnoreCase("TlsPremasterSecret")) { - keyLen = secret.length; } else { throw new NoSuchAlgorithmException ("Unknown algorithm " + algorithm); @@ -330,10 +317,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(), @@ -346,18 +343,6 @@ int keyLen = (int)lenAttributes[0].getLong(); SecretKey key = P11Key.secretKey (session, keyID, algorithm, keyLen << 3, attributes); - if ("RAW".equals(key.getFormat())) { - // 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-21-21.0.12.1+1/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDHKeyAgreement.java openjdk-21-21.0.13+9/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDHKeyAgreement.java --- openjdk-21-21.0.12.1+1/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDHKeyAgreement.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDHKeyAgreement.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import sun.security.util.ArrayUtil; import sun.security.util.CurveDB; import sun.security.util.ECUtil; +import sun.security.util.KeyUtil; import sun.security.util.NamedCurve; import sun.security.util.math.ImmutableIntegerModuloP; import sun.security.util.math.IntegerFieldModuloP; @@ -253,11 +254,11 @@ if (algorithm == null) { throw new NoSuchAlgorithmException("Algorithm must not be null"); } - if (!(algorithm.equals("TlsPremasterSecret"))) { - throw new NoSuchAlgorithmException - ("Only supported for algorithm TlsPremasterSecret"); + if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) { + throw new NoSuchAlgorithmException( + "Unsupported secret key algorithm: " + algorithm); } - return new SecretKeySpec(engineGenerateSecret(), "TlsPremasterSecret"); + return new SecretKeySpec(engineGenerateSecret(), algorithm); } private static diff -Nru openjdk-21-21.0.12.1+1/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java openjdk-21-21.0.13+9/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java --- openjdk-21-21.0.12.1+1/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package sun.security.ec; +import sun.security.util.KeyUtil; + import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -207,9 +209,9 @@ throw new NoSuchAlgorithmException("Algorithm must not be null"); } - if (!(algorithm.equals("TlsPremasterSecret"))) { + if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) { throw new NoSuchAlgorithmException( - "Only supported for algorithm TlsPremasterSecret"); + "Unsupported secret key algorithm: " + algorithm); } return new SecretKeySpec(engineGenerateSecret(), algorithm); } diff -Nru openjdk-21-21.0.12.1+1/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAParameters.java openjdk-21-21.0.13+9/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAParameters.java --- openjdk-21-21.0.12.1+1/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAParameters.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAParameters.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ package sun.security.ec.ed; import sun.security.ec.ParametersMap; -import sun.security.provider.SHAKE256; +import sun.security.provider.SHA3.SHAKE256; import sun.security.util.ObjectIdentifier; import sun.security.util.KnownOIDs; import sun.security.util.math.*; diff -Nru openjdk-21-21.0.12.1+1/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp openjdk-21-21.0.13+9/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp --- openjdk-21-21.0.12.1+1/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp 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 @@ -1364,7 +1364,7 @@ PROV_RSA_FULL, CRYPT_NEWKEYSET) == FALSE) { - ThrowException(env, KEY_EXCEPTION, GetLastError()); + ThrowExceptionWithMessageAndErrcode(env, KEY_EXCEPTION, "CryptAcquireContext failure", GetLastError()); __leave; } } @@ -1376,7 +1376,7 @@ dwFlags, &hKeyPair) == FALSE) { - ThrowException(env, KEY_EXCEPTION, GetLastError()); + ThrowExceptionWithMessageAndErrcode(env, KEY_EXCEPTION, "CryptGenKey failure", GetLastError()); __leave; } diff -Nru openjdk-21-21.0.12.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java openjdk-21-21.0.13+9/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java --- openjdk-21-21.0.12.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java openjdk-21-21.0.13+9/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java --- openjdk-21-21.0.12.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java openjdk-21-21.0.13+9/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java --- openjdk-21-21.0.12.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -74,6 +74,7 @@ // the value of the TCP_NODELAY socket-level option private static boolean noDelay; + private static boolean hostValidationDisabled; static { java.security.AccessController.doPrivileged( @@ -136,6 +137,7 @@ debug = Boolean.getBoolean("sun.net.httpserver.debug"); noDelay = Boolean.getBoolean("sun.net.httpserver.nodelay"); + hostValidationDisabled = Boolean.getBoolean("sun.net.httpserver.disableHostValidation"); return null; } @@ -260,4 +262,8 @@ static boolean noDelay() { return noDelay; } + + static boolean isHostValidationDisabled() { + return hostValidationDisabled; + } } diff -Nru openjdk-21-21.0.12.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java openjdk-21-21.0.13+9/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java --- openjdk-21-21.0.12.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java 2026-10-19 12:10:20.000000000 +0000 @@ -44,6 +44,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; @@ -110,6 +111,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 @@ -741,7 +743,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 */ @@ -784,7 +795,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)) { @@ -834,6 +852,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-21-21.0.12.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java openjdk-21-21.0.13+9/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java --- openjdk-21-21.0.12.1+1/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java 2026-10-19 12:10:20.000000000 +0000 @@ -229,7 +229,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-21-21.0.12.1+1/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js openjdk-21-21.0.13+9/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js --- openjdk-21-21.0.12.1+1/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js 2026-10-19 12:10:20.000000000 +0000 @@ -35,7 +35,7 @@ if (redirect.is(":checked")) { href += "&r=1"; } - searchLink.html(href); + searchLink.text(href); copy[0].onmouseenter(); } function copyLink(e) { @@ -70,11 +70,11 @@ var feelingLucky = false; 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 = { @@ -99,7 +99,7 @@ }, 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; @@ -217,13 +217,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); doSearch({ term: term, maxResults: 1200 }, renderResults); } } @@ -253,7 +253,7 @@ } }); reset.click(function() { - notify.html(messages.enterTerm); + notify.text(messages.enterTerm); resultSection.hide(); activeTab = ""; fixedTab = false; @@ -278,7 +278,7 @@ if (input.val()) { doPageSearch(); } else { - notify.html(messages.enterTerm); + notify.text(messages.enterTerm); } input.select().focus(); }); \ No newline at end of file diff -Nru openjdk-21-21.0.12.1+1/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js openjdk-21-21.0.13+9/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js --- openjdk-21-21.0.12.1+1/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js 2026-10-19 12:10:20.000000000 +0000 @@ -216,13 +216,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-21-21.0.12.1+1/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c openjdk-21-21.0.13+9/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c --- openjdk-21-21.0.12.1+1/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -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-21-21.0.12.1+1/src/jdk.jpackage/linux/native/applauncher/ExecCommand.c openjdk-21-21.0.13+9/src/jdk.jpackage/linux/native/applauncher/ExecCommand.c --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/linux/native/applauncher/ExecCommand.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jpackage/linux/native/applauncher/ExecCommand.h openjdk-21-21.0.13+9/src/jdk.jpackage/linux/native/applauncher/ExecCommand.h --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/linux/native/applauncher/ExecCommand.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxLauncher.c openjdk-21-21.0.13+9/src/jdk.jpackage/linux/native/applauncher/LinuxLauncher.c --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxLauncher.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c openjdk-21-21.0.13+9/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.h openjdk-21-21.0.13+9/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.h --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.h 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jpackage/linux/native/libapplauncher/Executor.cpp openjdk-21-21.0.13+9/src/jdk.jpackage/linux/native/libapplauncher/Executor.cpp --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/linux/native/libapplauncher/Executor.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jpackage/linux/native/libapplauncher/Executor.h openjdk-21-21.0.13+9/src/jdk.jpackage/linux/native/libapplauncher/Executor.h --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/linux/native/libapplauncher/Executor.h 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jpackage/linux/native/libapplauncher/LinuxLauncherLib.cpp openjdk-21-21.0.13+9/src/jdk.jpackage/linux/native/libapplauncher/LinuxLauncherLib.cpp --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/linux/native/libapplauncher/LinuxLauncherLib.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -47,11 +47,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")); @@ -102,12 +107,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 @@ -135,10 +140,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-21-21.0.12.1+1/src/jdk.jpackage/linux/native/libapplauncher/Package.cpp openjdk-21-21.0.13+9/src/jdk.jpackage/linux/native/libapplauncher/Package.cpp --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/linux/native/libapplauncher/Package.cpp 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jpackage/linux/native/libapplauncher/Package.h openjdk-21-21.0.13+9/src/jdk.jpackage/linux/native/libapplauncher/Package.h --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/linux/native/libapplauncher/Package.h 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jpackage/share/native/applauncher/JvmLauncher.h openjdk-21-21.0.13+9/src/jdk.jpackage/share/native/applauncher/JvmLauncher.h --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/share/native/applauncher/JvmLauncher.h 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jpackage/share/native/applauncher/JvmLauncherLib.c openjdk-21-21.0.13+9/src/jdk.jpackage/share/native/applauncher/JvmLauncherLib.c --- openjdk-21-21.0.12.1+1/src/jdk.jpackage/share/native/applauncher/JvmLauncherLib.c 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java openjdk-21-21.0.13+9/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java --- openjdk-21-21.0.12.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -32,12 +32,10 @@ import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; -import java.util.ArrayList; import java.util.Collections; 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,7 +46,11 @@ import com.sun.jdi.ThreadReference; import com.sun.jdi.VMDisconnectedException; import com.sun.jdi.VirtualMachine; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Base64; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; import jdk.jshell.JShellConsole; import jdk.jshell.spi.ExecutionControl; @@ -96,6 +98,7 @@ */ static ExecutionControl create(ExecutionEnv env, String remoteAgent, boolean isLaunch, String host, int timeout) throws IOException { + Process processToStop = null; try (final ServerSocket listener = new ServerSocket(0, 1, InetAddress.getLoopbackAddress())) { // timeout on I/O-socket listener.setSoTimeout(timeout); @@ -109,17 +112,32 @@ .toList(); // Set-up the JDI connection - JdiInitiator jdii = new JdiInitiator(port, + JdiInitiator jdii = new JdiInitiator(-1, augmentedremoteVMOptions, remoteAgent, isLaunch, host, timeout, Collections.emptyMap()); VirtualMachine vm = jdii.vm(); - Process process = jdii.process(); + Process process = processToStop = jdii.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 @@ -127,6 +145,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()); @@ -141,10 +172,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(); + } +} } /** @@ -156,7 +194,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; @@ -164,8 +202,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(); + }); } /** diff -Nru openjdk-21-21.0.12.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java openjdk-21-21.0.13+9/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java --- openjdk-21-21.0.12.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -175,6 +175,7 @@ ProcessBuilder pb = new ProcessBuilder(args); pb.redirectError(crashErrorFile); pb.redirectOutput(crashOutputFile); + pb.redirectInput(ProcessBuilder.Redirect.PIPE); process = pb.start(); // Accept the connection from the remote agent diff -Nru openjdk-21-21.0.12.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java openjdk-21-21.0.13+9/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java --- openjdk-21-21.0.12.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java openjdk-21-21.0.13+9/src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java --- openjdk-21-21.0.12.1+1/src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java openjdk-21-21.0.13+9/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java --- openjdk-21-21.0.12.1+1/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -147,10 +147,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-21-21.0.12.1+1/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java openjdk-21-21.0.13+9/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java --- openjdk-21-21.0.12.1+1/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java openjdk-21-21.0.13+9/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java --- openjdk-21-21.0.12.1+1/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 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 @@ -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; @@ -199,9 +210,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"; @@ -380,7 +390,7 @@ */ public boolean commit() throws LoginException { - if (succeeded == false) { + if (!succeeded) { return false; } else { if (subject.isReadOnly()) { @@ -388,11 +398,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 @@ -435,9 +445,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; @@ -509,34 +519,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(); @@ -558,14 +559,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] " + @@ -576,7 +580,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 @@ -591,27 +595,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)); @@ -620,13 +633,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: " + @@ -640,17 +659,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-21-21.0.12.1+1/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java openjdk-21-21.0.13+9/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java --- openjdk-21-21.0.12.1+1/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2023, 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; @@ -1202,7 +1205,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) @@ -1224,23 +1227,34 @@ close(); } - // Reads len bytes of data from the specified offset into buf. - // Returns the total number of bytes read. - // Each/every byte read from here (except the cen, which is mapped). - final long readFullyAt(byte[] buf, int off, long len, long pos) - throws IOException - { + /** + * Reads len bytes of data at the given file position into the given byte array + * starting at the given array offset. The method blocks until len bytes have been + * read, end of stream is detected, or an exception is thrown. Returns the total + * number of bytes read. + */ + final long readNBytesAt(byte[] buf, int off, long len, long pos) throws IOException { ByteBuffer bb = ByteBuffer.wrap(buf); bb.position(off); bb.limit((int)(off + len)); - return readFullyAt(bb, pos); + + long totalRead = 0; + while (totalRead < len) { + int n = readAt(bb, pos); + if (n < 0) { + break; + } + pos += n; + totalRead +=n; + } + return totalRead; } - private long readFullyAt(ByteBuffer bb, long pos) throws IOException { - if (ch instanceof FileChannel fch) { - return fch.read(bb, pos); + private int readAt(ByteBuffer bb, long pos) throws IOException { + if (ch instanceof FileChannel fc) { + return fc.read(bb, pos); } else { - synchronized(ch) { + synchronized (ch) { return ch.position(pos).read(bb); } } @@ -1264,7 +1278,7 @@ Arrays.fill(buf, 0, off, (byte)0); } int len = buf.length - off; - if (readFullyAt(buf, off, len, pos + off) != len) + if (readNBytesAt(buf, off, len, pos + off) != len) throw new ZipException("zip END header not found"); // Now scan the block backwards for END header signature @@ -1286,14 +1300,14 @@ // try if there is zip64 end; byte[] loc64 = new byte[ZIP64_LOCHDR]; if (end.endpos < ZIP64_LOCHDR || - readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR) + readNBytesAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR) != loc64.length || !locator64SigAt(loc64, 0)) { return end; } long end64pos = ZIP64_LOCOFF(loc64); byte[] end64buf = new byte[ZIP64_ENDHDR]; - if (readFullyAt(end64buf, 0, end64buf.length, end64pos) + if (readNBytesAt(end64buf, 0, end64buf.length, end64pos) != end64buf.length || !end64SigAt(end64buf, 0)) { return end; @@ -1311,7 +1325,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; } @@ -1545,25 +1559,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 (readFullyAt(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)"); @@ -1595,7 +1620,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(); @@ -1621,6 +1646,10 @@ } } + private static void zerror(String msg) throws ZipException { + throw new ZipException(msg); + } + private final void checkEncoding( byte[] a) throws ZipException { try { zc.toString(a); @@ -1706,7 +1735,7 @@ // 'name' field of the loc. if this byte is '/', which means the original // entry has an absolute path in original zip/jar file, the e.writeLOC() // is used to output the loc, in which the leading "/" will be removed - if (readFullyAt(buf, 0, LOCHDR + 1 , locoff) != LOCHDR + 1) + if (readNBytesAt(buf, 0, LOCHDR + 1 , locoff) != LOCHDR + 1) throw new ZipException("loc: reading failed"); if (updateHeader || LOCNAM(buf) > 0 && buf[LOCHDR] == '/') { @@ -1723,7 +1752,7 @@ } int n; while (size > 0 && - (n = (int)readFullyAt(buf, 0, buf.length, locoff)) != -1) + (n = (int)readNBytesAt(buf, 0, buf.length, locoff)) != -1) { if (size < n) n = (int)size; @@ -2338,7 +2367,7 @@ ByteBuffer bb = ByteBuffer.wrap(b); bb.position(off); bb.limit(off + len); - long n = readFullyAt(bb, pos); + long n = readAt(bb, pos); if (n > 0) { pos += n; rem -= n; @@ -2383,7 +2412,7 @@ if (pos <= 0) { pos = -pos + locpos; byte[] buf = new byte[LOCHDR]; - if (readFullyAt(buf, 0, buf.length, pos) != LOCHDR) { + if (readNBytesAt(buf, 0, buf.length, pos) != LOCHDR) { throw new ZipException("invalid loc " + pos + " for entry reading"); } pos += LOCHDR + LOCNAM(buf) + LOCEXT(buf); @@ -2455,7 +2484,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 @@ -2478,7 +2507,7 @@ xoff = ZIP64_MINVAL; hasZip64 = true; } - int count = centot; + int count = Math.toIntExact(centot); if (count >= ZIP64_MINVAL32) { count = ZIP64_MINVAL32; hasZip64 = true; @@ -3224,7 +3253,7 @@ */ private void readLocEXTT(ZipFileSystem zipfs) throws IOException { byte[] buf = new byte[LOCHDR]; - if (zipfs.readFullyAt(buf, 0, buf.length , locoff) + if (zipfs.readNBytesAt(buf, 0, buf.length , locoff) != buf.length) throw new ZipException("loc: reading failed"); if (!locSigAt(buf, 0)) @@ -3235,7 +3264,7 @@ return; int locNlen = LOCNAM(buf); buf = new byte[locElen]; - if (zipfs.readFullyAt(buf, 0, buf.length , locoff + LOCHDR + locNlen) + if (zipfs.readNBytesAt(buf, 0, buf.length , locoff + LOCHDR + locNlen) != buf.length) throw new ZipException("loc extra: reading failed"); int locPos = 0; diff -Nru openjdk-21-21.0.12.1+1/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipInfo.java openjdk-21-21.0.13+9/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipInfo.java --- openjdk-21-21.0.12.1+1/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipInfo.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipInfo.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,12 +65,12 @@ // loc.extra is bigger than the cen.extra, try to avoid to read // twice long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR; - if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len) + if (zfs.readNBytesAt(buf, 0, len, locoff(cen, pos)) != len) throw new ZipException("read loc header failed"); if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) { // have to read the second time; len = LOCHDR + LOCNAM(buf) + LOCEXT(buf); - if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len) + if (zfs.readNBytesAt(buf, 0, len, locoff(cen, pos)) != len) throw new ZipException("read loc header failed"); } printLOC(buf); diff -Nru openjdk-21-21.0.12.1+1/test/docs/TEST.ROOT openjdk-21-21.0.13+9/test/docs/TEST.ROOT --- openjdk-21-21.0.12.1+1/test/docs/TEST.ROOT 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/docs/TEST.ROOT 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 @@ -38,7 +38,7 @@ groups=TEST.groups # Minimum jtreg version -requiredVersion=7.4+1 +requiredVersion=8.2.1+1 # Use new module options useNewOptions=true diff -Nru openjdk-21-21.0.12.1+1/test/hotspot/gtest/aarch64/aarch64-asmtest.py openjdk-21-21.0.13+9/test/hotspot/gtest/aarch64/aarch64-asmtest.py --- openjdk-21-21.0.12.1+1/test/hotspot/gtest/aarch64/aarch64-asmtest.py 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/gtest/aarch64/aarch64-asmtest.py 2026-10-19 12:10:20.000000000 +0000 @@ -1833,6 +1833,11 @@ ["sminp", "sminp", "8B"], ["sminp", "sminp", "16B"], ["sminp", "sminp", "4H"], ["sminp", "sminp", "8H"], ["sminp", "sminp", "2S"], ["sminp", "sminp", "4S"], + ["sqdmulh", "sqdmulh", "4H"], ["sqdmulh", "sqdmulh", "8H"], + ["sqdmulh", "sqdmulh", "2S"], ["sqdmulh", "sqdmulh", "4S"], + ["shsubv", "shsub", "8B"], ["shsubv", "shsub", "16B"], + ["shsubv", "shsub", "4H"], ["shsubv", "shsub", "8H"], + ["shsubv", "shsub", "2S"], ["shsubv", "shsub", "4S"], ["fmin", "fmin", "2S"], ["fmin", "fmin", "4S"], ["fmin", "fmin", "2D"], ["facgt", "facgt", "2S"], ["facgt", "facgt", "4S"], diff -Nru openjdk-21-21.0.12.1+1/test/hotspot/gtest/aarch64/asmtest.out.h openjdk-21-21.0.13+9/test/hotspot/gtest/aarch64/asmtest.out.h --- openjdk-21-21.0.12.1+1/test/hotspot/gtest/aarch64/asmtest.out.h 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/gtest/aarch64/asmtest.out.h 2026-10-19 12:10:20.000000000 +0000 @@ -745,93 +745,103 @@ __ sminp(v2, __ T8H, v3, v4); // sminp v2.8H, v3.8H, v4.8H __ sminp(v0, __ T2S, v1, v2); // sminp v0.2S, v1.2S, v2.2S __ sminp(v9, __ T4S, v10, v11); // sminp v9.4S, v10.4S, v11.4S - __ fmin(v24, __ T2S, v25, v26); // fmin v24.2S, v25.2S, v26.2S - __ fmin(v26, __ T4S, v27, v28); // fmin v26.4S, v27.4S, v28.4S - __ fmin(v16, __ T2D, v17, v18); // fmin v16.2D, v17.2D, v18.2D - __ facgt(v30, __ T2S, v31, v0); // facgt v30.2S, v31.2S, v0.2S - __ facgt(v3, __ T4S, v4, v5); // facgt v3.4S, v4.4S, v5.4S - __ facgt(v10, __ T2D, v11, v12); // facgt v10.2D, v11.2D, v12.2D + __ sqdmulh(v24, __ T4H, v25, v26); // sqdmulh v24.4H, v25.4H, v26.4H + __ sqdmulh(v26, __ T8H, v27, v28); // sqdmulh v26.8H, v27.8H, v28.8H + __ sqdmulh(v16, __ T2S, v17, v18); // sqdmulh v16.2S, v17.2S, v18.2S + __ sqdmulh(v30, __ T4S, v31, v0); // sqdmulh v30.4S, v31.4S, v0.4S + __ shsubv(v3, __ T8B, v4, v5); // shsub v3.8B, v4.8B, v5.8B + __ shsubv(v10, __ T16B, v11, v12); // shsub v10.16B, v11.16B, v12.16B + __ shsubv(v23, __ T4H, v24, v25); // shsub v23.4H, v24.4H, v25.4H + __ shsubv(v10, __ T8H, v11, v12); // shsub v10.8H, v11.8H, v12.8H + __ shsubv(v4, __ T2S, v5, v6); // shsub v4.2S, v5.2S, v6.2S + __ shsubv(v18, __ T4S, v19, v20); // shsub v18.4S, v19.4S, v20.4S + __ fmin(v2, __ T2S, v3, v4); // fmin v2.2S, v3.2S, v4.2S + __ fmin(v11, __ T4S, v12, v13); // fmin v11.4S, v12.4S, v13.4S + __ fmin(v8, __ T2D, v9, v10); // fmin v8.2D, v9.2D, v10.2D + __ facgt(v10, __ T2S, v11, v12); // facgt v10.2S, v11.2S, v12.2S + __ facgt(v15, __ T4S, v16, v17); // facgt v15.4S, v16.4S, v17.4S + __ facgt(v17, __ T2D, v18, v19); // facgt v17.2D, v18.2D, v19.2D // VectorScalarNEONInstruction - __ fmlavs(v5, __ T2S, v6, v7, 1); // fmla v5.2S, v6.2S, v7.S[1] - __ mulvs(v9, __ T4S, v10, v11, 0); // mul v9.4S, v10.4S, v11.S[0] - __ fmlavs(v5, __ T2D, v6, v7, 0); // fmla v5.2D, v6.2D, v7.D[0] - __ fmlsvs(v5, __ T2S, v6, v7, 0); // fmls v5.2S, v6.2S, v7.S[0] - __ mulvs(v8, __ T4S, v9, v10, 1); // mul v8.4S, v9.4S, v10.S[1] - __ fmlsvs(v5, __ T2D, v6, v7, 0); // fmls v5.2D, v6.2D, v7.D[0] - __ fmulxvs(v6, __ T2S, v7, v8, 0); // fmulx v6.2S, v7.2S, v8.S[0] + __ fmlavs(v5, __ T2S, v6, v7, 0); // fmla v5.2S, v6.2S, v7.S[0] __ mulvs(v6, __ T4S, v7, v8, 1); // mul v6.4S, v7.4S, v8.S[1] - __ fmulxvs(v3, __ T2D, v4, v5, 0); // fmulx v3.2D, v4.2D, v5.D[0] - __ mulvs(v13, __ T4H, v14, v15, 2); // mul v13.4H, v14.4H, v15.H[2] - __ mulvs(v2, __ T8H, v3, v4, 4); // mul v2.8H, v3.8H, v4.H[4] - __ mulvs(v2, __ T2S, v3, v4, 0); // mul v2.2S, v3.2S, v4.S[0] + __ fmlavs(v6, __ T2D, v7, v8, 0); // fmla v6.2D, v7.2D, v8.D[0] + __ fmlsvs(v3, __ T2S, v4, v5, 0); // fmls v3.2S, v4.2S, v5.S[0] + __ mulvs(v13, __ T4S, v14, v15, 2); // mul v13.4S, v14.4S, v15.S[2] + __ fmlsvs(v2, __ T2D, v3, v4, 1); // fmls v2.2D, v3.2D, v4.D[1] + __ fmulxvs(v2, __ T2S, v3, v4, 0); // fmulx v2.2S, v3.2S, v4.S[0] __ mulvs(v9, __ T4S, v10, v11, 1); // mul v9.4S, v10.4S, v11.S[1] + __ fmulxvs(v8, __ T2D, v9, v10, 1); // fmulx v8.2D, v9.2D, v10.D[1] + __ mulvs(v5, __ T4H, v6, v7, 2); // mul v5.4H, v6.4H, v7.H[2] + __ mulvs(v11, __ T8H, v12, v13, 5); // mul v11.8H, v12.8H, v13.H[5] + __ mulvs(v13, __ T2S, v14, v15, 0); // mul v13.2S, v14.2S, v15.S[0] + __ mulvs(v14, __ T4S, v15, v16, 2); // mul v14.4S, v15.4S, v16.S[2] // NEONVectorCompare - __ cm(Assembler::GT, v21, __ T8B, v22, v23); // cmgt v21.8B, v22.8B, v23.8B - __ cm(Assembler::GT, v16, __ T16B, v17, v18); // cmgt v16.16B, v17.16B, v18.16B - __ cm(Assembler::GT, v18, __ T4H, v19, v20); // cmgt v18.4H, v19.4H, v20.4H - __ cm(Assembler::GT, v11, __ T8H, v12, v13); // cmgt v11.8H, v12.8H, v13.8H - __ cm(Assembler::GT, v21, __ T2S, v22, v23); // cmgt v21.2S, v22.2S, v23.2S - __ cm(Assembler::GT, v23, __ T4S, v24, v25); // cmgt v23.4S, v24.4S, v25.4S - __ cm(Assembler::GT, v12, __ T2D, v13, v14); // cmgt v12.2D, v13.2D, v14.2D - __ cm(Assembler::GE, v26, __ T8B, v27, v28); // cmge v26.8B, v27.8B, v28.8B - __ cm(Assembler::GE, v23, __ T16B, v24, v25); // cmge v23.16B, v24.16B, v25.16B - __ cm(Assembler::GE, v28, __ T4H, v29, v30); // cmge v28.4H, v29.4H, v30.4H - __ cm(Assembler::GE, v14, __ T8H, v15, v16); // cmge v14.8H, v15.8H, v16.8H - __ cm(Assembler::GE, v11, __ T2S, v12, v13); // cmge v11.2S, v12.2S, v13.2S - __ cm(Assembler::GE, v24, __ T4S, v25, v26); // cmge v24.4S, v25.4S, v26.4S - __ cm(Assembler::GE, v1, __ T2D, v2, v3); // cmge v1.2D, v2.2D, v3.2D - __ cm(Assembler::EQ, v12, __ T8B, v13, v14); // cmeq v12.8B, v13.8B, v14.8B - __ cm(Assembler::EQ, v31, __ T16B, v0, v1); // cmeq v31.16B, v0.16B, v1.16B - __ cm(Assembler::EQ, v10, __ T4H, v11, v12); // cmeq v10.4H, v11.4H, v12.4H - __ cm(Assembler::EQ, v16, __ T8H, v17, v18); // cmeq v16.8H, v17.8H, v18.8H - __ cm(Assembler::EQ, v7, __ T2S, v8, v9); // cmeq v7.2S, v8.2S, v9.2S - __ cm(Assembler::EQ, v2, __ T4S, v3, v4); // cmeq v2.4S, v3.4S, v4.4S - __ cm(Assembler::EQ, v3, __ T2D, v4, v5); // cmeq v3.2D, v4.2D, v5.2D - __ cm(Assembler::HI, v13, __ T8B, v14, v15); // cmhi v13.8B, v14.8B, v15.8B - __ cm(Assembler::HI, v19, __ T16B, v20, v21); // cmhi v19.16B, v20.16B, v21.16B - __ cm(Assembler::HI, v17, __ T4H, v18, v19); // cmhi v17.4H, v18.4H, v19.4H - __ cm(Assembler::HI, v16, __ T8H, v17, v18); // cmhi v16.8H, v17.8H, v18.8H - __ cm(Assembler::HI, v3, __ T2S, v4, v5); // cmhi v3.2S, v4.2S, v5.2S - __ cm(Assembler::HI, v1, __ T4S, v2, v3); // cmhi v1.4S, v2.4S, v3.4S - __ cm(Assembler::HI, v11, __ T2D, v12, v13); // cmhi v11.2D, v12.2D, v13.2D - __ cm(Assembler::HS, v30, __ T8B, v31, v0); // cmhs v30.8B, v31.8B, v0.8B - __ cm(Assembler::HS, v5, __ T16B, v6, v7); // cmhs v5.16B, v6.16B, v7.16B - __ cm(Assembler::HS, v8, __ T4H, v9, v10); // cmhs v8.4H, v9.4H, v10.4H - __ cm(Assembler::HS, v15, __ T8H, v16, v17); // cmhs v15.8H, v16.8H, v17.8H - __ cm(Assembler::HS, v29, __ T2S, v30, v31); // cmhs v29.2S, v30.2S, v31.2S - __ cm(Assembler::HS, v30, __ T4S, v31, v0); // cmhs v30.4S, v31.4S, v0.4S - __ cm(Assembler::HS, v0, __ T2D, v1, v2); // cmhs v0.2D, v1.2D, v2.2D - __ fcm(Assembler::EQ, v20, __ T2S, v21, v22); // fcmeq v20.2S, v21.2S, v22.2S - __ fcm(Assembler::EQ, v7, __ T4S, v8, v9); // fcmeq v7.4S, v8.4S, v9.4S - __ fcm(Assembler::EQ, v20, __ T2D, v21, v22); // fcmeq v20.2D, v21.2D, v22.2D - __ fcm(Assembler::GT, v23, __ T2S, v24, v25); // fcmgt v23.2S, v24.2S, v25.2S - __ fcm(Assembler::GT, v28, __ T4S, v29, v30); // fcmgt v28.4S, v29.4S, v30.4S - __ fcm(Assembler::GT, v21, __ T2D, v22, v23); // fcmgt v21.2D, v22.2D, v23.2D - __ fcm(Assembler::GE, v27, __ T2S, v28, v29); // fcmge v27.2S, v28.2S, v29.2S - __ fcm(Assembler::GE, v25, __ T4S, v26, v27); // fcmge v25.4S, v26.4S, v27.4S - __ fcm(Assembler::GE, v5, __ T2D, v6, v7); // fcmge v5.2D, v6.2D, v7.2D + __ cm(Assembler::GT, v14, __ T8B, v15, v16); // cmgt v14.8B, v15.8B, v16.8B + __ cm(Assembler::GT, v11, __ T16B, v12, v13); // cmgt v11.16B, v12.16B, v13.16B + __ cm(Assembler::GT, v24, __ T4H, v25, v26); // cmgt v24.4H, v25.4H, v26.4H + __ cm(Assembler::GT, v1, __ T8H, v2, v3); // cmgt v1.8H, v2.8H, v3.8H + __ cm(Assembler::GT, v12, __ T2S, v13, v14); // cmgt v12.2S, v13.2S, v14.2S + __ cm(Assembler::GT, v31, __ T4S, v0, v1); // cmgt v31.4S, v0.4S, v1.4S + __ cm(Assembler::GT, v10, __ T2D, v11, v12); // cmgt v10.2D, v11.2D, v12.2D + __ cm(Assembler::GE, v16, __ T8B, v17, v18); // cmge v16.8B, v17.8B, v18.8B + __ cm(Assembler::GE, v7, __ T16B, v8, v9); // cmge v7.16B, v8.16B, v9.16B + __ cm(Assembler::GE, v2, __ T4H, v3, v4); // cmge v2.4H, v3.4H, v4.4H + __ cm(Assembler::GE, v3, __ T8H, v4, v5); // cmge v3.8H, v4.8H, v5.8H + __ cm(Assembler::GE, v13, __ T2S, v14, v15); // cmge v13.2S, v14.2S, v15.2S + __ cm(Assembler::GE, v19, __ T4S, v20, v21); // cmge v19.4S, v20.4S, v21.4S + __ cm(Assembler::GE, v17, __ T2D, v18, v19); // cmge v17.2D, v18.2D, v19.2D + __ cm(Assembler::EQ, v16, __ T8B, v17, v18); // cmeq v16.8B, v17.8B, v18.8B + __ cm(Assembler::EQ, v3, __ T16B, v4, v5); // cmeq v3.16B, v4.16B, v5.16B + __ cm(Assembler::EQ, v1, __ T4H, v2, v3); // cmeq v1.4H, v2.4H, v3.4H + __ cm(Assembler::EQ, v11, __ T8H, v12, v13); // cmeq v11.8H, v12.8H, v13.8H + __ cm(Assembler::EQ, v30, __ T2S, v31, v0); // cmeq v30.2S, v31.2S, v0.2S + __ cm(Assembler::EQ, v5, __ T4S, v6, v7); // cmeq v5.4S, v6.4S, v7.4S + __ cm(Assembler::EQ, v8, __ T2D, v9, v10); // cmeq v8.2D, v9.2D, v10.2D + __ cm(Assembler::HI, v15, __ T8B, v16, v17); // cmhi v15.8B, v16.8B, v17.8B + __ cm(Assembler::HI, v29, __ T16B, v30, v31); // cmhi v29.16B, v30.16B, v31.16B + __ cm(Assembler::HI, v30, __ T4H, v31, v0); // cmhi v30.4H, v31.4H, v0.4H + __ cm(Assembler::HI, v0, __ T8H, v1, v2); // cmhi v0.8H, v1.8H, v2.8H + __ cm(Assembler::HI, v20, __ T2S, v21, v22); // cmhi v20.2S, v21.2S, v22.2S + __ cm(Assembler::HI, v7, __ T4S, v8, v9); // cmhi v7.4S, v8.4S, v9.4S + __ cm(Assembler::HI, v20, __ T2D, v21, v22); // cmhi v20.2D, v21.2D, v22.2D + __ cm(Assembler::HS, v23, __ T8B, v24, v25); // cmhs v23.8B, v24.8B, v25.8B + __ cm(Assembler::HS, v28, __ T16B, v29, v30); // cmhs v28.16B, v29.16B, v30.16B + __ cm(Assembler::HS, v21, __ T4H, v22, v23); // cmhs v21.4H, v22.4H, v23.4H + __ cm(Assembler::HS, v27, __ T8H, v28, v29); // cmhs v27.8H, v28.8H, v29.8H + __ cm(Assembler::HS, v25, __ T2S, v26, v27); // cmhs v25.2S, v26.2S, v27.2S + __ cm(Assembler::HS, v5, __ T4S, v6, v7); // cmhs v5.4S, v6.4S, v7.4S + __ cm(Assembler::HS, v1, __ T2D, v2, v3); // cmhs v1.2D, v2.2D, v3.2D + __ fcm(Assembler::EQ, v23, __ T2S, v24, v25); // fcmeq v23.2S, v24.2S, v25.2S + __ fcm(Assembler::EQ, v16, __ T4S, v17, v18); // fcmeq v16.4S, v17.4S, v18.4S + __ fcm(Assembler::EQ, v31, __ T2D, v0, v1); // fcmeq v31.2D, v0.2D, v1.2D + __ fcm(Assembler::GT, v5, __ T2S, v6, v7); // fcmgt v5.2S, v6.2S, v7.2S + __ fcm(Assembler::GT, v12, __ T4S, v13, v14); // fcmgt v12.4S, v13.4S, v14.4S + __ fcm(Assembler::GT, v9, __ T2D, v10, v11); // fcmgt v9.2D, v10.2D, v11.2D + __ fcm(Assembler::GE, v28, __ T2S, v29, v30); // fcmge v28.2S, v29.2S, v30.2S + __ fcm(Assembler::GE, v15, __ T4S, v16, v17); // fcmge v15.4S, v16.4S, v17.4S + __ fcm(Assembler::GE, v29, __ T2D, v30, v31); // fcmge v29.2D, v30.2D, v31.2D // SVEComparisonWithZero - __ sve_fcm(Assembler::EQ, p0, __ D, p7, z23, 0.0); // fcmeq p0.d, p7/z, z23.d, #0.0 - __ sve_fcm(Assembler::GT, p2, __ S, p7, z12, 0.0); // fcmgt p2.s, p7/z, z12.s, #0.0 - __ sve_fcm(Assembler::GE, p7, __ D, p7, z29, 0.0); // fcmge p7.d, p7/z, z29.d, #0.0 - __ sve_fcm(Assembler::LT, p9, __ S, p3, z31, 0.0); // fcmlt p9.s, p3/z, z31.s, #0.0 - __ sve_fcm(Assembler::LE, p9, __ D, p6, z31, 0.0); // fcmle p9.d, p6/z, z31.d, #0.0 - __ sve_fcm(Assembler::NE, p10, __ S, p2, z16, 0.0); // fcmne p10.s, p2/z, z16.s, #0.0 + __ sve_fcm(Assembler::EQ, p11, __ D, p7, z31, 0.0); // fcmeq p11.d, p7/z, z31.d, #0.0 + __ sve_fcm(Assembler::GT, p2, __ D, p7, z14, 0.0); // fcmgt p2.d, p7/z, z14.d, #0.0 + __ sve_fcm(Assembler::GE, p9, __ D, p4, z27, 0.0); // fcmge p9.d, p4/z, z27.d, #0.0 + __ sve_fcm(Assembler::LT, p6, __ S, p1, z11, 0.0); // fcmlt p6.s, p1/z, z11.s, #0.0 + __ sve_fcm(Assembler::LE, p15, __ D, p7, z17, 0.0); // fcmle p15.d, p7/z, z17.d, #0.0 + __ sve_fcm(Assembler::NE, p15, __ S, p5, z7, 0.0); // fcmne p15.s, p5/z, z7.s, #0.0 // SVEComparisonWithImm - __ sve_cmp(Assembler::EQ, p4, __ D, p4, z6, 11); // cmpeq p4.d, p4/z, z6.d, #11 - __ sve_cmp(Assembler::GT, p14, __ B, p2, z30, 4); // cmpgt p14.b, p2/z, z30.b, #4 - __ sve_cmp(Assembler::GE, p5, __ D, p4, z4, 1); // cmpge p5.d, p4/z, z4.d, #1 - __ sve_cmp(Assembler::LT, p11, __ D, p3, z3, 6); // cmplt p11.d, p3/z, z3.d, #6 - __ sve_cmp(Assembler::LE, p9, __ S, p0, z19, -1); // cmple p9.s, p0/z, z19.s, #-1 - __ sve_cmp(Assembler::NE, p3, __ S, p2, z12, -3); // cmpne p3.s, p2/z, z12.s, #-3 - __ sve_cmp(Assembler::HS, p11, __ D, p4, z1, 20); // cmphs p11.d, p4/z, z1.d, #20 - __ sve_cmp(Assembler::HI, p8, __ S, p5, z2, 53); // cmphi p8.s, p5/z, z2.s, #53 - __ sve_cmp(Assembler::LS, p5, __ D, p6, z21, 49); // cmpls p5.d, p6/z, z21.d, #49 - __ sve_cmp(Assembler::LO, p13, __ B, p7, z3, 97); // cmplo p13.b, p7/z, z3.b, #97 + __ sve_cmp(Assembler::EQ, p5, __ D, p4, z4, 1); // cmpeq p5.d, p4/z, z4.d, #1 + __ sve_cmp(Assembler::GT, p11, __ D, p3, z3, 6); // cmpgt p11.d, p3/z, z3.d, #6 + __ sve_cmp(Assembler::GE, p9, __ S, p0, z19, -1); // cmpge p9.s, p0/z, z19.s, #-1 + __ sve_cmp(Assembler::LT, p3, __ S, p2, z12, -3); // cmplt p3.s, p2/z, z12.s, #-3 + __ sve_cmp(Assembler::LE, p11, __ D, p4, z1, -11); // cmple p11.d, p4/z, z1.d, #-11 + __ sve_cmp(Assembler::NE, p8, __ S, p5, z2, -3); // cmpne p8.s, p5/z, z2.s, #-3 + __ sve_cmp(Assembler::HS, p5, __ D, p6, z21, 49); // cmphs p5.d, p6/z, z21.d, #49 + __ sve_cmp(Assembler::HI, p13, __ B, p7, z3, 97); // cmphi p13.b, p7/z, z3.b, #97 + __ sve_cmp(Assembler::LS, p9, __ H, p7, z17, 109); // cmpls p9.h, p7/z, z17.h, #109 + __ sve_cmp(Assembler::LO, p7, __ S, p5, z7, 127); // cmplo p7.s, p5/z, z7.s, #127 // SpecialCases __ ccmn(zr, zr, 3u, Assembler::LE); // ccmn xzr, xzr, #3, LE @@ -1086,229 +1096,229 @@ __ fmovd(v0, -1.0625); // fmov d0, #-1.0625 // LSEOp - __ swp(Assembler::xword, r19, r17, r9); // swp x19, x17, [x9] - __ ldadd(Assembler::xword, r28, r27, r15); // ldadd x28, x27, [x15] - __ ldbic(Assembler::xword, r7, r21, r23); // ldclr x7, x21, [x23] - __ ldeor(Assembler::xword, zr, r25, r2); // ldeor xzr, x25, [x2] - __ ldorr(Assembler::xword, zr, r27, r15); // ldset xzr, x27, [x15] - __ ldsmin(Assembler::xword, r10, r23, r19); // ldsmin x10, x23, [x19] - __ ldsmax(Assembler::xword, r3, r16, r0); // ldsmax x3, x16, [x0] - __ ldumin(Assembler::xword, r25, r26, r23); // ldumin x25, x26, [x23] - __ ldumax(Assembler::xword, r2, r16, r12); // ldumax x2, x16, [x12] + __ swp(Assembler::xword, r25, r2, sp); // swp x25, x2, [sp] + __ ldadd(Assembler::xword, r27, r16, r10); // ldadd x27, x16, [x10] + __ ldbic(Assembler::xword, r23, r19, r3); // ldclr x23, x19, [x3] + __ ldeor(Assembler::xword, r16, r0, r25); // ldeor x16, x0, [x25] + __ ldorr(Assembler::xword, r26, r23, r2); // ldset x26, x23, [x2] + __ ldsmin(Assembler::xword, r16, r12, r4); // ldsmin x16, x12, [x4] + __ ldsmax(Assembler::xword, r28, r30, r29); // ldsmax x28, x30, [x29] + __ ldumin(Assembler::xword, r16, r27, r6); // ldumin x16, x27, [x6] + __ ldumax(Assembler::xword, r9, r29, r15); // ldumax x9, x29, [x15] // LSEOp - __ swpa(Assembler::xword, r4, r28, r30); // swpa x4, x28, [x30] - __ ldadda(Assembler::xword, r29, r16, r27); // ldadda x29, x16, [x27] - __ ldbica(Assembler::xword, r6, r9, r29); // ldclra x6, x9, [x29] - __ ldeora(Assembler::xword, r16, r7, r4); // ldeora x16, x7, [x4] - __ ldorra(Assembler::xword, r7, r15, r9); // ldseta x7, x15, [x9] - __ ldsmina(Assembler::xword, r23, r8, r2); // ldsmina x23, x8, [x2] - __ ldsmaxa(Assembler::xword, r28, r21, sp); // ldsmaxa x28, x21, [sp] - __ ldumina(Assembler::xword, r5, r27, r0); // ldumina x5, x27, [x0] - __ ldumaxa(Assembler::xword, r17, r15, r4); // ldumaxa x17, x15, [x4] + __ swpa(Assembler::xword, r7, r4, r7); // swpa x7, x4, [x7] + __ ldadda(Assembler::xword, r15, r9, r23); // ldadda x15, x9, [x23] + __ ldbica(Assembler::xword, r8, r2, r28); // ldclra x8, x2, [x28] + __ ldeora(Assembler::xword, r21, zr, r5); // ldeora x21, xzr, [x5] + __ ldorra(Assembler::xword, r27, r0, r17); // ldseta x27, x0, [x17] + __ ldsmina(Assembler::xword, r15, r4, r26); // ldsmina x15, x4, [x26] + __ ldsmaxa(Assembler::xword, r8, r28, r22); // ldsmaxa x8, x28, [x22] + __ ldumina(Assembler::xword, r27, r27, r25); // ldumina x27, x27, [x25] + __ ldumaxa(Assembler::xword, r23, r0, r4); // ldumaxa x23, x0, [x4] // LSEOp - __ swpal(Assembler::xword, r26, r8, r28); // swpal x26, x8, [x28] - __ ldaddal(Assembler::xword, r22, r27, r27); // ldaddal x22, x27, [x27] - __ ldbical(Assembler::xword, r25, r23, r0); // ldclral x25, x23, [x0] - __ ldeoral(Assembler::xword, r4, r6, r15); // ldeoral x4, x6, [x15] - __ ldorral(Assembler::xword, r0, r4, r15); // ldsetal x0, x4, [x15] - __ ldsminal(Assembler::xword, r1, r10, r7); // ldsminal x1, x10, [x7] - __ ldsmaxal(Assembler::xword, r5, r10, r28); // ldsmaxal x5, x10, [x28] - __ lduminal(Assembler::xword, r7, r20, r23); // lduminal x7, x20, [x23] - __ ldumaxal(Assembler::xword, r21, r6, r11); // ldumaxal x21, x6, [x11] + __ swpal(Assembler::xword, r6, r16, r0); // swpal x6, x16, [x0] + __ ldaddal(Assembler::xword, r4, r15, r1); // ldaddal x4, x15, [x1] + __ ldbical(Assembler::xword, r10, r7, r5); // ldclral x10, x7, [x5] + __ ldeoral(Assembler::xword, r10, r28, r7); // ldeoral x10, x28, [x7] + __ ldorral(Assembler::xword, r20, r23, r21); // ldsetal x20, x23, [x21] + __ ldsminal(Assembler::xword, r6, r11, r8); // ldsminal x6, x11, [x8] + __ ldsmaxal(Assembler::xword, r17, zr, r6); // ldsmaxal x17, xzr, [x6] + __ lduminal(Assembler::xword, r17, r2, r12); // lduminal x17, x2, [x12] + __ ldumaxal(Assembler::xword, r30, r29, r3); // ldumaxal x30, x29, [x3] // LSEOp - __ swpl(Assembler::xword, r8, r17, sp); // swpl x8, x17, [sp] - __ ldaddl(Assembler::xword, r6, r17, r2); // ldaddl x6, x17, [x2] - __ ldbicl(Assembler::xword, r12, r30, r29); // ldclrl x12, x30, [x29] - __ ldeorl(Assembler::xword, r3, r27, r22); // ldeorl x3, x27, [x22] - __ ldorrl(Assembler::xword, r29, r14, r13); // ldsetl x29, x14, [x13] - __ ldsminl(Assembler::xword, r28, r17, r24); // ldsminl x28, x17, [x24] - __ ldsmaxl(Assembler::xword, r5, r2, r14); // ldsmaxl x5, x2, [x14] - __ lduminl(Assembler::xword, r10, r16, r11); // lduminl x10, x16, [x11] - __ ldumaxl(Assembler::xword, r27, r23, r12); // ldumaxl x27, x23, [x12] + __ swpl(Assembler::xword, r27, r22, r29); // swpl x27, x22, [x29] + __ ldaddl(Assembler::xword, r14, r13, r28); // ldaddl x14, x13, [x28] + __ ldbicl(Assembler::xword, r17, r24, r5); // ldclrl x17, x24, [x5] + __ ldeorl(Assembler::xword, r2, r14, r10); // ldeorl x2, x14, [x10] + __ ldorrl(Assembler::xword, r16, r11, r27); // ldsetl x16, x11, [x27] + __ ldsminl(Assembler::xword, r23, r12, r4); // ldsminl x23, x12, [x4] + __ ldsmaxl(Assembler::xword, r22, r17, r4); // ldsmaxl x22, x17, [x4] + __ lduminl(Assembler::xword, r1, r19, r16); // lduminl x1, x19, [x16] + __ ldumaxl(Assembler::xword, r16, r13, r14); // ldumaxl x16, x13, [x14] // LSEOp - __ swp(Assembler::word, r4, r22, r17); // swp w4, w22, [x17] - __ ldadd(Assembler::word, r4, r1, r19); // ldadd w4, w1, [x19] - __ ldbic(Assembler::word, r16, r16, r13); // ldclr w16, w16, [x13] - __ ldeor(Assembler::word, r14, r12, r2); // ldeor w14, w12, [x2] - __ ldorr(Assembler::word, r17, r3, r21); // ldset w17, w3, [x21] - __ ldsmin(Assembler::word, r23, r5, r6); // ldsmin w23, w5, [x6] - __ ldsmax(Assembler::word, r7, r19, r13); // ldsmax w7, w19, [x13] - __ ldumin(Assembler::word, r28, r17, r16); // ldumin w28, w17, [x16] - __ ldumax(Assembler::word, r6, r2, r29); // ldumax w6, w2, [x29] + __ swp(Assembler::word, r12, r2, r17); // swp w12, w2, [x17] + __ ldadd(Assembler::word, r3, r21, r23); // ldadd w3, w21, [x23] + __ ldbic(Assembler::word, r5, r6, r7); // ldclr w5, w6, [x7] + __ ldeor(Assembler::word, r19, r13, r28); // ldeor w19, w13, [x28] + __ ldorr(Assembler::word, r17, r16, r6); // ldset w17, w16, [x6] + __ ldsmin(Assembler::word, r2, r29, r3); // ldsmin w2, w29, [x3] + __ ldsmax(Assembler::word, r4, r6, r15); // ldsmax w4, w6, [x15] + __ ldumin(Assembler::word, r20, r13, r12); // ldumin w20, w13, [x12] + __ ldumax(Assembler::word, r20, r8, r25); // ldumax w20, w8, [x25] // LSEOp - __ swpa(Assembler::word, r3, r4, r6); // swpa w3, w4, [x6] - __ ldadda(Assembler::word, r16, r20, r13); // ldadda w16, w20, [x13] - __ ldbica(Assembler::word, r12, r20, r8); // ldclra w12, w20, [x8] - __ ldeora(Assembler::word, r25, r20, r19); // ldeora w25, w20, [x19] - __ ldorra(Assembler::word, r0, r11, r24); // ldseta w0, w11, [x24] - __ ldsmina(Assembler::word, r6, r20, sp); // ldsmina w6, w20, [sp] - __ ldsmaxa(Assembler::word, r14, r16, r6); // ldsmaxa w14, w16, [x6] - __ ldumina(Assembler::word, r0, r7, r15); // ldumina w0, w7, [x15] - __ ldumaxa(Assembler::word, r19, r26, r9); // ldumaxa w19, w26, [x9] + __ swpa(Assembler::word, r20, r19, r0); // swpa w20, w19, [x0] + __ ldadda(Assembler::word, r11, r24, r6); // ldadda w11, w24, [x6] + __ ldbica(Assembler::word, r20, zr, r14); // ldclra w20, wzr, [x14] + __ ldeora(Assembler::word, r16, r6, r0); // ldeora w16, w6, [x0] + __ ldorra(Assembler::word, r7, r15, r19); // ldseta w7, w15, [x19] + __ ldsmina(Assembler::word, r26, r9, r10); // ldsmina w26, w9, [x10] + __ ldsmaxa(Assembler::word, r23, r21, r22); // ldsmaxa w23, w21, [x22] + __ ldumina(Assembler::word, r28, r2, r3); // ldumina w28, w2, [x3] + __ ldumaxa(Assembler::word, r15, r19, r20); // ldumaxa w15, w19, [x20] // LSEOp - __ swpal(Assembler::word, r10, r23, r21); // swpal w10, w23, [x21] - __ ldaddal(Assembler::word, r22, r28, r2); // ldaddal w22, w28, [x2] - __ ldbical(Assembler::word, r3, r15, r19); // ldclral w3, w15, [x19] - __ ldeoral(Assembler::word, r20, r7, r4); // ldeoral w20, w7, [x4] - __ ldorral(Assembler::word, r29, r7, r0); // ldsetal w29, w7, [x0] - __ ldsminal(Assembler::word, r9, r16, r20); // ldsminal w9, w16, [x20] - __ ldsmaxal(Assembler::word, r23, r4, r16); // ldsmaxal w23, w4, [x16] - __ lduminal(Assembler::word, r10, r23, r11); // lduminal w10, w23, [x11] - __ ldumaxal(Assembler::word, r25, r6, sp); // ldumaxal w25, w6, [sp] + __ swpal(Assembler::word, r7, r4, r29); // swpal w7, w4, [x29] + __ ldaddal(Assembler::word, r7, r0, r9); // ldaddal w7, w0, [x9] + __ ldbical(Assembler::word, r16, r20, r23); // ldclral w16, w20, [x23] + __ ldeoral(Assembler::word, r4, r16, r10); // ldeoral w4, w16, [x10] + __ ldorral(Assembler::word, r23, r11, r25); // ldsetal w23, w11, [x25] + __ ldsminal(Assembler::word, r6, zr, r16); // ldsminal w6, wzr, [x16] + __ ldsmaxal(Assembler::word, r13, r23, r12); // ldsmaxal w13, w23, [x12] + __ lduminal(Assembler::word, r1, r14, r9); // lduminal w1, w14, [x9] + __ ldumaxal(Assembler::word, r21, r16, r26); // ldumaxal w21, w16, [x26] // LSEOp - __ swpl(Assembler::word, r16, r13, r23); // swpl w16, w13, [x23] - __ ldaddl(Assembler::word, r12, r1, r14); // ldaddl w12, w1, [x14] - __ ldbicl(Assembler::word, r9, r21, r16); // ldclrl w9, w21, [x16] - __ ldeorl(Assembler::word, r26, r15, r4); // ldeorl w26, w15, [x4] - __ ldorrl(Assembler::word, r4, r16, r8); // ldsetl w4, w16, [x8] - __ ldsminl(Assembler::word, r6, r30, r4); // ldsminl w6, w30, [x4] - __ ldsmaxl(Assembler::word, r29, r17, r29); // ldsmaxl w29, w17, [x29] - __ lduminl(Assembler::word, r26, r9, r15); // lduminl w26, w9, [x15] - __ ldumaxl(Assembler::word, r2, r11, r29); // ldumaxl w2, w11, [x29] + __ swpl(Assembler::word, r15, r4, r4); // swpl w15, w4, [x4] + __ ldaddl(Assembler::word, r16, r8, r6); // ldaddl w16, w8, [x6] + __ ldbicl(Assembler::word, r30, r4, r29); // ldclrl w30, w4, [x29] + __ ldeorl(Assembler::word, r17, r29, r26); // ldeorl w17, w29, [x26] + __ ldorrl(Assembler::word, r9, r15, r2); // ldsetl w9, w15, [x2] + __ ldsminl(Assembler::word, r11, r29, r3); // ldsminl w11, w29, [x3] + __ ldsmaxl(Assembler::word, r7, r1, r27); // ldsmaxl w7, w1, [x27] + __ lduminl(Assembler::word, r21, r16, r14); // lduminl w21, w16, [x14] + __ ldumaxl(Assembler::word, r8, r16, r22); // ldumaxl w8, w16, [x22] // SHA3SIMDOp - __ bcax(v3, __ T16B, v7, v1, v27); // bcax v3.16B, v7.16B, v1.16B, v27.16B - __ eor3(v21, __ T16B, v18, v14, v8); // eor3 v21.16B, v18.16B, v14.16B, v8.16B - __ rax1(v18, __ T2D, v22, v25); // rax1 v18.2D, v22.2D, v25.2D - __ xar(v5, __ T2D, v20, v21, 37); // xar v5.2D, v20.2D, v21.2D, #37 + __ bcax(v25, __ T16B, v5, v20, v21); // bcax v25.16B, v5.16B, v20.16B, v21.16B + __ eor3(v18, __ T16B, v23, v16, v30); // eor3 v18.16B, v23.16B, v16.16B, v30.16B + __ rax1(v20, __ T2D, v20, v0); // rax1 v20.2D, v20.2D, v0.2D + __ xar(v4, __ T2D, v19, v24, 9); // xar v4.2D, v19.2D, v24.2D, #9 // SHA512SIMDOp - __ sha512h(v23, __ T2D, v16, v30); // sha512h q23, q16, v30.2D - __ sha512h2(v20, __ T2D, v20, v0); // sha512h2 q20, q20, v0.2D - __ sha512su0(v4, __ T2D, v19); // sha512su0 v4.2D, v19.2D - __ sha512su1(v24, __ T2D, v4, v20); // sha512su1 v24.2D, v4.2D, v20.2D + __ sha512h(v20, __ T2D, v4, v24); // sha512h q20, q4, v24.2D + __ sha512h2(v26, __ T2D, v19, v2); // sha512h2 q26, q19, v2.2D + __ sha512su0(v8, __ T2D, v8); // sha512su0 v8.2D, v8.2D + __ sha512su1(v14, __ T2D, v24, v18); // sha512su1 v14.2D, v24.2D, v18.2D // SVEBinaryImmOp - __ sve_add(z4, __ D, 210u); // add z4.d, z4.d, #0xd2 - __ sve_sub(z19, __ B, 71u); // sub z19.b, z19.b, #0x47 - __ sve_and(z8, __ H, 49663u); // and z8.h, z8.h, #0xc1ff - __ sve_eor(z31, __ S, 4294967231u); // eor z31.s, z31.s, #0xffffffbf - __ sve_orr(z1, __ H, 16368u); // orr z1.h, z1.h, #0x3ff0 + __ sve_add(z31, __ S, 36u); // add z31.s, z31.s, #0x24 + __ sve_sub(z31, __ B, 85u); // sub z31.b, z31.b, #0x55 + __ sve_and(z20, __ H, 4032u); // and z20.h, z20.h, #0xfc0 + __ sve_eor(z7, __ D, 274877904896u); // eor z7.d, z7.d, #0x3ffffff800 + __ sve_orr(z27, __ B, 243u); // orr z27.b, z27.b, #0xf3 // SVEBinaryImmOp - __ sve_add(z0, __ H, 61u); // add z0.h, z0.h, #0x3d - __ sve_sub(z24, __ S, 36u); // sub z24.s, z24.s, #0x24 - __ sve_and(z27, __ B, 243u); // and z27.b, z27.b, #0xf3 - __ sve_eor(z24, __ H, 65534u); // eor z24.h, z24.h, #0xfffe - __ sve_orr(z22, __ S, 4294967293u); // orr z22.s, z22.s, #0xfffffffd + __ sve_add(z24, __ H, 132u); // add z24.h, z24.h, #0x84 + __ sve_sub(z31, __ S, 183u); // sub z31.s, z31.s, #0xb7 + __ sve_and(z20, __ D, 4503599627354112u); // and z20.d, z20.d, #0xfffffffffc000 + __ sve_eor(z14, __ S, 4042322160u); // eor z14.s, z14.s, #0xf0f0f0f0 + __ sve_orr(z28, __ H, 32256u); // orr z28.h, z28.h, #0x7e00 // SVEBinaryImmOp - __ sve_add(z29, __ H, 113u); // add z29.h, z29.h, #0x71 - __ sve_sub(z20, __ B, 165u); // sub z20.b, z20.b, #0xa5 - __ sve_and(z28, __ H, 32256u); // and z28.h, z28.h, #0x7e00 - __ sve_eor(z12, __ S, 4287102855u); // eor z12.s, z12.s, #0xff87ff87 - __ sve_orr(z9, __ S, 3825205247u); // orr z9.s, z9.s, #0xe3ffffff + __ sve_add(z12, __ S, 13u); // add z12.s, z12.s, #0xd + __ sve_sub(z24, __ H, 159u); // sub z24.h, z24.h, #0x9f + __ sve_and(z13, __ S, 2151677951u); // and z13.s, z13.s, #0x803fffff + __ sve_eor(z5, __ B, 124u); // eor z5.b, z5.b, #0x7c + __ sve_orr(z8, __ H, 32768u); // orr z8.h, z8.h, #0x8000 // SVEBinaryImmOp - __ sve_add(z18, __ S, 41u); // add z18.s, z18.s, #0x29 - __ sve_sub(z0, __ B, 98u); // sub z0.b, z0.b, #0x62 - __ sve_and(z8, __ H, 32768u); // and z8.h, z8.h, #0x8000 - __ sve_eor(z4, __ H, 508u); // eor z4.h, z4.h, #0x1fc - __ sve_orr(z0, __ H, 64512u); // orr z0.h, z0.h, #0xfc00 + __ sve_add(z4, __ H, 243u); // add z4.h, z4.h, #0xf3 + __ sve_sub(z5, __ B, 86u); // sub z5.b, z5.b, #0x56 + __ sve_and(z22, __ D, 8064u); // and z22.d, z22.d, #0x1f80 + __ sve_eor(z9, __ S, 130023424u); // eor z9.s, z9.s, #0x7c00000 + __ sve_orr(z24, __ B, 62u); // orr z24.b, z24.b, #0x3e // SVEBinaryImmOp - __ sve_add(z3, __ B, 79u); // add z3.b, z3.b, #0x4f - __ sve_sub(z19, __ D, 84u); // sub z19.d, z19.d, #0x54 - __ sve_and(z24, __ B, 62u); // and z24.b, z24.b, #0x3e - __ sve_eor(z24, __ D, 18428729675200069887u); // eor z24.d, z24.d, #0xffc00000000000ff - __ sve_orr(z11, __ D, 17296056810822168583u); // orr z11.d, z11.d, #0xf007f007f007f007 + __ sve_add(z24, __ D, 113u); // add z24.d, z24.d, #0x71 + __ sve_sub(z21, __ H, 217u); // sub z21.h, z21.h, #0xd9 + __ sve_and(z13, __ S, 3221229567u); // and z13.s, z13.s, #0xc0000fff + __ sve_eor(z14, __ B, 131u); // eor z14.b, z14.b, #0x83 + __ sve_orr(z22, __ S, 4042322160u); // orr z22.s, z22.s, #0xf0f0f0f0 // SVEBinaryImmOp - __ sve_add(z31, __ S, 115u); // add z31.s, z31.s, #0x73 - __ sve_sub(z3, __ D, 134u); // sub z3.d, z3.d, #0x86 - __ sve_and(z22, __ S, 4042322160u); // and z22.s, z22.s, #0xf0f0f0f0 - __ sve_eor(z3, __ B, 225u); // eor z3.b, z3.b, #0xe1 - __ sve_orr(z9, __ S, 4164941887u); // orr z9.s, z9.s, #0xf83ff83f + __ sve_add(z3, __ B, 215u); // add z3.b, z3.b, #0xd7 + __ sve_sub(z19, __ H, 134u); // sub z19.h, z19.h, #0x86 + __ sve_and(z17, __ S, 491520u); // and z17.s, z17.s, #0x78000 + __ sve_eor(z2, __ D, 8796093020160u); // eor z2.d, z2.d, #0x7fffffff800 + __ sve_orr(z11, __ S, 3221229567u); // orr z11.s, z11.s, #0xc0000fff // SVEVectorOp - __ sve_add(z0, __ D, z4, z2); // add z0.d, z4.d, z2.d - __ sve_sub(z14, __ S, z6, z11); // sub z14.s, z6.s, z11.s - __ sve_fadd(z14, __ S, z17, z30); // fadd z14.s, z17.s, z30.s - __ sve_fmul(z3, __ S, z3, z23); // fmul z3.s, z3.s, z23.s - __ sve_fsub(z3, __ S, z24, z28); // fsub z3.s, z24.s, z28.s - __ sve_abs(z19, __ D, p5, z7); // abs z19.d, p5/m, z7.d - __ sve_add(z21, __ H, p3, z5); // add z21.h, p3/m, z21.h, z5.h - __ sve_and(z26, __ S, p1, z22); // and z26.s, p1/m, z26.s, z22.s - __ sve_asr(z17, __ H, p0, z3); // asr z17.h, p0/m, z17.h, z3.h - __ sve_bic(z20, __ H, p3, z8); // bic z20.h, p3/m, z20.h, z8.h - __ sve_clz(z14, __ H, p4, z17); // clz z14.h, p4/m, z17.h - __ sve_cnt(z13, __ D, p6, z18); // cnt z13.d, p6/m, z18.d - __ sve_eor(z19, __ H, p2, z16); // eor z19.h, p2/m, z19.h, z16.h - __ sve_lsl(z27, __ S, p5, z28); // lsl z27.s, p5/m, z27.s, z28.s - __ sve_lsr(z8, __ D, p2, z5); // lsr z8.d, p2/m, z8.d, z5.d - __ sve_mul(z28, __ H, p2, z0); // mul z28.h, p2/m, z28.h, z0.h - __ sve_neg(z25, __ B, p5, z21); // neg z25.b, p5/m, z21.b - __ sve_not(z3, __ B, p5, z26); // not z3.b, p5/m, z26.b - __ sve_orr(z26, __ S, p7, z19); // orr z26.s, p7/m, z26.s, z19.s - __ sve_rbit(z1, __ D, p3, z14); // rbit z1.d, p3/m, z14.d - __ sve_revb(z14, __ H, p0, z18); // revb z14.h, p0/m, z18.h - __ sve_smax(z31, __ S, p5, z23); // smax z31.s, p5/m, z31.s, z23.s - __ sve_smin(z30, __ B, p3, z8); // smin z30.b, p3/m, z30.b, z8.b - __ sve_sub(z0, __ S, p3, z23); // sub z0.s, p3/m, z0.s, z23.s - __ sve_fabs(z0, __ D, p4, z26); // fabs z0.d, p4/m, z26.d - __ sve_fadd(z24, __ D, p3, z22); // fadd z24.d, p3/m, z24.d, z22.d - __ sve_fdiv(z2, __ D, p0, z11); // fdiv z2.d, p0/m, z2.d, z11.d - __ sve_fmax(z12, __ D, p5, z24); // fmax z12.d, p5/m, z12.d, z24.d - __ sve_fmin(z9, __ D, p7, z17); // fmin z9.d, p7/m, z9.d, z17.d - __ sve_fmul(z20, __ D, p5, z4); // fmul z20.d, p5/m, z20.d, z4.d - __ sve_fneg(z13, __ D, p7, z22); // fneg z13.d, p7/m, z22.d - __ sve_frintm(z31, __ D, p6, z18); // frintm z31.d, p6/m, z18.d - __ sve_frintn(z15, __ D, p2, z13); // frintn z15.d, p2/m, z13.d - __ sve_frintp(z20, __ S, p1, z1); // frintp z20.s, p1/m, z1.s - __ sve_fsqrt(z14, __ S, p0, z7); // fsqrt z14.s, p0/m, z7.s - __ sve_fsub(z12, __ D, p4, z4); // fsub z12.d, p4/m, z12.d, z4.d - __ sve_fmad(z15, __ S, p0, z3, z30); // fmad z15.s, p0/m, z3.s, z30.s - __ sve_fmla(z20, __ D, p1, z20, z31); // fmla z20.d, p1/m, z20.d, z31.d - __ sve_fmls(z13, __ D, p3, z9, z14); // fmls z13.d, p3/m, z9.d, z14.d - __ sve_fmsb(z1, __ S, p3, z28, z3); // fmsb z1.s, p3/m, z28.s, z3.s - __ sve_fnmad(z26, __ S, p2, z25, z9); // fnmad z26.s, p2/m, z25.s, z9.s - __ sve_fnmsb(z26, __ D, p2, z14, z1); // fnmsb z26.d, p2/m, z14.d, z1.d - __ sve_fnmla(z26, __ D, p1, z29, z20); // fnmla z26.d, p1/m, z29.d, z20.d - __ sve_fnmls(z6, __ D, p7, z13, z1); // fnmls z6.d, p7/m, z13.d, z1.d - __ sve_mla(z11, __ B, p2, z1, z1); // mla z11.b, p2/m, z1.b, z1.b - __ sve_mls(z27, __ B, p6, z15, z2); // mls z27.b, p6/m, z15.b, z2.b - __ sve_and(z30, z17, z25); // and z30.d, z17.d, z25.d - __ sve_eor(z2, z24, z3); // eor z2.d, z24.d, z3.d - __ sve_orr(z29, z13, z3); // orr z29.d, z13.d, z3.d - __ sve_bic(z14, z16, z28); // bic z14.d, z16.d, z28.d - __ sve_uzp1(z4, __ S, z11, z27); // uzp1 z4.s, z11.s, z27.s - __ sve_uzp2(z2, __ D, z16, z1); // uzp2 z2.d, z16.d, z1.d - __ sve_fabd(z7, __ D, p5, z31); // fabd z7.d, p5/m, z7.d, z31.d - __ sve_bext(z16, __ S, z10, z22); // bext z16.s, z10.s, z22.s - __ sve_bdep(z29, __ B, z7, z22); // bdep z29.b, z7.b, z22.b - __ sve_eor3(z12, z24, z11); // eor3 z12.d, z12.d, z24.d, z11.d + __ sve_add(z30, __ B, z12, z3); // add z30.b, z12.b, z3.b + __ sve_sub(z23, __ D, z9, z3); // sub z23.d, z9.d, z3.d + __ sve_fadd(z28, __ D, z3, z19); // fadd z28.d, z3.d, z19.d + __ sve_fmul(z7, __ S, z26, z21); // fmul z7.s, z26.s, z21.s + __ sve_fsub(z5, __ S, z8, z26); // fsub z5.s, z8.s, z26.s + __ sve_abs(z22, __ B, p4, z17); // abs z22.b, p4/m, z17.b + __ sve_add(z3, __ H, p2, z20); // add z3.h, p2/m, z3.h, z20.h + __ sve_and(z8, __ S, p3, z14); // and z8.s, p3/m, z8.s, z14.s + __ sve_asr(z17, __ D, p2, z13); // asr z17.d, p2/m, z17.d, z13.d + __ sve_bic(z18, __ H, p7, z19); // bic z18.h, p7/m, z18.h, z19.h + __ sve_clz(z16, __ S, p3, z27); // clz z16.s, p3/m, z27.s + __ sve_cnt(z28, __ H, p5, z8); // cnt z28.h, p5/m, z8.h + __ sve_eor(z5, __ H, p7, z28); // eor z5.h, p7/m, z5.h, z28.h + __ sve_lsl(z0, __ S, p3, z25); // lsl z0.s, p3/m, z0.s, z25.s + __ sve_lsr(z21, __ S, p0, z3); // lsr z21.s, p0/m, z21.s, z3.s + __ sve_mul(z26, __ D, p1, z26); // mul z26.d, p1/m, z26.d, z26.d + __ sve_neg(z19, __ H, p4, z1); // neg z19.h, p4/m, z1.h + __ sve_not(z14, __ B, p7, z14); // not z14.b, p7/m, z14.b + __ sve_orr(z18, __ S, p0, z31); // orr z18.s, p0/m, z18.s, z31.s + __ sve_rbit(z23, __ H, p5, z30); // rbit z23.h, p5/m, z30.h + __ sve_revb(z8, __ S, p0, z0); // revb z8.s, p0/m, z0.s + __ sve_smax(z23, __ S, p5, z0); // smax z23.s, p5/m, z23.s, z0.s + __ sve_smin(z26, __ H, p6, z24); // smin z26.h, p6/m, z26.h, z24.h + __ sve_sub(z22, __ B, p5, z2); // sub z22.b, p5/m, z22.b, z2.b + __ sve_fabs(z11, __ D, p5, z12); // fabs z11.d, p5/m, z12.d + __ sve_fadd(z24, __ D, p6, z9); // fadd z24.d, p6/m, z24.d, z9.d + __ sve_fdiv(z17, __ D, p5, z20); // fdiv z17.d, p5/m, z17.d, z20.d + __ sve_fmax(z4, __ D, p5, z13); // fmax z4.d, p5/m, z4.d, z13.d + __ sve_fmin(z22, __ D, p7, z31); // fmin z22.d, p7/m, z22.d, z31.d + __ sve_fmul(z18, __ S, p4, z15); // fmul z18.s, p4/m, z18.s, z15.s + __ sve_fneg(z13, __ S, p7, z20); // fneg z13.s, p7/m, z20.s + __ sve_frintm(z1, __ S, p3, z14); // frintm z1.s, p3/m, z14.s + __ sve_frintn(z7, __ D, p2, z12); // frintn z7.d, p2/m, z12.d + __ sve_frintp(z4, __ S, p6, z15); // frintp z4.s, p6/m, z15.s + __ sve_fsqrt(z3, __ D, p7, z1); // fsqrt z3.d, p7/m, z1.d + __ sve_fsub(z5, __ D, p5, z31); // fsub z5.d, p5/m, z5.d, z31.d + __ sve_fmad(z13, __ D, p3, z9, z14); // fmad z13.d, p3/m, z9.d, z14.d + __ sve_fmla(z1, __ S, p3, z28, z3); // fmla z1.s, p3/m, z28.s, z3.s + __ sve_fmls(z26, __ S, p2, z25, z9); // fmls z26.s, p2/m, z25.s, z9.s + __ sve_fmsb(z26, __ D, p2, z14, z1); // fmsb z26.d, p2/m, z14.d, z1.d + __ sve_fnmad(z26, __ D, p1, z29, z20); // fnmad z26.d, p1/m, z29.d, z20.d + __ sve_fnmsb(z6, __ D, p7, z13, z1); // fnmsb z6.d, p7/m, z13.d, z1.d + __ sve_fnmla(z11, __ S, p2, z1, z1); // fnmla z11.s, p2/m, z1.s, z1.s + __ sve_fnmls(z27, __ S, p6, z15, z2); // fnmls z27.s, p6/m, z15.s, z2.s + __ sve_mla(z30, __ B, p4, z25, z2); // mla z30.b, p4/m, z25.b, z2.b + __ sve_mls(z24, __ H, p0, z26, z29); // mls z24.h, p0/m, z26.h, z29.h + __ sve_and(z3, z22, z14); // and z3.d, z22.d, z14.d + __ sve_eor(z28, z17, z4); // eor z28.d, z17.d, z4.d + __ sve_orr(z27, z16, z2); // orr z27.d, z16.d, z2.d + __ sve_bic(z1, z28, z7); // bic z1.d, z28.d, z7.d + __ sve_uzp1(z31, __ H, z28, z16); // uzp1 z31.h, z28.h, z16.h + __ sve_uzp2(z22, __ B, z17, z29); // uzp2 z22.b, z17.b, z29.b + __ sve_fabd(z22, __ D, p1, z12); // fabd z22.d, p1/m, z22.d, z12.d + __ sve_bext(z11, __ H, z9, z11); // bext z11.h, z9.h, z11.h + __ sve_bdep(z0, __ S, z4, z23); // bdep z0.s, z4.s, z23.s + __ sve_eor3(z20, z4, z3); // eor3 z20.d, z20.d, z4.d, z3.d // SVEReductionOp - __ sve_andv(v11, __ B, p2, z0); // andv b11, p2, z0.b - __ sve_orv(v23, __ B, p5, z20); // orv b23, p5, z20.b - __ sve_eorv(v3, __ B, p3, z15); // eorv b3, p3, z15.b - __ sve_smaxv(v30, __ B, p6, z27); // smaxv b30, p6, z27.b - __ sve_sminv(v21, __ D, p6, z10); // sminv d21, p6, z10.d - __ sve_fminv(v3, __ S, p6, z4); // fminv s3, p6, z4.s - __ sve_fmaxv(v6, __ S, p0, z21); // fmaxv s6, p0, z21.s - __ sve_fadda(v25, __ D, p6, z30); // fadda d25, p6, d25, z30.d - __ sve_uaddv(v31, __ H, p4, z1); // uaddv d31, p4, z1.h + __ sve_andv(v15, __ D, p1, z30); // andv d15, p1, z30.d + __ sve_orv(v27, __ D, p1, z21); // orv d27, p1, z21.d + __ sve_eorv(v10, __ D, p7, z3); // eorv d10, p7, z3.d + __ sve_smaxv(v4, __ B, p2, z6); // smaxv b4, p2, z6.b + __ sve_sminv(v21, __ D, p1, z25); // sminv d21, p1, z25.d + __ sve_fminv(v30, __ D, p6, z31); // fminv d30, p6, z31.d + __ sve_fmaxv(v1, __ D, p2, z12); // fmaxv d1, p2, z12.d + __ sve_fadda(v13, __ D, p2, z25); // fadda d13, p2, d13, z25.d + __ sve_uaddv(v1, __ D, p7, z23); // uaddv d1, p7, z23.d // AddWideNEONOp - __ saddwv(v12, v13, __ T8H, v14, __ T8B); // saddw v12.8H, v13.8H, v14.8B - __ saddwv2(v30, v31, __ T8H, v0, __ T16B); // saddw2 v30.8H, v31.8H, v0.16B - __ saddwv(v13, v14, __ T4S, v15, __ T4H); // saddw v13.4S, v14.4S, v15.4H - __ saddwv2(v8, v9, __ T4S, v10, __ T8H); // saddw2 v8.4S, v9.4S, v10.8H - __ saddwv(v25, v26, __ T2D, v27, __ T2S); // saddw v25.2D, v26.2D, v27.2S + __ saddwv(v20, v21, __ T8H, v22, __ T8B); // saddw v20.8H, v21.8H, v22.8B + __ saddwv2(v0, v1, __ T8H, v2, __ T16B); // saddw2 v0.8H, v1.8H, v2.16B + __ saddwv(v21, v22, __ T4S, v23, __ T4H); // saddw v21.4S, v22.4S, v23.4H + __ saddwv2(v7, v8, __ T4S, v9, __ T8H); // saddw2 v7.4S, v8.4S, v9.8H + __ saddwv(v31, v0, __ T2D, v1, __ T2S); // saddw v31.2D, v0.2D, v1.2S __ saddwv2(v29, v30, __ T2D, v31, __ T4S); // saddw2 v29.2D, v30.2D, v31.4S - __ uaddwv(v1, v2, __ T8H, v3, __ T8B); // uaddw v1.8H, v2.8H, v3.8B - __ uaddwv2(v31, v0, __ T8H, v1, __ T16B); // uaddw2 v31.8H, v0.8H, v1.16B - __ uaddwv(v23, v24, __ T4S, v25, __ T4H); // uaddw v23.4S, v24.4S, v25.4H - __ uaddwv2(v31, v0, __ T4S, v1, __ T8H); // uaddw2 v31.4S, v0.4S, v1.8H - __ uaddwv(v20, v21, __ T2D, v22, __ T2S); // uaddw v20.2D, v21.2D, v22.2S - __ uaddwv2(v0, v1, __ T2D, v2, __ T4S); // uaddw2 v0.2D, v1.2D, v2.4S + __ uaddwv(v27, v28, __ T8H, v29, __ T8B); // uaddw v27.8H, v28.8H, v29.8B + __ uaddwv2(v22, v23, __ T8H, v24, __ T16B); // uaddw2 v22.8H, v23.8H, v24.16B + __ uaddwv(v8, v9, __ T4S, v10, __ T4H); // uaddw v8.4S, v9.4S, v10.4H + __ uaddwv2(v29, v30, __ T4S, v31, __ T8H); // uaddw2 v29.4S, v30.4S, v31.8H + __ uaddwv(v26, v27, __ T2D, v28, __ T2S); // uaddw v26.2D, v27.2D, v28.2S + __ uaddwv2(v20, v21, __ T2D, v22, __ T4S); // uaddw2 v20.2D, v21.2D, v22.4S __ bind(forth); @@ -1327,30 +1337,30 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x14000441, 0x94000000, - 0x97ffffd4, 0x9400043e, 0x3400000a, 0x34fffa2a, - 0x3400876a, 0x35000008, 0x35fff9c8, 0x35008708, - 0xb400000b, 0xb4fff96b, 0xb40086ab, 0xb500001d, - 0xb5fff91d, 0xb500865d, 0x10000013, 0x10fff8b3, - 0x100085f3, 0x90000013, 0x36300016, 0x3637f836, - 0x36308576, 0x3758000c, 0x375ff7cc, 0x3758850c, + 0x14000000, 0x17ffffd7, 0x1400044b, 0x94000000, + 0x97ffffd4, 0x94000448, 0x3400000a, 0x34fffa2a, + 0x340088aa, 0x35000008, 0x35fff9c8, 0x35008848, + 0xb400000b, 0xb4fff96b, 0xb40087eb, 0xb500001d, + 0xb5fff91d, 0xb500879d, 0x10000013, 0x10fff8b3, + 0x10008733, 0x90000013, 0x36300016, 0x3637f836, + 0x363086b6, 0x3758000c, 0x375ff7cc, 0x3758864c, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x540082e0, 0x54000001, 0x54fff541, 0x54008281, - 0x54000002, 0x54fff4e2, 0x54008222, 0x54000002, - 0x54fff482, 0x540081c2, 0x54000003, 0x54fff423, - 0x54008163, 0x54000003, 0x54fff3c3, 0x54008103, - 0x54000004, 0x54fff364, 0x540080a4, 0x54000005, - 0x54fff305, 0x54008045, 0x54000006, 0x54fff2a6, - 0x54007fe6, 0x54000007, 0x54fff247, 0x54007f87, - 0x54000008, 0x54fff1e8, 0x54007f28, 0x54000009, - 0x54fff189, 0x54007ec9, 0x5400000a, 0x54fff12a, - 0x54007e6a, 0x5400000b, 0x54fff0cb, 0x54007e0b, - 0x5400000c, 0x54fff06c, 0x54007dac, 0x5400000d, - 0x54fff00d, 0x54007d4d, 0x5400000e, 0x54ffefae, - 0x54007cee, 0x5400000f, 0x54ffef4f, 0x54007c8f, + 0x54008420, 0x54000001, 0x54fff541, 0x540083c1, + 0x54000002, 0x54fff4e2, 0x54008362, 0x54000002, + 0x54fff482, 0x54008302, 0x54000003, 0x54fff423, + 0x540082a3, 0x54000003, 0x54fff3c3, 0x54008243, + 0x54000004, 0x54fff364, 0x540081e4, 0x54000005, + 0x54fff305, 0x54008185, 0x54000006, 0x54fff2a6, + 0x54008126, 0x54000007, 0x54fff247, 0x540080c7, + 0x54000008, 0x54fff1e8, 0x54008068, 0x54000009, + 0x54fff189, 0x54008009, 0x5400000a, 0x54fff12a, + 0x54007faa, 0x5400000b, 0x54fff0cb, 0x54007f4b, + 0x5400000c, 0x54fff06c, 0x54007eec, 0x5400000d, + 0x54fff00d, 0x54007e8d, 0x5400000e, 0x54ffefae, + 0x54007e2e, 0x5400000f, 0x54ffef4f, 0x54007dcf, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, @@ -1471,134 +1481,137 @@ 0x4e60f7fe, 0x0e3c6f7a, 0x4e346e72, 0x0e6b6d49, 0x4e6a6d28, 0x0eae6dac, 0x4ea26c20, 0x0e36aeb4, 0x4e23ac41, 0x0e7aaf38, 0x4e64ac62, 0x0ea2ac20, - 0x4eabad49, 0x0ebaf738, 0x4ebcf77a, 0x4ef2f630, - 0x2ea0effe, 0x6ea5ec83, 0x6eeced6a, 0x0fa710c5, - 0x4f8b8149, 0x4fc710c5, 0x0f8750c5, 0x4faa8128, - 0x4fc750c5, 0x2f8890e6, 0x4fa880e6, 0x6fc59083, - 0x0f6f81cd, 0x4f448862, 0x0f848062, 0x4fab8149, - 0x0e3736d5, 0x4e323630, 0x0e743672, 0x4e6d358b, - 0x0eb736d5, 0x4eb93717, 0x4eee35ac, 0x0e3c3f7a, - 0x4e393f17, 0x0e7e3fbc, 0x4e703dee, 0x0ead3d8b, - 0x4eba3f38, 0x4ee33c41, 0x2e2e8dac, 0x6e218c1f, - 0x2e6c8d6a, 0x6e728e30, 0x2ea98d07, 0x6ea48c62, - 0x6ee58c83, 0x2e2f35cd, 0x6e353693, 0x2e733651, - 0x6e723630, 0x2ea53483, 0x6ea33441, 0x6eed358b, - 0x2e203ffe, 0x6e273cc5, 0x2e6a3d28, 0x6e713e0f, - 0x2ebf3fdd, 0x6ea03ffe, 0x6ee23c20, 0x0e36e6b4, - 0x4e29e507, 0x4e76e6b4, 0x2eb9e717, 0x6ebee7bc, - 0x6ef7e6d5, 0x2e3de79b, 0x6e3be759, 0x6e67e4c5, - 0x65d23ee0, 0x65903d92, 0x65d03fa7, 0x65912fe9, - 0x65d13bf9, 0x65932a0a, 0x25cb90c4, 0x25040bde, - 0x25c11085, 0x25c62c6b, 0x259f2279, 0x259d8993, - 0x24e5102b, 0x24ad5458, 0x24ec7ab5, 0x24387c6d, - 0xba5fd3e3, 0x3a5f03e5, 0xfa411be4, 0x7a42cbe2, - 0x93df03ff, 0xc820ffff, 0x8822fc7f, 0xc8247cbf, - 0x88267fff, 0x4e010fe0, 0x5e040420, 0x4e081fe1, - 0x4e0c1fe1, 0x4e0a1fe1, 0x4e071fe1, 0x4e042c20, - 0x4e062c20, 0x4e052c20, 0x4e083c20, 0x0e0c3c20, - 0x0e0a3c20, 0x0e073c20, 0x9eae0020, 0x0f03f409, - 0x6f03f40e, 0x4cc0ac3f, 0x0ea1b820, 0x4e21c862, - 0x4e61b8a4, 0x05a08020, 0x05104fe0, 0x05505001, - 0x05906fe2, 0x05d03005, 0x05101fea, 0x05901feb, - 0x04b0e3e0, 0x0470e7e1, 0x042f9c20, 0x043f9c35, - 0x047f9c20, 0x04ff9c20, 0x04299420, 0x04319160, - 0x0461943e, 0x04a19020, 0x04038100, 0x040381a0, - 0x040387e1, 0x04438be2, 0x04c38fe3, 0x040181e0, - 0x04018100, 0x04018621, 0x04418b22, 0x04418822, - 0x04818c23, 0x040081e0, 0x04008120, 0x04008761, - 0x04008621, 0x04408822, 0x04808c23, 0x042053ff, - 0x047f5401, 0x25208028, 0x2538cfe0, 0x2578d001, - 0x25b8efe2, 0x25f8f007, 0x2538dfea, 0x25b8dfeb, - 0xa400a3e0, 0xa420a7e0, 0xa4484be0, 0xa467afe0, - 0xa4a8a7ea, 0xa547a814, 0xa4084ffe, 0xa55c53e0, - 0xa5e1540b, 0xe400fbf6, 0xe408ffff, 0xe420e7e0, - 0xe4484be0, 0xe460efe0, 0xe547e400, 0xe4014be0, - 0xe4a84fe0, 0xe5f15000, 0x858043e0, 0x85a043ff, - 0xe59f5d08, 0x0420e3e9, 0x0460e3ea, 0x04a0e3eb, - 0x04e0e3ec, 0x25104042, 0x25104871, 0x25904861, - 0x25904c92, 0x05344020, 0x05744041, 0x05b44062, - 0x05f44083, 0x252c8840, 0x253c1420, 0x25681572, - 0x25a21ce3, 0x25ea1e34, 0x253c0421, 0x25680572, - 0x25a20ce3, 0x25ea0e34, 0x0522c020, 0x05e6c0a4, - 0x2401a001, 0x2443a051, 0x24858881, 0x24c78cd1, - 0x24850891, 0x24c70cc1, 0x250f9001, 0x25508051, - 0x25802491, 0x25df28c1, 0x25850c81, 0x251e10d1, - 0x65816001, 0x65c36051, 0x65854891, 0x65c74cc1, - 0x05733820, 0x05b238a4, 0x05f138e6, 0x0570396a, - 0x65d0a001, 0x65d6a443, 0x65d4a826, 0x6594ac26, - 0x6554ac26, 0x6556ac26, 0x6552ac26, 0x65cbac85, - 0x65caac01, 0x6589ac85, 0x6588ac01, 0x65c9ac85, - 0x65c8ac01, 0x65dea833, 0x659ca509, 0x65d8a801, - 0x65dcac01, 0x655cb241, 0x0520a1e0, 0x0521a601, - 0x052281e0, 0x05238601, 0x04a14026, 0x042244a6, - 0x046344a6, 0x04a444a6, 0x04e544a7, 0x0568aca7, - 0x05b23230, 0x853040af, 0xc5b040af, 0xe57080af, - 0xe5b080af, 0x25034440, 0x254054c4, 0x25034640, - 0x25415a05, 0x25834440, 0x25c54489, 0x250b5d3a, - 0x2550dc20, 0x2518e3e1, 0x2518e021, 0x2518e0a1, - 0x2518e121, 0x2518e1a1, 0x2558e3e2, 0x2558e042, - 0x2558e0c2, 0x2558e142, 0x2598e3e3, 0x2598e063, - 0x2598e0e3, 0x2598e163, 0x25d8e3e4, 0x25d8e084, - 0x25d8e104, 0x25d8e184, 0x2518e407, 0x05214800, - 0x05614800, 0x05a14800, 0x05e14800, 0x05214c00, - 0x05614c00, 0x05a14c00, 0x05e14c00, 0x05304001, - 0x05314001, 0x05a18610, 0x05e18610, 0x05271e11, - 0x6545e891, 0x6585e891, 0x65c5e891, 0x6545c891, - 0x6585c891, 0x65c5c891, 0x45b0c210, 0x45f1c231, - 0x1e601000, 0x1e603000, 0x1e621000, 0x1e623000, - 0x1e641000, 0x1e643000, 0x1e661000, 0x1e663000, - 0x1e681000, 0x1e683000, 0x1e6a1000, 0x1e6a3000, - 0x1e6c1000, 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, - 0x1e701000, 0x1e703000, 0x1e721000, 0x1e723000, - 0x1e741000, 0x1e743000, 0x1e761000, 0x1e763000, - 0x1e781000, 0x1e783000, 0x1e7a1000, 0x1e7a3000, - 0x1e7c1000, 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, - 0xf8338131, 0xf83c01fb, 0xf82712f5, 0xf83f2059, - 0xf83f31fb, 0xf82a5277, 0xf8234010, 0xf83972fa, - 0xf8226190, 0xf8a483dc, 0xf8bd0370, 0xf8a613a9, - 0xf8b02087, 0xf8a7312f, 0xf8b75048, 0xf8bc43f5, - 0xf8a5701b, 0xf8b1608f, 0xf8fa8388, 0xf8f6037b, - 0xf8f91017, 0xf8e421e6, 0xf8e031e4, 0xf8e150ea, - 0xf8e5438a, 0xf8e772f4, 0xf8f56166, 0xf86883f1, - 0xf8660051, 0xf86c13be, 0xf86322db, 0xf87d31ae, - 0xf87c5311, 0xf86541c2, 0xf86a7170, 0xf87b6197, - 0xb8248236, 0xb8240261, 0xb83011b0, 0xb82e204c, - 0xb83132a3, 0xb83750c5, 0xb82741b3, 0xb83c7211, - 0xb82663a2, 0xb8a380c4, 0xb8b001b4, 0xb8ac1114, - 0xb8b92274, 0xb8a0330b, 0xb8a653f4, 0xb8ae40d0, - 0xb8a071e7, 0xb8b3613a, 0xb8ea82b7, 0xb8f6005c, - 0xb8e3126f, 0xb8f42087, 0xb8fd3007, 0xb8e95290, - 0xb8f74204, 0xb8ea7177, 0xb8f963e6, 0xb87082ed, - 0xb86c01c1, 0xb8691215, 0xb87a208f, 0xb8643110, - 0xb866509e, 0xb87d43b1, 0xb87a71e9, 0xb86263ab, - 0xce216ce3, 0xce0e2255, 0xce798ed2, 0xce959685, - 0xce7e8217, 0xce608694, 0xcec08264, 0xce748898, - 0x25e0da44, 0x2521c8f3, 0x05801548, 0x0540cbdf, - 0x05006521, 0x2560c7a0, 0x25a1c498, 0x058026bb, - 0x05407dd8, 0x0500f3d6, 0x2560ce3d, 0x2521d4b4, - 0x05803cbc, 0x05404d6c, 0x05001b89, 0x25a0c532, - 0x2521cc40, 0x05800c08, 0x054074c4, 0x050034a0, - 0x2520c9e3, 0x25e1ca93, 0x05803e98, 0x05425238, - 0x050024cb, 0x25a0ce7f, 0x25e1d0c3, 0x05802676, - 0x05401e63, 0x05002d49, 0x04e20080, 0x04ab04ce, - 0x659e022e, 0x65970863, 0x659c0703, 0x04d6b4f3, - 0x04400cb5, 0x049a06da, 0x04508071, 0x045b0d14, - 0x0459b22e, 0x04daba4d, 0x04590a13, 0x0493979b, - 0x04d188a8, 0x0450081c, 0x0417b6b9, 0x041eb743, - 0x04981e7a, 0x05e78dc1, 0x0564824e, 0x048816ff, - 0x040a0d1e, 0x04810ee0, 0x04dcb340, 0x65c08ed8, - 0x65cd8162, 0x65c6970c, 0x65c79e29, 0x65c29494, - 0x04ddbecd, 0x65c2ba5f, 0x65c0a9af, 0x6581a434, - 0x658da0ee, 0x65c1908c, 0x65be806f, 0x65ff0694, - 0x65ee2d2d, 0x65a3af81, 0x65a9cb3a, 0x65e1e9da, - 0x65f447ba, 0x65e17da6, 0x0401482b, 0x040279fb, - 0x0439323e, 0x04a33302, 0x046331bd, 0x04fc320e, - 0x05bb6964, 0x05e16e02, 0x65c897e7, 0x4596b150, - 0x4516b4fd, 0x0438396c, 0x041a280b, 0x04183697, - 0x04192de3, 0x04083b7e, 0x04ca3955, 0x65873883, - 0x658622a6, 0x65d83bd9, 0x0441303f, 0x0e2e11ac, - 0x4e2013fe, 0x0e6f11cd, 0x4e6a1128, 0x0ebb1359, - 0x4ebf13dd, 0x2e231041, 0x6e21101f, 0x2e791317, - 0x6e61101f, 0x2eb612b4, 0x6ea21020, + 0x4eabad49, 0x0e7ab738, 0x4e7cb77a, 0x0eb2b630, + 0x4ea0b7fe, 0x0e252483, 0x4e2c256a, 0x0e792717, + 0x4e6c256a, 0x0ea624a4, 0x4eb42672, 0x0ea4f462, + 0x4eadf58b, 0x4eeaf528, 0x2eaced6a, 0x6eb1ee0f, + 0x6ef3ee51, 0x0f8710c5, 0x4fa880e6, 0x4fc810e6, + 0x0f855083, 0x4f8f89cd, 0x4fc45862, 0x2f849062, + 0x4fab8149, 0x6fca9928, 0x0f6780c5, 0x4f5d898b, + 0x0f8f81cd, 0x4f9089ee, 0x0e3035ee, 0x4e2d358b, + 0x0e7a3738, 0x4e633441, 0x0eae35ac, 0x4ea1341f, + 0x4eec356a, 0x0e323e30, 0x4e293d07, 0x0e643c62, + 0x4e653c83, 0x0eaf3dcd, 0x4eb53e93, 0x4ef33e51, + 0x2e328e30, 0x6e258c83, 0x2e638c41, 0x6e6d8d8b, + 0x2ea08ffe, 0x6ea78cc5, 0x6eea8d28, 0x2e31360f, + 0x6e3f37dd, 0x2e6037fe, 0x6e623420, 0x2eb636b4, + 0x6ea93507, 0x6ef636b4, 0x2e393f17, 0x6e3e3fbc, + 0x2e773ed5, 0x6e7d3f9b, 0x2ebb3f59, 0x6ea73cc5, + 0x6ee33c41, 0x0e39e717, 0x4e32e630, 0x4e61e41f, + 0x2ea7e4c5, 0x6eaee5ac, 0x6eebe549, 0x2e3ee7bc, + 0x6e31e60f, 0x6e7fe7dd, 0x65d23feb, 0x65d03dd2, + 0x65d03369, 0x65912566, 0x65d13e3f, 0x659334ef, + 0x25c19085, 0x25c60c7b, 0x259f0269, 0x259d2983, + 0x25d5303b, 0x259d9458, 0x24ec5aa5, 0x24385c7d, + 0x247b7e39, 0x24bff4e7, 0xba5fd3e3, 0x3a5f03e5, + 0xfa411be4, 0x7a42cbe2, 0x93df03ff, 0xc820ffff, + 0x8822fc7f, 0xc8247cbf, 0x88267fff, 0x4e010fe0, + 0x5e040420, 0x4e081fe1, 0x4e0c1fe1, 0x4e0a1fe1, + 0x4e071fe1, 0x4e042c20, 0x4e062c20, 0x4e052c20, + 0x4e083c20, 0x0e0c3c20, 0x0e0a3c20, 0x0e073c20, + 0x9eae0020, 0x0f03f409, 0x6f03f40e, 0x4cc0ac3f, + 0x0ea1b820, 0x4e21c862, 0x4e61b8a4, 0x05a08020, + 0x05104fe0, 0x05505001, 0x05906fe2, 0x05d03005, + 0x05101fea, 0x05901feb, 0x04b0e3e0, 0x0470e7e1, + 0x042f9c20, 0x043f9c35, 0x047f9c20, 0x04ff9c20, + 0x04299420, 0x04319160, 0x0461943e, 0x04a19020, + 0x04038100, 0x040381a0, 0x040387e1, 0x04438be2, + 0x04c38fe3, 0x040181e0, 0x04018100, 0x04018621, + 0x04418b22, 0x04418822, 0x04818c23, 0x040081e0, + 0x04008120, 0x04008761, 0x04008621, 0x04408822, + 0x04808c23, 0x042053ff, 0x047f5401, 0x25208028, + 0x2538cfe0, 0x2578d001, 0x25b8efe2, 0x25f8f007, + 0x2538dfea, 0x25b8dfeb, 0xa400a3e0, 0xa420a7e0, + 0xa4484be0, 0xa467afe0, 0xa4a8a7ea, 0xa547a814, + 0xa4084ffe, 0xa55c53e0, 0xa5e1540b, 0xe400fbf6, + 0xe408ffff, 0xe420e7e0, 0xe4484be0, 0xe460efe0, + 0xe547e400, 0xe4014be0, 0xe4a84fe0, 0xe5f15000, + 0x858043e0, 0x85a043ff, 0xe59f5d08, 0x0420e3e9, + 0x0460e3ea, 0x04a0e3eb, 0x04e0e3ec, 0x25104042, + 0x25104871, 0x25904861, 0x25904c92, 0x05344020, + 0x05744041, 0x05b44062, 0x05f44083, 0x252c8840, + 0x253c1420, 0x25681572, 0x25a21ce3, 0x25ea1e34, + 0x253c0421, 0x25680572, 0x25a20ce3, 0x25ea0e34, + 0x0522c020, 0x05e6c0a4, 0x2401a001, 0x2443a051, + 0x24858881, 0x24c78cd1, 0x24850891, 0x24c70cc1, + 0x250f9001, 0x25508051, 0x25802491, 0x25df28c1, + 0x25850c81, 0x251e10d1, 0x65816001, 0x65c36051, + 0x65854891, 0x65c74cc1, 0x05733820, 0x05b238a4, + 0x05f138e6, 0x0570396a, 0x65d0a001, 0x65d6a443, + 0x65d4a826, 0x6594ac26, 0x6554ac26, 0x6556ac26, + 0x6552ac26, 0x65cbac85, 0x65caac01, 0x6589ac85, + 0x6588ac01, 0x65c9ac85, 0x65c8ac01, 0x65dea833, + 0x659ca509, 0x65d8a801, 0x65dcac01, 0x655cb241, + 0x0520a1e0, 0x0521a601, 0x052281e0, 0x05238601, + 0x04a14026, 0x042244a6, 0x046344a6, 0x04a444a6, + 0x04e544a7, 0x0568aca7, 0x05b23230, 0x853040af, + 0xc5b040af, 0xe57080af, 0xe5b080af, 0x25034440, + 0x254054c4, 0x25034640, 0x25415a05, 0x25834440, + 0x25c54489, 0x250b5d3a, 0x2550dc20, 0x2518e3e1, + 0x2518e021, 0x2518e0a1, 0x2518e121, 0x2518e1a1, + 0x2558e3e2, 0x2558e042, 0x2558e0c2, 0x2558e142, + 0x2598e3e3, 0x2598e063, 0x2598e0e3, 0x2598e163, + 0x25d8e3e4, 0x25d8e084, 0x25d8e104, 0x25d8e184, + 0x2518e407, 0x05214800, 0x05614800, 0x05a14800, + 0x05e14800, 0x05214c00, 0x05614c00, 0x05a14c00, + 0x05e14c00, 0x05304001, 0x05314001, 0x05a18610, + 0x05e18610, 0x05271e11, 0x6545e891, 0x6585e891, + 0x65c5e891, 0x6545c891, 0x6585c891, 0x65c5c891, + 0x45b0c210, 0x45f1c231, 0x1e601000, 0x1e603000, + 0x1e621000, 0x1e623000, 0x1e641000, 0x1e643000, + 0x1e661000, 0x1e663000, 0x1e681000, 0x1e683000, + 0x1e6a1000, 0x1e6a3000, 0x1e6c1000, 0x1e6c3000, + 0x1e6e1000, 0x1e6e3000, 0x1e701000, 0x1e703000, + 0x1e721000, 0x1e723000, 0x1e741000, 0x1e743000, + 0x1e761000, 0x1e763000, 0x1e781000, 0x1e783000, + 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, 0x1e7c3000, + 0x1e7e1000, 0x1e7e3000, 0xf83983e2, 0xf83b0150, + 0xf8371073, 0xf8302320, 0xf83a3057, 0xf830508c, + 0xf83c43be, 0xf83070db, 0xf82961fd, 0xf8a780e4, + 0xf8af02e9, 0xf8a81382, 0xf8b520bf, 0xf8bb3220, + 0xf8af5344, 0xf8a842dc, 0xf8bb733b, 0xf8b76080, + 0xf8e68010, 0xf8e4002f, 0xf8ea10a7, 0xf8ea20fc, + 0xf8f432b7, 0xf8e6510b, 0xf8f140df, 0xf8f17182, + 0xf8fe607d, 0xf87b83b6, 0xf86e038d, 0xf87110b8, + 0xf862214e, 0xf870336b, 0xf877508c, 0xf8764091, + 0xf8617213, 0xf87061cd, 0xb82c8222, 0xb82302f5, + 0xb82510e6, 0xb833238d, 0xb83130d0, 0xb822507d, + 0xb82441e6, 0xb834718d, 0xb8346328, 0xb8b48013, + 0xb8ab00d8, 0xb8b411df, 0xb8b02006, 0xb8a7326f, + 0xb8ba5149, 0xb8b742d5, 0xb8bc7062, 0xb8af6293, + 0xb8e783a4, 0xb8e70120, 0xb8f012f4, 0xb8e42150, + 0xb8f7332b, 0xb8e6521f, 0xb8ed4197, 0xb8e1712e, + 0xb8f56350, 0xb86f8084, 0xb87000c8, 0xb87e13a4, + 0xb871235d, 0xb869304f, 0xb86b507d, 0xb8674361, + 0xb87571d0, 0xb86862d0, 0xce3454b9, 0xce107af2, + 0xce608e94, 0xce982664, 0xce788094, 0xce62867a, + 0xcec08108, 0xce728b0e, 0x25a0c49f, 0x2521cabf, + 0x058054b4, 0x0543ab47, 0x050026bb, 0x2560d098, + 0x25a1d6ff, 0x058394b4, 0x0540266e, 0x05003cbc, + 0x25a0c1ac, 0x2561d3f8, 0x05800acd, 0x05403685, + 0x05000c08, 0x2560de64, 0x2521cac5, 0x0583c8b6, + 0x05405089, 0x05003e98, 0x25e0ce38, 0x2561db35, + 0x058011ad, 0x05400e4e, 0x05002676, 0x2520dae3, + 0x2561d0d3, 0x05808871, 0x0543abe2, 0x050011ab, + 0x0423019e, 0x04e30537, 0x65d3007c, 0x65950b47, + 0x659a0505, 0x0416b236, 0x04400a83, 0x049a0dc8, + 0x04d089b1, 0x045b1e72, 0x0499af70, 0x045ab51c, + 0x04591f85, 0x04938f20, 0x04918075, 0x04d0075a, + 0x0457b033, 0x041ebdce, 0x049803f2, 0x056797d7, + 0x05a48008, 0x04881417, 0x044a1b1a, 0x04011456, + 0x04dcb58b, 0x65c09938, 0x65cd9691, 0x65c695a4, + 0x65c79ff6, 0x658291f2, 0x049dbe8d, 0x6582adc1, + 0x65c0a987, 0x6581b9e4, 0x65cdbc23, 0x65c197e5, + 0x65ee8d2d, 0x65a30f81, 0x65a92b3a, 0x65e1a9da, + 0x65f4c7ba, 0x65e1fda6, 0x65a1482b, 0x65a279fb, + 0x0402533e, 0x045d6358, 0x042e32c3, 0x04a4323c, + 0x0462321b, 0x04e73381, 0x05706b9f, 0x053d6e36, + 0x65c88596, 0x454bb12b, 0x4597b480, 0x04243874, + 0x04da27cf, 0x04d826bb, 0x04d93c6a, 0x040828c4, + 0x04ca2735, 0x65c73bfe, 0x65c62981, 0x65d82b2d, + 0x04c13ee1, 0x0e3612b4, 0x4e221020, 0x0e7712d5, + 0x4e691107, 0x0ea1101f, 0x4ebf13dd, 0x2e3d139b, + 0x6e3812f6, 0x2e6a1128, 0x6e7f13dd, 0x2ebc137a, + 0x6eb612b4, }; // END Generated code -- do not edit diff -Nru openjdk-21-21.0.12.1+1/test/hotspot/jtreg/TEST.ROOT openjdk-21-21.0.13+9/test/hotspot/jtreg/TEST.ROOT --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/TEST.ROOT 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -94,7 +94,7 @@ jdk.containerized # Minimum jtreg version -requiredVersion=7.5.2+1 +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-21-21.0.12.1+1/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java 2026-10-19 12:10:20.000000000 +0000 @@ -84,8 +84,14 @@ } @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}) + // This check will fail if JDK-8311932 is backported, adjust the count to 1. + @IR(counts = { IRNode.COUNTED_LOOP, "3"}) public static void testStridePosScalePosInIntLoop2(int start, int stop, long length, long offset) { final int scale = 2; final int stride = 1; @@ -135,8 +141,14 @@ } @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}) + // This check will fail if JDK-8311932 is backported, adjust the count to 1. + @IR(counts = { IRNode.COUNTED_LOOP, "3"}) public static void testStrideNegScaleNegInIntLoop2(int start, int stop, long length, long offset) { final int scale = -2; final int stride = 1; @@ -184,8 +196,14 @@ } @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}) + // This check will fail if JDK-8311932 is backported, adjust the count to 1. + @IR(counts = { IRNode.COUNTED_LOOP, "3"}) public static void testStrideNegScalePosInIntLoop2(int start, int stop, long length, long offset) { final int scale = 2; final int stride = 1; @@ -232,8 +250,14 @@ } @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}) + // This check will fail if JDK-8311932 is backported, adjust the count to 1. + @IR(counts = { IRNode.COUNTED_LOOP, "3"}) public static void testStridePosScaleNegInIntLoop2(int start, int stop, long length, long offset) { final int scale = -2; final int stride = 1; diff -Nru openjdk-21-21.0.12.1+1/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java 2026-10-19 12:10:20.000000000 +0000 @@ -63,7 +63,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]); } } @@ -74,6 +74,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-21-21.0.12.1+1/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java 2026-10-19 12:10:20.000000000 +0000 @@ -348,6 +348,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"); diff -Nru openjdk-21-21.0.12.1+1/test/hotspot/jtreg/compiler/rangechecks/TestIndexMatching.java openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/rangechecks/TestIndexMatching.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/compiler/rangechecks/TestIndexMatching.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheckWithZeroScaling.java openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheckWithZeroScaling.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheckWithZeroScaling.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java 2026-10-19 12:10:20.000000000 +0000 @@ -102,8 +102,10 @@ new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null)))))))))); public static final BooleanSupplier SHA3_INSTRUCTION_AVAILABLE - // sha3 is only implemented on aarch64 for now - = new CPUSpecificPredicate("aarch64.*", new String[] {"sha3" }, null); + // sha3 is only implemented on aarch64 and avx512 for now + = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] {"sha3" }, null), + new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] {"avx512f", "avx512bw"}, null), + new CPUSpecificPredicate("x86_64", new String[] {"avx512f", "avx512bw"}, null))); public static final BooleanSupplier ANY_SHA_INSTRUCTION_AVAILABLE = new OrPredicate(IntrinsicPredicates.SHA1_INSTRUCTION_AVAILABLE, diff -Nru openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/DockerBasicTest.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/DockerBasicTest.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/DockerBasicTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/ShareTmpDir.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/ShareTmpDir.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/ShareTmpDir.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestCPUSets.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestCPUSets.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestCPUSets.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestContainerInfo.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestContainerInfo.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestContainerInfo.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestJFREvents.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestJFREvents.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestJFREvents.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestJFREvents.java 2026-10-19 12:10:20.000000000 +0000 @@ -33,6 +33,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 JfrReporter @@ -56,9 +57,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); diff -Nru openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestJcmd.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestJcmd.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestJcmd.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java 2026-10-19 12:10:20.000000000 +0000 @@ -54,10 +54,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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java 2026-10-19 12:10:20.000000000 +0000 @@ -51,10 +51,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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestMisc.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestMisc.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestMisc.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestPids.java openjdk-21-21.0.13+9/test/hotspot/jtreg/containers/docker/TestPids.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/containers/docker/TestPids.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/gc/TestNativeReferenceGet.java openjdk-21-21.0.13+9/test/hotspot/jtreg/gc/TestNativeReferenceGet.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/gc/TestNativeReferenceGet.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java openjdk-21-21.0.13+9/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java 2026-10-19 12:10:20.000000000 +0000 @@ -27,6 +27,7 @@ * @summary Class-Path: attribute in MANIFEST file * @requires vm.cds * @library /test/lib + * @compile test-classes/Hello.java * @run driver/timeout=240 ClassPathAttr */ @@ -44,6 +45,7 @@ public static void main(String[] args) throws Exception { testNormalOps(); testNonExistentJars(); + testClassPathAttrJarOnCP(); } static void testNormalOps() throws Exception { @@ -126,6 +128,62 @@ }); } + static void testClassPathAttrJarOnCP() throws Exception { + String helloJar = JarBuilder.getOrCreateHelloJar(); + String jar1 = TestCommon.getTestJar("cpattr1.jar"); + String cp = jar1 + File.pathSeparator + helloJar; + + // The cpattr1.jar contains "Class-Path: cpattr2.jar". + // The cpattr2.jar contains "Class-Path: cpattr3.jar cpattr5_123456789_223456789_323456789_42345678.jar". + // With -cp cpattr1:hello.jar, the following shared paths should be stored in the CDS archive: + // cpattr1.jar:cpattr2.jar:cpattr3.jar:cpattr5_123456789_223456789_323456789_42345678.jari:hello.jar + TestCommon.testDump(cp, TestCommon.list("Hello"), "-Xlog:class+path"); + + // Run with the same -cp apattr1.jar:hello.jar. The Hello class should be + // loaded from the archive. + TestCommon.run("-Xlog:class+path,class+load", + "-cp", cp, + "Hello") + .assertNormalExit(output -> { + output.shouldContain("Hello source: shared objects file"); + }); + + // Run with -cp apattr1.jar:cpattr2.jar:hello.jar. App classpath mismatch should be detected. + String jar2 = TestCommon.getTestJar("cpattr2.jar"); + cp = jar1 + File.pathSeparator + jar2 + File.pathSeparator + helloJar; + TestCommon.run("-Xlog:class+path,class+load", + "-cp", cp, + "Hello") + .assertAbnormalExit(output -> { + output.shouldMatch(".*APP classpath mismatch, actual: -Djava.class.path=.*cpattr1.jar.*cpattr2.jar.*hello.jar") + .shouldContain("Unable to use shared archive."); + }); + + // Run with different -cp cpattr2.jar:hello.jar. App classpath mismatch should be detected. + cp = jar2 + File.pathSeparator + helloJar; + TestCommon.run("-Xlog:class+path,class+load", + "-cp", cp, + "Hello") + .assertAbnormalExit(output -> { + output.shouldMatch(".*APP classpath mismatch, actual: -Djava.class.path=.*cpattr2.jar.*hello.jar") + .shouldContain("Unable to use shared archive."); + }); + + // Dumping with -cp cpattr1.jar:cpattr2.jar:hello.jar + // The cpattr2.jar is from the Class-Path: attribute of cpattr1.jar. + cp = jar1 + File.pathSeparator + jar2 + File.pathSeparator + helloJar; + TestCommon.testDump(cp, TestCommon.list("Hello"), "-Xlog:class+path"); + + // Run with the same -cp as dump time. The Hello class should be loaded from the archive. + TestCommon.run("-Xlog:class+path,class+load", + "-cp", cp, + "Hello") + .assertNormalExit(output -> { + output.shouldContain("Hello source: shared objects file"); + }); + + } + private static void buildCpAttr(String jarName, String manifest, String enclosingClassName, String ...testClassNames) throws Exception { String jarClassesDir = CDSTestUtils.getOutputDir() + File.separator + jarName + "_classes"; try { Files.createDirectory(Paths.get(jarClassesDir)); } catch (FileAlreadyExistsException e) { } diff -Nru openjdk-21-21.0.12.1+1/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java openjdk-21-21.0.13+9/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/serviceability/dcmd/thread/PrintTest.java openjdk-21-21.0.13+9/test/hotspot/jtreg/serviceability/dcmd/thread/PrintTest.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/serviceability/dcmd/thread/PrintTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/hotspot/jtreg/testlibrary/jittester/conf/exclude.methods.lst openjdk-21-21.0.13+9/test/hotspot/jtreg/testlibrary/jittester/conf/exclude.methods.lst --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/testlibrary/jittester/conf/exclude.methods.lst 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/jtreg/testlibrary/jittester/conf/exclude.methods.lst 2026-10-19 12:10:20.000000000 +0000 @@ -1,4 +1,5 @@ java/lang/EnumConstantNotPresentException::EnumConstantNotPresentException(Ljava/lang/Class;Ljava/lang/String;) +java/lang/Math::random() java/lang/Object::notify() java/lang/Object::notifyAll() java/lang/Object::toString() diff -Nru openjdk-21-21.0.12.1+1/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003.java openjdk-21-21.0.13+9/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003.java 2026-10-19 12:10:20.000000000 +0000 @@ -25,9 +25,10 @@ import java.io.File; import java.io.FileInputStream; import java.io.PrintStream; +import java.net.URI; +import java.nio.file.Path; +import java.security.CodeSource; import java.security.ProtectionDomain; -import java.util.regex.Pattern; -import java.util.regex.Matcher; import nsk.share.Consts; import nsk.share.test.Stresser; @@ -80,24 +81,12 @@ public static int run(String args[], PrintStream out) { - String testclasspath = System.getProperty("test.class.path"); - String [] testpaths = testclasspath.split(System.getProperty("path.separator")); - String classesDir = ""; - - Pattern pattern = Pattern.compile("^(.*)classes(.*)vmTestbase(.*)$"); - for (int i = 0 ; i < testpaths.length; i++) { - if (pattern.matcher(testpaths[i]).matches()) { - classesDir = testpaths[i]; - } - } - if (classesDir.equals("")) { - System.err.println("TEST BUG: Classes directory not found in test,class.path."); - return Consts.TEST_FAILED; - } Stresser stress = new Stresser(args); String className = Helper.class.getName(); - byte[] bloatBytes = fileBytes(classesDir + File.separator + className.replace('.', '/') + ".class"); + CodeSource classCodeSource = Helper.class.getProtectionDomain().getCodeSource(); + Path classFilePath = Path.of(URI.create(classCodeSource.getLocation().toString())); + byte[] bloatBytes = fileBytes(classFilePath.resolve(className.replace('.', '/') + ".class").toString()); int count = 0; Helper.resetExhaustedEvent(); diff -Nru openjdk-21-21.0.12.1+1/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java openjdk-21-21.0.13+9/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java --- openjdk-21-21.0.12.1+1/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jaxp/TEST.ROOT openjdk-21-21.0.13+9/test/jaxp/TEST.ROOT --- openjdk-21-21.0.12.1+1/test/jaxp/TEST.ROOT 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jaxp/TEST.ROOT 2026-10-19 12:10:20.000000000 +0000 @@ -23,7 +23,7 @@ groups=TEST.groups # Minimum jtreg version -requiredVersion=7.5.2+1 +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-21-21.0.12.1+1/test/jdk/ProblemList.txt openjdk-21-21.0.13+9/test/jdk/ProblemList.txt --- openjdk-21-21.0.12.1+1/test/jdk/ProblemList.txt 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -647,18 +646,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 - ############################################################################ # jdk_imageio diff -Nru openjdk-21-21.0.12.1+1/test/jdk/TEST.ROOT openjdk-21-21.0.13+9/test/jdk/TEST.ROOT --- openjdk-21-21.0.12.1+1/test/jdk/TEST.ROOT 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 @@ -115,7 +115,7 @@ jdk.foreign.linker # Minimum jtreg version -requiredVersion=7.5.2+1 +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-21-21.0.12.1+1/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java openjdk-21-21.0.13+9/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,160 @@ +/* + * 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.BufferedReader; +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 BufferedReader(new InputStreamReader(socket.getInputStream())); + var line = reader.lines().toList(); + 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-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/Test10.java openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/Test10.java --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/Test10.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/Test3.java openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/Test3.java --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/Test3.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/Test3.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -128,13 +128,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-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/Test4.java openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/Test4.java --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/Test4.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/Test4.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,13 +126,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-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/Test5.java openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/Test5.java --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/Test5.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/Test5.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,13 +125,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-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/bugs/B6361557.java openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/bugs/B6361557.java --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/bugs/B6361557.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/bugs/B6393710.java openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/bugs/B6393710.java --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/bugs/B6393710.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/bugs/B6433018.java openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/bugs/B6433018.java --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/bugs/B6433018.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestNoRead.policy openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestNoRead.policy --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestNoRead.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestNoRead.policy 2026-10-19 12:10:20.000000000 +0000 @@ -21,11 +21,6 @@ // questions. // -// for JTwork/classes/test/lib/jdk/test/lib/util/FileUtils.class -grant codeBase "file:${test.classes}/../../../../../../test/lib/-" { - permission java.util.PropertyPermission "*", "read"; -}; - grant codeBase "file:${test.classes}/*" { permission java.net.URLPermission "http://localhost:*/*", "GET"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestRead.policy openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestRead.policy --- openjdk-21-21.0.12.1+1/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestRead.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestRead.policy 2026-10-19 12:10:20.000000000 +0000 @@ -21,11 +21,6 @@ // questions. // -// for JTwork/classes/test/lib/jdk/test/lib/util/FileUtils.class -grant codeBase "file:${test.classes}/../../../../../../test/lib/-" { - permission java.util.PropertyPermission "*", "read"; -}; - grant codeBase "file:${test.classes}/*" { permission java.net.URLPermission "http://localhost:*/*", "GET"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/awt/Graphics2D/ClearPolyLineUsingXORTest.java openjdk-21-21.0.13+9/test/jdk/java/awt/Graphics2D/ClearPolyLineUsingXORTest.java --- openjdk-21-21.0.12.1+1/test/jdk/java/awt/Graphics2D/ClearPolyLineUsingXORTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java openjdk-21-21.0.13+9/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java --- openjdk-21-21.0.12.1+1/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java openjdk-21-21.0.13+9/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java --- openjdk-21-21.0.12.1+1/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java openjdk-21-21.0.13+9/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java --- openjdk-21-21.0.12.1+1/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java openjdk-21-21.0.13+9/test/jdk/java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java --- openjdk-21-21.0.12.1+1/test/jdk/java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,8 +30,7 @@ * @test * @key headful * @bug 8007156 8025126 - * @summary Extended key code is not set for a key event - * @author Alexandr Scherbatiy + * @summary Tests that ExtendedKeyCode is set for key events * @library /lib/client * @build ExtendedRobot * @run main ExtendedKeyCodeTest @@ -75,7 +74,8 @@ frame.dispose(); if (eventsCount != 2 || !setExtendedKeyCode) { - throw new RuntimeException("Wrong extended key code"); + throw new RuntimeException("Wrong extended key code\n" + + "eventsCount: " + eventsCount); } frame = new Frame(); diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/io/Serializable/records/ProhibitedMethods.java openjdk-21-21.0.13+9/test/jdk/java/io/Serializable/records/ProhibitedMethods.java --- openjdk-21-21.0.12.1+1/test/jdk/java/io/Serializable/records/ProhibitedMethods.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/io/Serializable/records/ProhibitedMethods.java 2026-10-19 12:10:20.000000000 +0000 @@ -295,7 +295,7 @@ MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, READ_OBJECT_NAME, READ_OBJECT_DESC, null, null); mv.visitCode(); mv.visitLdcInsn(READ_OBJECT_NAME + " should not be invoked"); - mv.visitMethodInsn(INVOKESTATIC, "org/testng/Assert", "fail", "(Ljava/lang/String;)V", false); + mv.visitMethodInsn(INVOKESTATIC, "org/junit/jupiter/api/Assertions", "fail", "(Ljava/lang/String;)Ljava/lang/Object;", false); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); @@ -314,7 +314,7 @@ MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, READ_OBJECT_NO_DATA_NAME, READ_OBJECT_NO_DATA_DESC, null, null); mv.visitCode(); mv.visitLdcInsn(READ_OBJECT_NO_DATA_NAME + " should not be invoked"); - mv.visitMethodInsn(INVOKESTATIC, "org/testng/Assert", "fail", "(Ljava/lang/String;)V", false); + mv.visitMethodInsn(INVOKESTATIC, "org/junit/jupiter/api/Assertions", "fail", "(Ljava/lang/String;)Ljava/lang/Object;", false); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); @@ -371,4 +371,5 @@ } } } -} \ No newline at end of file +} + diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/lang/ProcessBuilder/Basic.java openjdk-21-21.0.13+9/test/jdk/java/lang/ProcessBuilder/Basic.java --- openjdk-21-21.0.12.1+1/test/jdk/java/lang/ProcessBuilder/Basic.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/lang/ProcessBuilder/Basic.java 2026-10-19 12:10:20.000000000 +0000 @@ -699,7 +699,7 @@ public static String path() { return path; } private static final String path = path0(); private static String path0(){ - if (!Platform.isBusybox("/bin/true")) { + if (!Files.isSymbolicLink(Paths.get("/bin/true"))) { return "/bin/true"; } else { File trueExe = new File("true"); @@ -714,7 +714,7 @@ public static String path() { return path; } private static final String path = path0(); private static String path0(){ - if (!Platform.isBusybox("/bin/false")) { + if (!Files.isSymbolicLink(Paths.get("/bin/false"))) { return "/bin/false"; } else { File falseExe = new File("false"); diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/lang/ProcessHandle/InfoTest.java openjdk-21-21.0.13+9/test/jdk/java/lang/ProcessHandle/InfoTest.java --- openjdk-21-21.0.12.1+1/test/jdk/java/lang/ProcessHandle/InfoTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/lang/ProcessHandle/InfoTest.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, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -294,10 +294,12 @@ String expected = "sleep"; if (Platform.isWindows()) { expected = "sleep.exe"; - } else if (Platform.isBusybox("/bin/sleep")) { - // With busybox sleep is just a sym link to busybox. - // The busbox executable is seen as ProcessHandle.Info command. - expected = "busybox"; + } else if (Files.isSymbolicLink(Paths.get("/bin/sleep"))) { + // Busybox sleep is a symbolic link to /bin/busybox. + // Rust coreutils sleep is a symbolic link to coreutils + // The busbox/coreutils executables are seen as ProcessHandle.Info command. + Path executable = Files.readSymbolicLink(Paths.get("/bin/sleep")); + expected = executable.getFileName().toString(); } Assert.assertTrue(command.endsWith(expected), "Command: expected: \'" + expected + "\', actual: " + command); diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/IPSupport/MinimumPermissions.policy openjdk-21-21.0.13+9/test/jdk/java/net/IPSupport/MinimumPermissions.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/IPSupport/MinimumPermissions.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/IPSupport/MinimumPermissions.policy 2026-10-19 12:10:20.000000000 +0000 @@ -21,7 +21,7 @@ // questions. // -grant codeBase "file:${test.classes}/../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.net.SocketPermission "localhost:0", "listen,resolve"; permission java.util.PropertyPermission "java.net.preferIPv4Stack", "read"; permission java.util.PropertyPermission "java.net.preferIPv6Addresses", "read"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/AsFileDownloadTest.policy openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/AsFileDownloadTest.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/AsFileDownloadTest.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/AsFileDownloadTest.policy 2026-10-19 12:10:20.000000000 +0000 @@ -22,13 +22,13 @@ // // for JTwork/classes/0/test/lib/jdk/test/lib/net/SimpleSSLContext.class -grant codeBase "file:${test.classes}/../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "test.src.path", "read"; permission java.io.FilePermission "${test.src}/../../../../lib/jdk/test/lib/net/testkeys", "read"; }; // for classes in JTwork//classes/0/test/jdk/java/net/httpclient/lib/ -grant codeBase "file:${test.classes}/../../../../test/jdk/java/net/httpclient/lib/-" { +grant codeBase "file:${test.classes}/test/jdk/java/net/httpclient/lib/-" { permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.common"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.frame"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.hpack"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest1.policy openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest1.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest1.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest1.policy 2026-10-19 12:10:20.000000000 +0000 @@ -22,13 +22,13 @@ // // for JTwork/classes/0/test/lib/jdk/test/lib/net/SimpleSSLContext.class -grant codeBase "file:${test.classes}/../../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "test.src.path", "read"; permission java.io.FilePermission "${test.src}/../../../../../lib/jdk/test/lib/net/testkeys", "read"; }; // for jdk/httpclient/test/lib/* classes -grant codeBase "file:${test.classes}/../../../../../test/jdk/java/net/httpclient/lib/-" { +grant codeBase "file:${test.classes}/test/jdk/java/net/httpclient/lib/-" { permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.common"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.frame"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.hpack"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest2.policy openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest2.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest2.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest2.policy 2026-10-19 12:10:20.000000000 +0000 @@ -24,13 +24,13 @@ // same as FilePublisherPermsTest1.policy with custom permission for test classes // for JTwork/classes/0/test/lib/jdk/test/lib/net/SimpleSSLContext.class -grant codeBase "file:${test.classes}/../../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "test.src.path", "read"; permission java.io.FilePermission "${test.src}/../../../../../lib/jdk/test/lib/net/testkeys", "read"; }; // for jdk/httpclient/test/lib/* classes -grant codeBase "file:${test.classes}/../../../../../test/jdk/java/net/httpclient/lib/-" { +grant codeBase "file:${test.classes}/test/jdk/java/net/httpclient/lib/-" { permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.common"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.frame"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.hpack"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest3.policy openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest3.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest3.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/FilePublisher/FilePublisherPermsTest3.policy 2026-10-19 12:10:20.000000000 +0000 @@ -29,13 +29,13 @@ }; // for JTwork/classes/0/test/lib/jdk/test/lib/net/SimpleSSLContext.class -grant codeBase "file:${test.classes}/../../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "test.src.path", "read"; permission java.io.FilePermission "${test.src}/../../../../../lib/jdk/test/lib/net/testkeys", "read"; }; // for jdk/httpclient/test/lib/* classes -grant codeBase "file:${test.classes}/../../../../../test/jdk/java/net/httpclient/lib/-" { +grant codeBase "file:${test.classes}/test/jdk/java/net/httpclient/lib/-" { permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.common"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.frame"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.hpack"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/FilePublisher/FilePublisherTest.policy openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/FilePublisher/FilePublisherTest.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/FilePublisher/FilePublisherTest.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/FilePublisher/FilePublisherTest.policy 2026-10-19 12:10:20.000000000 +0000 @@ -22,13 +22,13 @@ // // for JTwork/classes/0/test/lib/jdk/test/lib/net/SimpleSSLContext.class -grant codeBase "file:${test.classes}/../../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "test.src.path", "read"; permission java.io.FilePermission "${test.src}/../../../../../lib/jdk/test/lib/net/testkeys", "read"; }; // for JTwork/classes/0/java/net/httpclient/http2/server/* -grant codeBase "file:${test.classes}/../../../../../test/jdk/java/net/httpclient/lib/-" { +grant codeBase "file:${test.classes}/test/jdk/java/net/httpclient/lib/-" { permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.common"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.frame"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.hpack"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/PathSubscriber/ofFile.policy openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/PathSubscriber/ofFile.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/PathSubscriber/ofFile.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/PathSubscriber/ofFile.policy 2026-10-19 12:10:20.000000000 +0000 @@ -22,7 +22,7 @@ // // for test/lib library classes -grant codeBase "file:${test.classes}/../../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "java.vm.info", "read"; permission java.util.PropertyPermission "jdk.debug", "read"; permission java.util.PropertyPermission "sun.arch.data.model", "read"; @@ -39,7 +39,7 @@ }; // for jdk/httpclient/test/lib/* classes -grant codeBase "file:${test.classes}/../../../../../test/jdk/java/net/httpclient/lib/-" { +grant codeBase "file:${test.classes}/test/jdk/java/net/httpclient/lib/-" { permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.common"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.frame"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.hpack"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/PathSubscriber/ofFileDownload.policy openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/PathSubscriber/ofFileDownload.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/PathSubscriber/ofFileDownload.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/PathSubscriber/ofFileDownload.policy 2026-10-19 12:10:20.000000000 +0000 @@ -22,7 +22,7 @@ // // for test/lib library classes -grant codeBase "file:${test.classes}/../../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "java.vm.info", "read"; permission java.util.PropertyPermission "jdk.debug", "read"; permission java.util.PropertyPermission "sun.arch.data.model", "read"; @@ -39,7 +39,7 @@ }; // for jdk/httpclient/test/lib/* classes -grant codeBase "file:${test.classes}/../../../../../test/jdk/java/net/httpclient/lib/-" { +grant codeBase "file:${test.classes}/test/jdk/java/net/httpclient/lib/-" { permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.common"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.frame"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.hpack"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/RequestBodyTest.policy openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/RequestBodyTest.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/RequestBodyTest.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/RequestBodyTest.policy 2026-10-19 12:10:20.000000000 +0000 @@ -22,19 +22,19 @@ // // for JTwork//classes/0/test/lib/jdk/test/lib/util/FileUtils.class -grant codeBase "file:${test.classes}/../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "*", "read"; permission java.io.FilePermission "RequestBodyTest.tmp", "read,delete"; }; // for JTwork/classes/0/test/lib/jdk/test/lib/net/SimpleSSLContext.class -grant codeBase "file:${test.classes}/../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "test.src.path", "read"; permission java.io.FilePermission "${test.src}/../../../../lib/jdk/test/lib/net/testkeys", "read"; }; // for jdk/httpclient/test/lib/* classes -grant codeBase "file:${test.classes}/../../../../test/jdk/java/net/httpclient/lib/-" { +grant codeBase "file:${test.classes}/test/jdk/java/net/httpclient/lib/-" { permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.common"; }; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/dependent.policy openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/dependent.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/dependent.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/dependent.policy 2026-10-19 12:10:20.000000000 +0000 @@ -22,13 +22,13 @@ // // for JTwork/classes/0/test/lib/jdk/test/lib/net/SimpleSSLContext.class -grant codeBase "file:${test.classes}/../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "test.src.path", "read"; permission java.io.FilePermission "${test.src}/../../../../lib/jdk/test/lib/net/testkeys", "read"; }; // for jdk/httpclient/test/lib/* classes -grant codeBase "file:${test.classes}/../../../../test/jdk/java/net/httpclient/lib/-" { +grant codeBase "file:${test.classes}/test/jdk/java/net/httpclient/lib/-" { permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.common"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.frame"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.hpack"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/httpclient-localaddr-security.policy openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/httpclient-localaddr-security.policy --- openjdk-21-21.0.12.1+1/test/jdk/java/net/httpclient/httpclient-localaddr-security.policy 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/net/httpclient/httpclient-localaddr-security.policy 2026-10-19 12:10:20.000000000 +0000 @@ -23,7 +23,7 @@ // for JTwork/classes/0/test/lib/jdk/test/lib/net/SimpleSSLContext.class and // JTwork/classes/0/test/lib/jdk/test/lib/net/IPSupport.class -grant codeBase "file:${test.classes}/../../../../test/lib/-" { +grant codeBase "file:${test.classes}/test/lib/-" { permission java.util.PropertyPermission "test.src.path", "read"; permission java.io.FilePermission "${test.src}/../../../../lib/jdk/test/lib/net/testkeys", "read"; permission java.util.PropertyPermission "java.net.preferIPv4Stack", "read"; @@ -31,7 +31,7 @@ }; // for classes in JTwork//classes/0/test/jdk/java/net/httpclient/lib/ -grant codeBase "file:${test.classes}/../../../../test/jdk/java/net/httpclient/lib/-" { +grant codeBase "file:${test.classes}/test/jdk/java/net/httpclient/lib/-" { permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.common"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.frame"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.net.http.hpack"; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java openjdk-21-21.0.13+9/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java --- openjdk-21-21.0.12.1+1/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java 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, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,18 +92,19 @@ // Write the data to a temporary file Path tempFile = Files.createTempFile("LargeGatheringWrite", ".dat"); - - printTime("before writing"); - System.out.printf("Writing %d bytes of data...%n", totalLength); - try (FileChannel fcw = FileChannel.open(tempFile, CREATE, WRITE);) { - // Print size of individual writes and total number written - long bytesWritten = 0; - long n; - while ((n = fcw.write(bigBuffers)) > 0) { - System.out.printf("Wrote %d bytes\n", n); - bytesWritten += n; + try { + printTime("before writing"); + System.out.printf("Writing %d bytes of data...%n", totalLength); + try (FileChannel fcw = FileChannel.open(tempFile, CREATE, WRITE);) { + // Print size of individual writes and total number written + long bytesWritten = 0; + long n; + while ((n = fcw.write(bigBuffers)) > 0) { + System.out.printf("Wrote %d bytes\n", n); + bytesWritten += n; + } + System.out.printf("Total of %d bytes written\n", bytesWritten); } - System.out.printf("Total of %d bytes written\n", bytesWritten); printTime("after writing"); // Verify the content written @@ -121,8 +122,13 @@ ByteBuffer dst = ByteBuffer.wrap(bytes).slice(0, length); if (dst.remaining() != length) throw new RuntimeException("remaining"); - if (fcr.read(dst) != length) - throw new RuntimeException("length"); + long totalRead = 0; + while (totalRead < length) { + int bytesRead = fcr.read(dst); + if (bytesRead < 0) + throw new RuntimeException("premature EOF"); + totalRead += bytesRead; + } dst.rewind(); // Verify that the bytes read from the file match the buffer diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/security/KeyAgreement/Generic.java openjdk-21-21.0.13+9/test/jdk/java/security/KeyAgreement/Generic.java --- openjdk-21-21.0.12.1+1/test/jdk/java/security/KeyAgreement/Generic.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/security/KeyAgreement/Generic.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8189441 + * @library /test/lib /test/jdk/sun/security/pkcs11 + * @summary make sure Generic is accepted by all KeyAgreement implementations + * @run main Generic builtin + * @run main/othervm Generic nss + * @run main/othervm -DCUSTOM_P11_CONFIG_NAME=p11-nss-sensitive.txt Generic nss + */ +import jdk.test.lib.Asserts; + +import javax.crypto.KeyAgreement; +import java.security.KeyPairGenerator; +import java.security.Provider; +import java.security.Security; +import java.util.List; + +public class Generic { + + public static void main(String[] args) throws Exception { + if (args[0].equals("nss")) { + test(PKCS11Test.getSunPKCS11(PKCS11Test.getNssConfig())); + } else { + for (var p : Security.getProviders()) { + test(p); + } + } + } + + static void test(Provider p) throws Exception { + for (var s : p.getServices()) { + if (s.getType().equalsIgnoreCase("KeyAgreement")) { + try { + System.out.println(s.getProvider().getName() + "." + s.getAlgorithm()); + var g = KeyPairGenerator.getInstance(ka2kpg(s.getAlgorithm()), p); + var kp1 = g.generateKeyPair(); + var kp2 = g.generateKeyPair(); + var ka = KeyAgreement.getInstance(s.getAlgorithm(), s.getProvider()); + for (var alg : List.of("TlsPremasterSecret", "Generic")) { + ka.init(kp1.getPrivate()); + ka.doPhase(kp2.getPublic(), true); + Asserts.assertEquals( + ka.generateSecret(alg).getAlgorithm(), alg); + } + } catch (Exception e) { + throw e; + } + } + } + } + + // Find key algorithm from KeyAgreement algorithm + private static String ka2kpg(String ka) { + return ka.equals("ECDH") ? "EC" : ka; + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/security/SignedJar/spi-calendar-provider/TestSPISigned.java openjdk-21-21.0.13+9/test/jdk/java/security/SignedJar/spi-calendar-provider/TestSPISigned.java --- openjdk-21-21.0.12.1+1/test/jdk/java/security/SignedJar/spi-calendar-provider/TestSPISigned.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/security/SignedJar/spi-calendar-provider/TestSPISigned.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 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 @@ -30,6 +31,7 @@ import java.util.Locale; import java.util.List; import java.util.ArrayList; +import java.net.URI; import java.nio.file.Paths; import java.nio.file.Path; import java.nio.file.Files; @@ -54,12 +56,9 @@ */ public class TestSPISigned { - private static final String TEST_CLASSES = System.getProperty("test.classes", "."); private static final String TEST_SRC = System.getProperty("test.src", "."); private static final Path META_INF_DIR = Paths.get(TEST_SRC, "provider", "meta"); - private static final Path PROVIDER_PARENT = Paths.get(TEST_CLASSES, ".."); - private static final Path PROVIDER_DIR = PROVIDER_PARENT.resolve("provider"); private static final Path MODS_DIR = Paths.get("mods"); private static final Path UNSIGNED_JAR = MODS_DIR.resolve("unsigned-with-locale.jar"); private static final Path SIGNED_JAR = MODS_DIR.resolve("signed-with-locale.jar"); @@ -81,7 +80,9 @@ // Set up signed jar with custom calendar data provider // // 1. Create jar with custom CalendarDataProvider - JarUtils.createJarFile(UNSIGNED_JAR, PROVIDER_DIR); + var codeSource = baz.CalendarDataProviderImpl.class.getProtectionDomain().getCodeSource(); + var providerDir = Path.of(URI.create(codeSource.getLocation().toString())); + JarUtils.createJarFile(UNSIGNED_JAR, providerDir); JarUtils.updateJarFile(UNSIGNED_JAR, META_INF_DIR); // create signer's keypair SecurityTools.keytool("-genkeypair -keyalg RSA -keystore ks " + diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/security/spec/TestNamedParameterSpec.java openjdk-21-21.0.13+9/test/jdk/java/security/spec/TestNamedParameterSpec.java --- openjdk-21-21.0.12.1+1/test/jdk/java/security/spec/TestNamedParameterSpec.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/security/spec/TestNamedParameterSpec.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,67 @@ +/* + * 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 8345057 + * @summary Test the existence of constants inside the + * java.security.spec.NamedParameterSpec class. + * @run main TestNamedParameterSpec + */ +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; +import java.util.TreeSet; + +public class TestNamedParameterSpec { + + // names of the static fields in NamedParameterSpec class + private static String[] EXPECTED = { + "ED25519", "ED448", "X25519", "X448", + }; + + public static void main(String[] args) throws Exception { + Arrays.sort(EXPECTED); + var actual = getSortedConstNames(NamedParameterSpec.class); + // both arrays should be sorted before comparison + if (Arrays.compare(EXPECTED, actual) != 0) { + System.out.println("expected: " + Arrays.toString(EXPECTED)); + System.out.println("actual: " + Arrays.toString(actual)); + throw new RuntimeException("Name check failed"); + } + System.out.println("Test Passed"); + } + + public static String[] getSortedConstNames(Class clazz) { + TreeSet names = new TreeSet(); + for (Field field : clazz.getDeclaredFields()) { + int mods = field.getModifiers(); + if (Modifier.isPublic(mods) && Modifier.isStatic(mods) + && Modifier.isFinal(mods)){ + names.add(field.getName()); + } + } + return names.toArray(new String[0]); + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java openjdk-21-21.0.13+9/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java --- openjdk-21-21.0.12.1+1/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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, 2022, 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,6 +54,7 @@ /* * @test * @bug 8081022 8151876 8166875 8177819 8189784 8206980 8277049 8278434 + * 8390388 8388214 8392519 8393344 * @key randomness */ @@ -61,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"), @@ -88,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-"))) { printText(locale, zdt, TextStyle.FULL, tz, tz.getID()); @@ -99,9 +124,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-21-21.0.12.1+1/test/jdk/java/time/test/java/time/zone/TestZoneRules.java openjdk-21-21.0.13+9/test/jdk/java/time/test/java/time/zone/TestZoneRules.java --- openjdk-21-21.0.12.1+1/test/jdk/java/time/test/java/time/zone/TestZoneRules.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/java/util/TimeZone/AIXTzMappingTest.java openjdk-21-21.0.13+9/test/jdk/java/util/TimeZone/AIXTzMappingTest.java --- openjdk-21-21.0.12.1+1/test/jdk/java/util/TimeZone/AIXTzMappingTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/java/util/TimeZone/Bug6329116.java openjdk-21-21.0.13+9/test/jdk/java/util/TimeZone/Bug6329116.java --- openjdk-21-21.0.12.1+1/test/jdk/java/util/TimeZone/Bug6329116.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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 8347841 + * 8388214 8392377 8393337 * @summary Make sure that timezone short display names are idenical to Olson's data. * @run junit/othervm -Djava.locale.providers=COMPAT,SPI Bug6329116 */ @@ -42,6 +43,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"); + static Locale[] locales = Locale.getAvailableLocales(); static String[] timezones = Arrays.stream(TimeZone.getAvailableIDs()) .filter(Predicate.not(ZoneId.SHORT_IDS::containsKey)) @@ -246,6 +259,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-21-21.0.12.1+1/test/jdk/java/util/TimeZone/CustomTzIDCheckDST.java openjdk-21-21.0.13+9/test/jdk/java/util/TimeZone/CustomTzIDCheckDST.java --- openjdk-21-21.0.12.1+1/test/jdk/java/util/TimeZone/CustomTzIDCheckDST.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/java/util/TimeZone/NegativeDSTTest.java openjdk-21-21.0.13+9/test/jdk/java/util/TimeZone/NegativeDSTTest.java --- openjdk-21-21.0.12.1+1/test/jdk/java/util/TimeZone/NegativeDSTTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/java/util/TimeZone/TimeZoneData/VERSION openjdk-21-21.0.13+9/test/jdk/java/util/TimeZone/TimeZoneData/VERSION --- openjdk-21-21.0.12.1+1/test/jdk/java/util/TimeZone/TimeZoneData/VERSION 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/util/TimeZone/TimeZoneData/VERSION 2026-10-19 12:10:20.000000000 +0000 @@ -1 +1 @@ -tzdata2026b +tzdata2026e diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt openjdk-21-21.0.13+9/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt --- openjdk-21-21.0.12.1+1/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt 2026-10-19 12:10:20.000000000 +0000 @@ -32,7 +32,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 @@ -50,7 +50,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 @@ -88,9 +88,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 diff -Nru openjdk-21-21.0.12.1+1/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java openjdk-21-21.0.13+9/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java --- openjdk-21-21.0.12.1+1/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.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 @@ -24,29 +24,25 @@ /* @test * @bug 8272746 * @summary Verify that ZipFile rejects files with CEN sizes exceeding the implementation limit - * @run testng/othervm EndOfCenValidation + * @library /test/lib + * @build jdk.test.lib.util.ZipUtils + * @run junit/othervm EndOfCenValidation */ -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; - -import java.io.*; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.FileChannel; -import java.nio.charset.StandardCharsets; +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.Files; import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; -import static org.testng.Assert.*; +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 @@ -60,44 +56,24 @@ 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 int MAX_CEN_SIZE = Integer.MAX_VALUE - ENDHDR - 1; - - // 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)"; - - // 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 - */ - @BeforeTest - public void setup() throws IOException { - zipBytes = templateZip(); - } + // Maximum allowed CEN size allowed by ZipFile + static final int MAX_CEN_SIZE = Integer.MAX_VALUE - ZipFile.ENDHDR - 1; /** * Delete big files after test, in case the file system did not support sparse files. * @throws IOException if an error occurs */ - @AfterTest + @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); } /** @@ -108,14 +84,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 = expectThrows(ZipException.class, () -> { - new ZipFile(zip.toFile()); - }); - - assertEquals(ex.getMessage(), INVALID_CEN_SIZE_TOO_LARGE); + verifyRejection(zip, INVALID_CEN_SIZE_TOO_LARGE); } /** @@ -126,16 +96,9 @@ */ @Test public void shouldRejectInvalidCenSize() throws IOException { - int size = MAX_CEN_SIZE; - Path zip = zipWithModifiedEndRecord(size, false, 0, INVALID_CEN_SIZE); - - ZipException ex = expectThrows(ZipException.class, () -> { - new ZipFile(zip.toFile()); - }); - - assertEquals(ex.getMessage(), INVALID_CEN_BAD_SIZE); + verifyRejection(zip, INVALID_CEN_BAD_SIZE); } /** @@ -146,93 +109,41 @@ */ @Test public void shouldRejectInvalidCenOffset() throws IOException { - int size = MAX_CEN_SIZE; - Path zip = zipWithModifiedEndRecord(size, true, 100, BAD_CEN_OFFSET_ZIP); - - ZipException ex = expectThrows(ZipException.class, () -> { - new ZipFile(zip.toFile()); - }); - - assertEquals(ex.getMessage(), INVALID_CEN_BAD_OFFSET); + verifyRejection(zip, INVALID_CEN_BAD_OFFSET); } /** - * 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 + * 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. * - * 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; + @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); } /** - * 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-21-21.0.12.1+1/test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java openjdk-21-21.0.13+9/test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java --- openjdk-21-21.0.12.1+1/test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml openjdk-21-21.0.13+9/test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml --- openjdk-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml openjdk-21-21.0.13+9/test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml --- openjdk-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml openjdk-21-21.0.13+9/test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml --- openjdk-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml openjdk-21-21.0.13+9/test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml --- openjdk-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml openjdk-21-21.0.13+9/test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml --- openjdk-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml openjdk-21-21.0.13+9/test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml --- openjdk-21-21.0.12.1+1/test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/javax/swing/SwingWorker/TestDoneBeforeDoInBackground.java openjdk-21-21.0.13+9/test/jdk/javax/swing/SwingWorker/TestDoneBeforeDoInBackground.java --- openjdk-21-21.0.12.1+1/test/jdk/javax/swing/SwingWorker/TestDoneBeforeDoInBackground.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java openjdk-21-21.0.13+9/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java openjdk-21-21.0.13+9/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java openjdk-21-21.0.13+9/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java openjdk-21-21.0.13+9/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java 2026-10-19 12:10:20.000000000 +0000 @@ -57,10 +57,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-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java openjdk-21-21.0.13+9/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java openjdk-21-21.0.13+9/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java openjdk-21-21.0.13+9/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java openjdk-21-21.0.13+9/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java openjdk-21-21.0.13+9/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java openjdk-21-21.0.13+9/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/jdk/jfr/event/gc/collection/TestGarbageCollectionEventWithZMinor.java 2026-10-19 12:10:20.000000000 +0000 @@ -41,7 +41,6 @@ * @test * @key jfr * @requires vm.hasJFR & vm.gc.ZGenerational - * @key jfr * @library /test/lib /test/jdk * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox diff -Nru openjdk-21-21.0.12.1+1/test/jdk/jdk/jfr/event/os/TestCPULoad.java openjdk-21-21.0.13+9/test/jdk/jdk/jfr/event/os/TestCPULoad.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/jfr/event/os/TestCPULoad.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/jdk/nio/zipfs/EndOfCenValidation.java openjdk-21-21.0.13+9/test/jdk/jdk/nio/zipfs/EndOfCenValidation.java --- openjdk-21-21.0.12.1+1/test/jdk/jdk/nio/zipfs/EndOfCenValidation.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java openjdk-21-21.0.13+9/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java --- openjdk-21-21.0.12.1+1/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java openjdk-21-21.0.13+9/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/security/ec/ECDHPrimitive.java openjdk-21-21.0.13+9/test/jdk/sun/security/ec/ECDHPrimitive.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/ec/ECDHPrimitive.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/ec/ECDHPrimitive.java 2026-10-19 12:10:20.000000000 +0000 @@ -118,7 +118,7 @@ byte[] secret = ka.generateSecret(); byte[] expectedSecret = values.get("ZIUT"); - Asserts.assertEqualsByteArray(secret, expectedSecret, "Incorrect secret value"); + Asserts.assertEqualsByteArray(expectedSecret, secret, "Incorrect secret value"); int testIndex = values.get("COUNT")[0]; System.out.println("Test " + testIndex + " passed."); } @@ -141,4 +141,4 @@ private static String lookupName(String name) { return NAME_MAP.get(name); } -} \ No newline at end of file +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/ec/ed/TestEdOps.java openjdk-21-21.0.13+9/test/jdk/sun/security/ec/ed/TestEdOps.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/ec/ed/TestEdOps.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/ec/ed/TestEdOps.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ import java.util.Arrays; import java.util.HexFormat; -import sun.security.provider.SHAKE256; +import sun.security.provider.SHA3.SHAKE256; public class TestEdOps { diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java openjdk-21-21.0.13+9/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt openjdk-21-21.0.13+9/test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt 2026-10-19 12:10:20.000000000 +0000 @@ -49,10 +49,12 @@ # Make all private keys sensitive attributes(*,CKO_PRIVATE_KEY,*) = { CKA_SENSITIVE = true + CKA_EXTRACTABLE = false } # Make all secret keys sensitive attributes(*,CKO_SECRET_KEY,*) = { CKA_SENSITIVE = true + CKA_EXTRACTABLE = false } diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java openjdk-21-21.0.13+9/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -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 @@ -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.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-21-21.0.12.1+1/test/jdk/sun/security/provider/MessageDigest/SHAKEhash.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/MessageDigest/SHAKEhash.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/MessageDigest/SHAKEhash.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/MessageDigest/SHAKEhash.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8354305 + * @summary Ensure SHAKE message digest algorithms behave the same + * as correspondent XOF of the same output size + * @library /test/lib + * @modules java.base/sun.security.provider + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.security.SeededSecureRandom; +import sun.security.provider.SHA3; + +import java.security.MessageDigest; + +public class SHAKEhash { + public static void main(String[] args) throws Exception { + var random = SeededSecureRandom.one(); + var s1 = new SHA3.SHAKE128(); + var m1 = MessageDigest.getInstance("SHAKE128-256"); // use standard name + var s2 = new SHA3.SHAKE256(); + var m2 = MessageDigest.getInstance("SHAKE256"); // use alias + for (var i = 0; i < 1_000_000; i++) { + var msg = random.nBytes(random.nextInt(100)); + s1.update(msg); + m1.update(msg); + Asserts.assertEqualsByteArray(s1.squeeze(32), m1.digest()); + s2.update(msg); + m2.update(msg); + Asserts.assertEqualsByteArray(s2.squeeze(64), m2.digest()); + s1.reset(); + s2.reset(); + } + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/MessageDigest/SHAKEsqueeze.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/MessageDigest/SHAKEsqueeze.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/MessageDigest/SHAKEsqueeze.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/MessageDigest/SHAKEsqueeze.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,102 @@ +/* + * 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 8338587 + * @summary Ensure squeeze and digest always have the same output + * @library /test/lib + * @modules java.base/sun.security.provider + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.security.SeededSecureRandom; +import sun.security.provider.SHA3; + +import java.io.ByteArrayOutputStream; +import java.util.Arrays; + +public class SHAKEsqueeze { + public static void main(String[] args) throws Exception { + resetFix(); + random(); + } + + static void resetFix() throws Exception { + var s = new SHA3.SHAKE256(); + var d1 = s.squeeze(10); + s.reset(); + Asserts.assertEqualsByteArray(d1, s.squeeze(10)); + } + + static void random() throws Exception { + var r = SeededSecureRandom.one(); + var atlast = 0; + // Random test on SHAKE + for (var i = 0; i < 1_000_000; i++) { + var s = new SHA3.SHAKE256(0); + var in = new ByteArrayOutputStream(); + while (r.nextBoolean()) { + var b = r.nBytes(r.nextInt(200)); + if (b.length > 0 && r.nextBoolean()) { + // Test update(b) + s.update(b[0]); + in.write(b[0]); + } else if (r.nextBoolean()) { + // Test update(byte[]) + s.update(b); + in.write(b); + } else { + // Test update(byte[], offset, len) + var prepend = r.nextInt(100); + var append = r.nextInt(100); + var bb = new byte[prepend + b.length + append]; + r.nextBytes(bb); + System.arraycopy(b, 0, bb, prepend, b.length); + s.update(bb, prepend, b.length); + in.write(b); + } + } + + // Squeeze for multiple times + var out = new ByteArrayOutputStream(); + do { + var n = r.nextInt(200); + out.write(s.squeeze(n)); + } while (out.size() == 0 || r.nextBoolean()); + var b1 = out.toByteArray(); + + // Digest for one time + var s2 = new SHA3.SHAKE256(b1.length); + s2.update(in.toByteArray()); + var b2 = s2.digest(); + + atlast = Arrays.hashCode(b2) * 17 + atlast; + Asserts.assertEqualsByteArray(b1, b2); + } + // Just to provide a visual clue to show that the same + // SeededSecureRandom seed results in same final result + // so that the test can be exactly reproduced. + System.out.println("Final hash: " + atlast); + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/acvp/Launcher.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/acvp/Launcher.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/acvp/Launcher.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/acvp/Launcher.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,210 @@ +/* + * 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. + */ + +import jdk.test.lib.artifacts.Artifact; +import jdk.test.lib.artifacts.ArtifactResolver; +import jdk.test.lib.json.JSONValue; +import jtreg.SkippedException; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.security.Provider; +import java.security.Security; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/* + * @test + * @bug 8342442 8345057 + * @library /test/lib + * @modules java.base/sun.security.provider + * java.base/sun.security.util + * java.base/com.sun.crypto.provider + * @run main/othervm/timeout=480 Launcher + */ + +/* + * @test + * @summary Test verifying the intrinsic implementation. + * @bug 8342442 8345057 + * @library /test/lib + * @modules java.base/sun.security.provider + * java.base/sun.security.util + * java.base/com.sun.crypto.provider + * @run main/othervm/timeout=480 -Xcomp Launcher + */ + +/// This test runs on `internalProjection.json`-style files generated by NIST's +/// ACVP Server ([GitHub repository](https://github.com/usnistgov/ACVP-Server)). +/// These files are included in ZIP archives available under the +/// [tags section](https://github.com/usnistgov/ACVP-Server/tags) +/// of the repository. +/// +/// The zip archive is either hosted on artifactory server or +/// specified with local path to the test. +/// The test looks for test data files in the archive listed with `TEST_FILES`. +/// +/// These tests are currently compatible with ACVP version 1.1.0.38. +/// +/// By default, the test uses system-preferred implementations. +/// If you want to test a specific provider, set the +/// `test.acvp.provider` test property. The provider must be +/// registered. +/// +/// Tests for each algorithm must be compliant to its specification linked from +/// [https://github.com/usnistgov/ACVP?tab=readme-ov-file#supported-algorithms]. +/// +/// Example: +/// +/// Run locally with ArtifactResolver +/// ``` +/// jtreg -Djdk.test.lib.artifacts.ACVP-Server= +/// ``` +/// OR host the zip archive on artifactory server. +/// + +public class Launcher { + + private static final Provider PROVIDER; + + private static final String ACVP_BUNDLE_LOC = "jpg.tests.jdk"; + private static final String ACVP_BUNDLE_NAME = "ACVP-Server"; + private static final String ACVP_BUNDLE_VERSION = "1.1.0.38"; + // Zip archive entry name, do not update to use File.separator + private static final String[] TEST_FILES = { + "gen-val/json-files/ML-DSA-keyGen-FIPS204/internalProjection.json", + "gen-val/json-files/ML-DSA-sigGen-FIPS204/internalProjection.json", + "gen-val/json-files/ML-DSA-sigVer-FIPS204/internalProjection.json", + "gen-val/json-files/ML-KEM-encapDecap-FIPS203/internalProjection.json", + "gen-val/json-files/ML-KEM-keyGen-FIPS203/internalProjection.json" + }; + + private static int count = 0; + private static int invalidTest = 0; + private static int unsupportedTest = 0; + + static { + var provProp = System.getProperty("test.acvp.provider"); + if (provProp != null) { + var p = Security.getProvider(provProp); + if (p == null) { + System.err.println(provProp + " is not a registered provider name"); + throw new RuntimeException(provProp + " is not a registered provider name"); + } + PROVIDER = p; + } else { + PROVIDER = null; + } + } + + public static void main(String[] args) throws Exception { + + Path archivePath = null; + try { + archivePath = ArtifactResolver.fetchOne(ACVP_SERVER_TESTS.class); + } catch (IOException e) { + if (e.getMessage().contains("Cannot find the artifact ACVP-Server")) { + throw new SkippedException("ACVP-Server not available."); + } + } + System.out.println("Data path: " + archivePath); + + if (PROVIDER != null) { + System.out.println("Provider: " + PROVIDER.getName()); + } + + // Read test data files from zip archive + try (ZipFile zf = new ZipFile(archivePath.toFile())) { + for (String testFile : TEST_FILES) { + // Zip archive entry name, do not update to use File.separator + String fullEntryName = ACVP_BUNDLE_NAME + "-" + ACVP_BUNDLE_VERSION + "/" + testFile; + System.out.println("Find and test with: " + fullEntryName); + ZipEntry ze = zf.getEntry(fullEntryName); + if (ze != null) { + run(zf.getInputStream(ze)); + } else { + throw new RuntimeException("Entry not found: " + fullEntryName); + } + } + } + + if (count > 0) { + System.out.println(); + System.out.println("Test completed: " + count); + System.out.println("Invalid tests: " + invalidTest); + System.out.println("Unsupported tests: " + unsupportedTest); + } else { + throw new RuntimeException("No supported test found"); + } + + if (invalidTest != 0 || unsupportedTest != 0){ + throw new RuntimeException("Invalid or Unsupported tests found"); + } + } + + static void run(InputStream test) { + try { + JSONValue kat; + try (test) { + kat = JSONValue.parse(new String(test.readAllBytes())); + } catch (Exception e) { + System.out.println("Warning: cannot parse " + test + ". Skipped"); + invalidTest++; + return; + } + var alg = kat.get("algorithm").asString(); + switch (alg) { + case "ML-DSA" -> { + ML_DSA_Test.run(kat, PROVIDER); + count++; + } + case "ML-KEM" -> { + ML_KEM_Test.run(kat, PROVIDER); + count++; + } + case "SHA2-256", "SHA2-224", "SHA3-256", "SHA3-224" -> { + SHA_Test.run(kat, PROVIDER); + count++; + } + default -> { + System.out.println("Skipped unsupported algorithm: " + alg); + unsupportedTest++; + } + } + } catch (RuntimeException re) { + throw re; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Artifact( + organization = ACVP_BUNDLE_LOC, + name = ACVP_BUNDLE_NAME, + revision = ACVP_BUNDLE_VERSION, + extension = "zip", + unpack = false) + private static class ACVP_SERVER_TESTS { + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,175 @@ +/* + * 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. + */ +import jdk.test.lib.Asserts; +import jdk.test.lib.json.JSONValue; +import jdk.test.lib.security.FixedSecureRandom; +import sun.security.provider.ML_DSA_Impls; +import sun.security.util.DerOutputStream; + +import java.security.*; +import java.security.spec.EncodedKeySpec; +import java.security.spec.NamedParameterSpec; + +import static jdk.test.lib.Utils.toByteArray; + +// JSON spec at https://pages.nist.gov/ACVP/draft-celi-acvp-ml-dsa.html +public class ML_DSA_Test { + + public static void run(JSONValue kat, Provider provider) throws Exception { + + var mode = kat.get("mode").asString(); + switch (mode) { + case "keyGen" -> keyGenTest(kat, provider); + case "sigGen" -> sigGenTest(kat, provider); + case "sigVer" -> sigVerTest(kat, provider); + default -> throw new UnsupportedOperationException("Unknown mode: " + mode); + } + } + + static NamedParameterSpec genParams(String pname) { + return switch (pname) { + case "ML-DSA-44" -> new NamedParameterSpec(pname); + case "ML-DSA-65" -> new NamedParameterSpec(pname); + case "ML-DSA-87" -> new NamedParameterSpec(pname); + default -> throw new RuntimeException("Unknown params: " + pname); + + }; + } + + static void keyGenTest(JSONValue kat, Provider p) throws Exception { + var g = p == null + ? KeyPairGenerator.getInstance("ML-DSA") + : KeyPairGenerator.getInstance("ML-DSA", p); + var f = p == null + ? KeyFactory.getInstance("ML-DSA") + : KeyFactory.getInstance("ML-DSA", p); + for (var t : kat.get("testGroups").asArray()) { + var pname = t.get("parameterSet").asString(); + var np = genParams(pname); + System.out.println(">> " + pname); + for (var c : t.get("tests").asArray()) { + System.out.print(c.get("tcId").asString() + " "); + var seed = toByteArray(c.get("seed").asString()); + g.initialize(np, new FixedSecureRandom(seed)); + var kp = g.generateKeyPair(); + var pk = f.getKeySpec(kp.getPublic(), EncodedKeySpec.class).getEncoded(); + Asserts.assertEqualsByteArray(toByteArray(c.get("pk").asString()), pk); + Asserts.assertEqualsByteArray(toByteArray(c.get("sk").asString()), + ML_DSA_Impls.seedToExpanded(pname, seed)); + } + System.out.println(); + } + } + + static void sigGenTest(JSONValue kat, Provider p) throws Exception { + var s = p == null + ? Signature.getInstance("ML-DSA") + : Signature.getInstance("ML-DSA", p); + 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()); + 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")) { + continue; // Not supported + } + for (var c : t.get("tests").asArray()) { + var cstr = c.get("context"); + var ctxt = cstr == null ? new byte[0] : toByteArray(cstr.asString()); + var hashAlg = c.get("hashAlg").asString(); + if (!hashAlg.equals("none") || ctxt.length != 0) { + continue; // Not supported + } + System.out.print(Integer.parseInt(c.get("tcId").asString()) + " "); + var sk = new PrivateKey() { + public String getAlgorithm() { return pname; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return oct(toByteArray(c.get("sk").asString())); } + }; + var sr = new FixedSecureRandom( + det ? new byte[32] : toByteArray(c.get("rnd").asString())); + s.initSign(sk, sr); + s.update(toByteArray(c.get("message").asString())); + var sig = s.sign(); + Asserts.assertEqualsByteArray( + toByteArray(c.get("signature").asString()), sig); + } + System.out.println(); + } + } + + static byte[] oct(byte[] in) { + return new DerOutputStream().putOctetString(in).toByteArray(); + } + + static void sigVerTest(JSONValue kat, Provider p) throws Exception { + var s = p == null + ? Signature.getInstance("ML-DSA") + : Signature.getInstance("ML-DSA", p); + for (var t : kat.get("testGroups").asArray()) { + var pname = t.get("parameterSet").asString(); + System.out.println(">> " + pname + " verify"); + + 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")) { + continue; // Not supported + } + + for (var c : t.get("tests").asArray()) { + var cstr = c.get("context"); + var ctxt = cstr == null ? new byte[0] : toByteArray(cstr.asString()); + var hashAlg = c.get("hashAlg").asString(); + if (!hashAlg.equals("none") || ctxt.length != 0) { + continue; // Not supported + } + System.out.print(c.get("tcId").asString() + " "); + var pk = new PublicKey() { + public String getAlgorithm() { return pname; } + public String getFormat() { return "RAW"; } + 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 actual = true; + try { + s.initVerify(pk); + s.update(toByteArray(c.get("message").asString())); + actual = s.verify(toByteArray(c.get("signature").asString())); + } catch (InvalidKeyException | SignatureException e) { + actual = false; + } + Asserts.assertEQ(expected, actual); + } + System.out.println(); + } + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,128 @@ +/* + * 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. + */ +import com.sun.crypto.provider.ML_KEM_Impls; +import jdk.test.lib.Asserts; +import jdk.test.lib.json.JSONValue; +import jdk.test.lib.security.FixedSecureRandom; +import sun.security.util.DerOutputStream; + +import javax.crypto.KEM; +import java.security.*; +import java.security.spec.EncodedKeySpec; +import java.security.spec.NamedParameterSpec; + +import static jdk.test.lib.Utils.toByteArray; + +// JSON spec at https://pages.nist.gov/ACVP/draft-celi-acvp-ml-kem.html +public class ML_KEM_Test { + + public static void run(JSONValue kat, Provider provider) throws Exception { + var mode = kat.get("mode").asString(); + switch (mode) { + case "keyGen" -> keyGenTest(kat, provider); + case "encapDecap" -> encapDecapTest(kat, provider); + default -> throw new UnsupportedOperationException("Unknown mode: " + mode); + } + } + + static NamedParameterSpec genParams(String pname) { + return switch (pname) { + case "ML-KEM-512" -> new NamedParameterSpec(pname); + case "ML-KEM-768" -> new NamedParameterSpec(pname); + case "ML-KEM-1024" -> new NamedParameterSpec(pname); + default -> throw new RuntimeException("Unknown params: " + pname); + }; + } + + static void keyGenTest(JSONValue kat, Provider p) throws Exception { + var g = p == null + ? KeyPairGenerator.getInstance("ML-KEM") + : KeyPairGenerator.getInstance("ML-KEM", p); + var f = p == null + ? KeyFactory.getInstance("ML-KEM") + : KeyFactory.getInstance("ML-KEM", p); + for (var t : kat.get("testGroups").asArray()) { + var pname = t.get("parameterSet").asString(); + var np = genParams(pname); + System.out.println(">> " + pname); + for (var c : t.get("tests").asArray()) { + System.out.print(c.get("tcId").asString() + " "); + var seed = toByteArray(c.get("d").asString() + c.get("z").asString()); + g.initialize(np, new FixedSecureRandom(seed)); + var kp = g.generateKeyPair(); + var pk = f.getKeySpec(kp.getPublic(), EncodedKeySpec.class).getEncoded(); + Asserts.assertEqualsByteArray(toByteArray(c.get("ek").asString()), pk); + Asserts.assertEqualsByteArray( + toByteArray(c.get("dk").asString()), + ML_KEM_Impls.seedToExpanded(pname, seed)); + } + System.out.println(); + } + } + + static void encapDecapTest(JSONValue kat, Provider p) throws Exception { + var g = p == null + ? KEM.getInstance("ML-KEM") + : KEM.getInstance("ML-KEM", p); + for (var t : kat.get("testGroups").asArray()) { + var pname = t.get("parameterSet").asString(); + var function = t.get("function").asString(); + System.out.println(">> " + pname + " " + function); + if (function.equals("encapsulation")) { + for (var c : t.get("tests").asArray()) { + System.out.print(c.get("tcId").asString() + " "); + var ek = new PublicKey() { + public String getAlgorithm() { return pname; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return toByteArray(c.get("ek").asString()); } + }; + var e = g.newEncapsulator( + ek, new FixedSecureRandom(toByteArray(c.get("m").asString()))); + var enc = e.encapsulate(); + Asserts.assertEqualsByteArray( + toByteArray(c.get("c").asString()), enc.encapsulation()); + Asserts.assertEqualsByteArray( + toByteArray(c.get("k").asString()), enc.key().getEncoded()); + } + System.out.println(); + } else if (function.equals("decapsulation")) { + var dk = new PrivateKey() { + public String getAlgorithm() { return pname; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return oct(toByteArray(t.get("dk").asString())); } + }; + for (var c : t.get("tests").asArray()) { + System.out.print(c.get("tcId").asString() + " "); + var d = g.newDecapsulator(dk); + var k = d.decapsulate(toByteArray(c.get("c").asString())); + Asserts.assertEqualsByteArray(toByteArray(c.get("k").asString()), k.getEncoded()); + } + System.out.println(); + } + } + } + + static byte[] oct(byte[] in) { + return new DerOutputStream().putOctetString(in).toByteArray(); + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/acvp/SHA_Test.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/acvp/SHA_Test.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/acvp/SHA_Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/acvp/SHA_Test.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,139 @@ +/* + * 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. + */ +import jdk.test.lib.Asserts; +import jdk.test.lib.json.JSONValue; + +import java.security.*; +import java.util.Arrays; + +import static jdk.test.lib.Utils.toByteArray; + +// JSON spec at https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html +// and https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html +public class SHA_Test { + + public static void run(JSONValue kat, Provider provider) throws Exception { + var alg = kat.get("algorithm").asString(); + if (alg.startsWith("SHA2-")) alg = "SHA-" + alg.substring(5); + var md = provider == null ? MessageDigest.getInstance(alg) + : MessageDigest.getInstance(alg, provider); + for (var t : kat.get("testGroups").asArray()) { + var testType = t.get("testType").asString(); + switch (testType) { + case "AFT" -> { + for (var c : t.get("tests").asArray()) { + System.out.print(c.get("tcId").asString() + " "); + var msg = toByteArray(c.get("msg").asString()); + var len = Integer.parseInt(c.get("len").asString()); + if (msg.length * 8 == len) { + Asserts.assertEqualsByteArray( + toByteArray(c.get("md").asString()), md.digest(msg)); + } else { + System.out.print("bits "); + } + } + } + case "MCT" -> { + var mctVersion = t.get("mctVersion").asString(); + var trunc = mctVersion.equals("alternate"); + for (var c : t.get("tests").asArray()) { + System.out.print(c.get("tcId").asString() + " "); + var SEED = toByteArray(c.get("msg").asString()); + var INITIAL_SEED_LENGTH = Integer.parseInt(c.get("len").asString()); + if (SEED.length * 8 == INITIAL_SEED_LENGTH) { + for (var r : c.get("resultsArray").asArray()) { + if (alg.startsWith("SHA3-")) { + var MD = SEED; + for (var i = 0; i < 1000; i++) { + if (trunc) { + MD = Arrays.copyOf(MD, INITIAL_SEED_LENGTH / 8); + } + MD = md.digest(MD); + } + Asserts.assertEqualsByteArray( + toByteArray(r.get("md").asString()), MD); + SEED = MD; + } else { + var A = SEED; + var B = SEED; + var C = SEED; + byte[] MD = null; + for (var i = 0; i < 1000; i++) { + var MSG = concat(A, B, C); + if (trunc) { + MSG = Arrays.copyOf(MSG, INITIAL_SEED_LENGTH / 8); + } + MD = md.digest(MSG); + A = B; + B = C; + C = MD; + } + Asserts.assertEqualsByteArray( + toByteArray(r.get("md").asString()), MD); + SEED = MD; + } + } + } else { + System.out.print("bits "); + } + } + } + case "LDT" -> { + for (var c : t.get("tests").asArray()) { + System.out.print(c.get("tcId").asString() + " "); + var lm = c.get("largeMsg"); + var ct = toByteArray(lm.get("content").asString()); + var flen = Long.parseLong(lm.get("fullLength").asString()); + var clen = Long.parseLong(lm.get("contentLength").asString()); + var cc = 0L; + while (cc < flen) { + md.update(ct); + cc += clen; + } + Asserts.assertEqualsByteArray( + toByteArray(c.get("md").asString()), md.digest()); + } + } + default -> throw new UnsupportedOperationException( + "Unknown testType: " + testType); + } + System.out.println(); + } + } + + ///////////// + + static byte[] concat(byte[]... input) { + var sum = 0; + for (var i : input) { + sum += i.length; + } + var out = new byte[sum]; + sum = 0; + for (var i : input) { + System.arraycopy(i, 0, out, sum, i.length); + sum += i.length; + } + return out; + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/all/Deterministic.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/all/Deterministic.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/all/Deterministic.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/all/Deterministic.java 2026-10-19 12:10:20.000000000 +0000 @@ -212,6 +212,8 @@ case "EC" -> 256; case "EdDSA", "Ed25519", "XDH", "X25519" -> 255; case "Ed448", "X448" -> 448; + case "ML-KEM", "ML-KEM-768", "ML-KEM-512", "ML-KEM-1024", + "ML-DSA", "ML-DSA-44", "ML-DSA-65", "ML-DSA-87" -> -1; default -> throw new UnsupportedOperationException(alg); }; g.initialize(size, new SeededSecureRandom(SEED + offset)); diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/named/NamedEdDSA.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/named/NamedEdDSA.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/named/NamedEdDSA.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/named/NamedEdDSA.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8340327 8347938 + * @modules jdk.crypto.ec/sun.security.ec.ed + * jdk.crypto.ec/sun.security.ec.point + * java.base/sun.security.jca + * java.base/sun.security.provider + * java.base/sun.security.util + * @library /test/lib + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.security.ec.ed.EdDSAOperations; +import sun.security.ec.ed.EdDSAParameters; +import sun.security.ec.point.AffinePoint; +import sun.security.jca.JCAUtil; +import sun.security.provider.NamedKeyFactory; +import sun.security.provider.NamedKeyPairGenerator; +import sun.security.provider.NamedSignature; +import sun.security.util.DerOutputStream; +import sun.security.util.DerValue; + +import java.io.IOException; +import java.security.*; +import java.security.spec.EdDSAParameterSpec; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; +import java.util.List; + +public class NamedEdDSA { + + public static class ProviderImpl extends Provider { + public ProviderImpl() { + super("Named", "0", ""); + put("KeyPairGenerator.EdDSA", EdDSAKeyPairGenerator.class.getName()); + put("KeyPairGenerator.Ed25519", EdDSAKeyPairGenerator.Ed25519.class.getName()); + put("KeyPairGenerator.Ed448", EdDSAKeyPairGenerator.Ed448.class.getName()); + put("KeyFactory.EdDSA", EdDSAKeyFactory.class.getName()); + put("KeyFactory.Ed25519", EdDSAKeyFactory.Ed25519.class.getName()); + put("KeyFactory.Ed448", EdDSAKeyFactory.Ed448.class.getName()); + put("Signature.EdDSA", EdDSASignature.class.getName()); + put("Signature.Ed25519", EdDSASignature.Ed25519.class.getName()); + put("Signature.Ed448", EdDSASignature.Ed448.class.getName()); + } + } + + public static class EdDSASignature extends NamedSignature { + public EdDSASignature() { + super("EdDSA", new EdDSAKeyFactory()); + } + + protected EdDSASignature(String pname) { + super("EdDSA", new EdDSAKeyFactory(pname)); + } + + public static class Ed25519 extends EdDSASignature { + public Ed25519() { + super("Ed25519"); + } + } + + public static class Ed448 extends EdDSASignature { + public Ed448() { + super("Ed448"); + } + } + + @Override + public byte[] implSign(String pname, byte[] sk, Object sk2, byte[] msg, SecureRandom sr) { + return getOps(pname).sign(plain, sk, msg); + } + + @Override + public boolean implVerify(String pname, byte[] pk, Object pk2, byte[] msg, byte[] sig) throws SignatureException { + return getOps(pname).verify(plain, (AffinePoint) pk2, pk, msg, sig); + } + + @Override + public Object implCheckPublicKey(String pname, byte[] pk) throws InvalidKeyException { + return getOps(pname).decodeAffinePoint(InvalidKeyException::new, pk); + } + } + + public static class EdDSAKeyFactory extends NamedKeyFactory { + @Override + protected byte[] implExpand(String pname, byte[] input) + throws InvalidKeyException { + try { + return new DerValue(input).getOctetString(); + } catch (IOException e) { + throw new InvalidKeyException(e); + } + } + + public EdDSAKeyFactory() { + super("EdDSA", "Ed25519", "Ed448"); + } + + protected EdDSAKeyFactory(String pname) { + super("EdDSA", pname); + } + + public static class Ed25519 extends EdDSAKeyFactory { + public Ed25519() { + super("Ed25519"); + } + } + + public static class Ed448 extends EdDSAKeyFactory { + public Ed448() { + super("Ed448"); + } + } + } + + public static class EdDSAKeyPairGenerator extends NamedKeyPairGenerator { + public EdDSAKeyPairGenerator() { + super("EdDSA", "Ed25519", "Ed448"); + } + + protected EdDSAKeyPairGenerator(String pname) { + super("EdDSA", pname); + } + + public static class Ed25519 extends EdDSAKeyPairGenerator { + public Ed25519() { + super("Ed25519"); + } + } + + public static class Ed448 extends EdDSAKeyPairGenerator { + public Ed448() { + super("Ed448"); + } + } + + @Override + public byte[][] implGenerateKeyPair(String pname, SecureRandom sr) { + sr = sr == null ? JCAUtil.getDefSecureRandom() : sr; + var op = getOps(pname); + var sk = op.generatePrivate(sr); + var point = op.computePublic(sk); + byte[] encodedPoint = point.getY().toByteArray(); + reverse(encodedPoint); + // array may be too large or too small, depending on the value + encodedPoint = Arrays.copyOf(encodedPoint, op.getParameters().getKeyLength()); + // set the high-order bit of the encoded point + byte msb = (byte) (point.isXOdd() ? 0x80 : 0); + encodedPoint[encodedPoint.length - 1] |= msb; + return new byte[][] { + encodedPoint, + new DerOutputStream().putOctetString(sk).toByteArray(), + sk}; + } + + private static void swap(byte[] arr, int i, int j) { + byte tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } + + private static void reverse(byte [] arr) { + int i = 0; + int j = arr.length - 1; + + while (i < j) { + swap(arr, i, j); + i++; + j--; + } + } + } + + private static EdDSAOperations getOps(String pname) { + var op = switch (pname) { + case "Ed25519" -> e2; + case "Ed448" -> e4; + default -> throw new AssertionError("unknown pname " + pname); + }; + return op; + } + + static final EdDSAParameterSpec plain = new EdDSAParameterSpec(false); + static final EdDSAOperations e2, e4; + static { + try { + e2 = new EdDSAOperations(EdDSAParameters.getBySize(AssertionError::new, 255)); + e4 = new EdDSAOperations(EdDSAParameters.getBySize(AssertionError::new, 448)); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + public static void main(String[] args) throws Exception { + var ps = List.of(new ProviderImpl(), Security.getProvider("SunEC")); + for (var p1 : ps) { + for (var p2 : ps) { + for (var p3 : ps) { + test(p1, p2, p3); + } + } + } + } + + static void test(Provider p1, Provider p2, Provider p3) throws Exception { + System.out.println(p1.getName() + " " + p2.getName() + " " + p3.getName()); + var g = KeyPairGenerator.getInstance("EdDSA", p1); + g.initialize(NamedParameterSpec.ED448); + var kp = g.generateKeyPair(); + var s1 = Signature.getInstance("EdDSA", p2); + var s2 = Signature.getInstance("EdDSA", p3); + var f1 = KeyFactory.getInstance("EdDSA", p2); + var f2 = KeyFactory.getInstance("EdDSA", p3); + var sk = (PrivateKey) f1.translateKey(kp.getPrivate()); + var pk = (PublicKey) f2.translateKey(kp.getPublic()); + // sign and verify twice to make sure the key is intact + s1.initSign(sk); + var sig1 = s1.sign(); + s1.initSign(sk); + var sig2 = s1.sign(); + // EdDSA signing is deterministic + Asserts.assertEqualsByteArray(sig1, sig2); + s2.initVerify(pk); + Asserts.assertTrue(s2.verify(sig1)); + s2.initVerify(pk); + Asserts.assertTrue(s2.verify(sig2)); + // No parameters defined + s1.setParameter(null); + Utils.runAndCheckException(() -> s1.setParameter(NamedParameterSpec.ED448), + InvalidAlgorithmParameterException.class); + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/named/NamedKeyFactoryTest.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/named/NamedKeyFactoryTest.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/named/NamedKeyFactoryTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/named/NamedKeyFactoryTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=plainTest + * @bug 8340327 8347938 + * @modules java.base/sun.security.x509 + * java.base/sun.security.pkcs + * java.base/sun.security.provider + * java.base/sun.security.util + * @library /test/lib + */ + +/* + * @test id=securityManager + * @bug 8340327 + * @modules java.base/sun.security.x509 + * java.base/sun.security.pkcs + * java.base/sun.security.provider + * java.base/sun.security.util + * @library /test/lib + * @run main/othervm/policy=namedKeyFactoryTest.policy NamedKeyFactoryTest + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import jdk.test.lib.security.SeededSecureRandom; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.provider.NamedKeyFactory; +import sun.security.provider.NamedKeyPairGenerator; +import sun.security.util.KeyUtil; +import sun.security.util.RawKeySpec; +import sun.security.x509.NamedX509Key; + +import java.security.*; +import java.security.spec.*; +import java.util.Arrays; + +public class NamedKeyFactoryTest { + + private static final SeededSecureRandom RAND = SeededSecureRandom.one(); + private static final byte[] RAW_SK = RAND.nBytes(16); + private static final byte[] RAW_PK = RAND.nBytes(16); + + public static void main(String[] args) throws Exception { + Security.addProvider(new ProviderImpl()); + + var g = KeyPairGenerator.getInstance("sHA"); + var g2 = KeyPairGenerator.getInstance("ShA-256"); + var g5 = KeyPairGenerator.getInstance("SHa-512"); + var kf = KeyFactory.getInstance("ShA"); + var kf2 = KeyFactory.getInstance("Sha-256"); + var kf5 = KeyFactory.getInstance("Sha-512"); + + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g2.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g5.generateKeyPair(), "SHA", "SHA-512"); + + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g2.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g5.generateKeyPair(), "SHA", "SHA-512"); + + Utils.runAndCheckException(() -> g.initialize(NamedParameterSpec.ED448), + InvalidAlgorithmParameterException.class); // wrong pname + Utils.runAndCheckException(() -> g.initialize(new NamedParameterSpec("SHA-384")), + InvalidAlgorithmParameterException.class); // wrong pname + + Utils.runAndCheckException(() -> g5.initialize(new NamedParameterSpec("SHA-256")), + InvalidAlgorithmParameterException.class); // diff pname + g5.initialize(new NamedParameterSpec("SHA-512")); + + g.initialize(new NamedParameterSpec("sHA-512")); + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-512"); + g.initialize(new NamedParameterSpec("ShA-256")); + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-256"); + + var pk = new NamedX509Key("sHa", "ShA-256", RAW_PK); + var sk = NamedPKCS8Key.internalCreate("sHa", "SHa-256", RAW_SK, null); + checkKey(pk, "sHa", "ShA-256"); + checkKey(sk, "sHa", "SHa-256"); + + Asserts.assertEquals("X.509", pk.getFormat()); + Asserts.assertEquals("PKCS#8", sk.getFormat()); + + var pkSpec = kf.getKeySpec(pk, X509EncodedKeySpec.class); + var skSpec = kf.getKeySpec(sk, PKCS8EncodedKeySpec.class); + + kf2.getKeySpec(pk, X509EncodedKeySpec.class); + kf2.getKeySpec(sk, PKCS8EncodedKeySpec.class); + Utils.runAndCheckException(() -> kf5.getKeySpec(pk, X509EncodedKeySpec.class), + InvalidKeySpecException.class); // wrong KF + Utils.runAndCheckException(() -> kf5.getKeySpec(sk, PKCS8EncodedKeySpec.class), + InvalidKeySpecException.class); + Utils.runAndCheckException(() -> kf.getKeySpec(pk, PKCS8EncodedKeySpec.class), + InvalidKeySpecException.class); // wrong KeySpec + Utils.runAndCheckException(() -> kf.getKeySpec(sk, X509EncodedKeySpec.class), + InvalidKeySpecException.class); + + checkKey(kf.generatePublic(pkSpec), "SHA", "SHA-256"); + Utils.runAndCheckException(() -> kf.generatePrivate(pkSpec), + InvalidKeySpecException.class); + + checkKey(kf.generatePrivate(skSpec), "SHA", "SHA-256"); + Utils.runAndCheckException(() -> kf.generatePublic(skSpec), + InvalidKeySpecException.class); + + checkKey(kf2.generatePrivate(skSpec), "SHA", "SHA-256"); + checkKey(kf2.generatePublic(pkSpec), "SHA", "SHA-256"); + + Utils.runAndCheckException(() -> kf5.generatePublic(pkSpec), + InvalidKeySpecException.class); // wrong KF + Utils.runAndCheckException(() -> kf5.generatePublic(skSpec), + InvalidKeySpecException.class); + + // The private RawKeySpec and unnamed RAW EncodedKeySpec + var prk = kf.getKeySpec(pk, RawKeySpec.class); + Asserts.assertEqualsByteArray(prk.getKeyArr(), pk.getRawBytes()); + var prk2 = kf.getKeySpec(pk, EncodedKeySpec.class); + Asserts.assertEquals("RAW", prk2.getFormat()); + Asserts.assertEqualsByteArray(prk.getKeyArr(), prk2.getEncoded()); + + Asserts.assertEqualsByteArray(kf2.generatePublic(prk).getEncoded(), pk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePublic(prk), InvalidKeySpecException.class); // no pname + Asserts.assertEqualsByteArray(kf2.generatePublic(prk2).getEncoded(), pk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePublic(prk2), InvalidKeySpecException.class); // no pname + + var srk = kf.getKeySpec(sk, RawKeySpec.class); + Asserts.assertEqualsByteArray(srk.getKeyArr(), sk.getRawBytes()); + var srk2 = kf.getKeySpec(sk, EncodedKeySpec.class); + Asserts.assertEquals("RAW", srk2.getFormat()); + Asserts.assertEqualsByteArray(srk2.getEncoded(), sk.getRawBytes()); + + checkKey(kf2.generatePrivate(srk), "SHA", "SHA-256"); + Asserts.assertEqualsByteArray(kf2.generatePrivate(srk).getEncoded(), sk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePrivate(srk), InvalidKeySpecException.class); // no pname + checkKey(kf2.generatePrivate(srk), "SHA", "SHA-256"); + Asserts.assertEqualsByteArray(kf2.generatePrivate(srk2).getEncoded(), sk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePrivate(srk2), InvalidKeySpecException.class); // no pname + + var pk1 = new PublicKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAW_PK; } + }; + var pk2 = new PublicKey() { + public String getAlgorithm() { return "sHA-256"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAW_PK; } + }; + var pk3 = new PublicKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAW_PK; } + public AlgorithmParameterSpec getParams() { return new NamedParameterSpec("sHA-256"); } + }; + + checkKey(kf2.translateKey(pk1), "SHA", "SHA-256"); + checkKey(kf.translateKey(pk2), "SHA", "SHA-256"); + checkKey(kf.translateKey(pk3), "SHA", "SHA-256"); + + Utils.runAndCheckException(() -> kf.translateKey(pk1), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(pk2), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(pk3), InvalidKeyException.class); + + var sk1 = new PrivateKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAW_SK; } + }; + var sk2 = new PrivateKey() { + public String getAlgorithm() { return "sHA-256"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAW_SK; } + }; + var sk3 = new PrivateKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAW_SK; } + public AlgorithmParameterSpec getParams() { return new NamedParameterSpec("sHA-256"); } + }; + + checkKey(kf2.translateKey(sk1), "SHA", "SHA-256"); + checkKey(kf.translateKey(sk2), "SHA", "SHA-256"); + checkKey(kf.translateKey(sk3), "SHA", "SHA-256"); + + Utils.runAndCheckException(() -> kf.translateKey(sk1), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(sk2), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(sk3), InvalidKeyException.class); + } + + static void checkKeyPair(KeyPair kp, String algName, String toString) { + checkKey(kp.getPrivate(), algName, toString); + checkKey(kp.getPublic(), algName, toString); + } + + static void checkKey(Key k, String algName, String pname) { + Asserts.assertEquals(algName, k.getAlgorithm()); + Asserts.assertTrue(k.toString().contains(pname)); + if ((k instanceof PrivateKey || k instanceof PublicKey) && KeyUtil.getParams(k) instanceof NamedParameterSpec nps) { + Asserts.assertEquals(pname, nps.getName()); + } + if (k instanceof NamedPKCS8Key nsk) { + var raw = nsk.getRawBytes(); + Asserts.assertEqualsByteArray(Arrays.copyOf(RAW_SK, raw.length), raw); + } + if (k instanceof NamedX509Key npk) { + var raw = npk.getRawBytes(); + Asserts.assertEqualsByteArray(Arrays.copyOf(RAW_PK, raw.length), raw); + } + } + + // Provider + + public static class ProviderImpl extends Provider { + public ProviderImpl() { + super("P", "1", "..."); + put("KeyFactory.SHA", KF.class.getName()); + put("KeyFactory.SHA-256", KF1.class.getName()); + put("KeyFactory.SHA-512", KF2.class.getName()); + put("KeyPairGenerator.SHA", KPG.class.getName()); + put("KeyPairGenerator.SHA-256", KPG1.class.getName()); + put("KeyPairGenerator.SHA-512", KPG2.class.getName()); + } + } + public static class KF extends NamedKeyFactory { + public KF() { + super("SHA", "SHA-256", "SHA-512"); + } + + public KF(String name) { + super("SHA", name); + } + + @Override + protected byte[] implExpand(String pname, byte[] input) throws InvalidKeyException { + return null; + } + } + public static class KF1 extends KF { + public KF1() { + super("SHA-256"); + } + } + public static class KF2 extends KF { + public KF2() { + super("SHA-512"); + } + } + public static class KPG extends NamedKeyPairGenerator { + public KPG() { + super("SHA", "SHA-256", "SHA-512"); + } + + public KPG(String pname) { + super("SHA", pname); + } + + @Override + public byte[][] implGenerateKeyPair(String name, SecureRandom sr) { + var out = new byte[2][]; + out[0] = name.endsWith("256") ? Arrays.copyOf(RAW_PK, 8) : RAW_PK; + out[1] = name.endsWith("256") ? Arrays.copyOf(RAW_SK, 8) : RAW_SK; + return out; + } + } + public static class KPG1 extends KPG { + public KPG1() { + super("SHA-256"); + } + } + public static class KPG2 extends KPG { + public KPG2() { + super("SHA-512"); + } + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/named/NamedKeys.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/named/NamedKeys.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/named/NamedKeys.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/named/NamedKeys.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,103 @@ +/* + * 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 8347938 + * @modules java.base/sun.security.pkcs + * java.base/sun.security.x509 + * @library /test/lib + * @summary check the Named***Key behavior + */ +import jdk.test.lib.Asserts; +import jdk.test.lib.security.SeededSecureRandom; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import java.util.Arrays; + +public class NamedKeys { + public static void main(String[] args) throws Exception { + + // This test uses fictional key algorithms SHA and SHA-256, + // simply because they look like a family name and parameter + // set name and SHA-256 already have its OID defined. + + var r = SeededSecureRandom.one(); + var raw = r.nBytes(32); + + // Create a key using raw bytes + var sk = NamedPKCS8Key.internalCreate("SHA", "SHA-256", raw, null); + var enc = sk.getEncoded(); + + // The raw bytes array is re-used + Asserts.assertTrue(sk.getRawBytes() == sk.getRawBytes()); + // but the encoding is different + Asserts.assertTrue(sk.getEncoded() != sk.getEncoded()); + + // When source change + Arrays.fill(raw, (byte)0); + // Internal raw bytes also changes + Asserts.assertEqualsByteArray(sk.getRawBytes(), new byte[32]); + // No guarantee on getEncoded() output, could be cached + + // Create a key using encoding + var sk1 = new NamedPKCS8Key("SHA", enc, null); + var sk2 = new NamedPKCS8Key("SHA", enc, null); + var raw1 = sk1.getRawBytes(); + Asserts.assertTrue(raw1 != sk2.getRawBytes()); + Asserts.assertTrue(sk1.getEncoded() != sk2.getEncoded()); + + var encCopy = enc.clone(); // store a copy + Arrays.fill(enc, (byte)0); // clean the source and the key unchanged + Asserts.assertEqualsByteArray(encCopy, sk1.getEncoded()); + + // Same with public key + // Create a key using raw bytes + raw = r.nBytes(32); + var pk = new NamedX509Key("SHA", "SHA-256", raw); + enc = pk.getEncoded().clone(); + + // The raw bytes array is re-used + Asserts.assertTrue(pk.getRawBytes() == pk.getRawBytes()); + // but the encoding is different + Asserts.assertTrue(pk.getEncoded() != pk.getEncoded()); + + // When source change + Arrays.fill(raw, (byte)0); + // Internal raw bytes also changes + Asserts.assertEqualsByteArray(pk.getRawBytes(), new byte[32]); + // No guarantee on getEncoded() output, could be cached + + // Create a key using encoding + var pk1 = new NamedX509Key("SHA", enc); + var pk2 = new NamedX509Key("SHA", enc); + raw1 = pk1.getRawBytes(); + Asserts.assertTrue(raw1 != pk2.getRawBytes()); + Asserts.assertTrue(pk1.getEncoded() != pk2.getEncoded()); + + encCopy = enc.clone(); // store a copy + Arrays.fill(enc, (byte)0); // clean the source and the key unchanged + Asserts.assertEqualsByteArray(encCopy, pk1.getEncoded()); + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/named/namedKeyFactoryTest.policy openjdk-21-21.0.13+9/test/jdk/sun/security/provider/named/namedKeyFactoryTest.policy --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/named/namedKeyFactoryTest.policy 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/named/namedKeyFactoryTest.policy 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,11 @@ +grant { + + permission java.util.PropertyPermission "*", "read"; + permission java.security.SecurityPermission "putProviderProperty.P"; + permission java.security.SecurityPermission "insertProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.security.x509"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.security.pkcs"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.security.util"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.security.provider"; + +}; diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/pqc/PrivateKeyEncodings.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/pqc/PrivateKeyEncodings.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/pqc/PrivateKeyEncodings.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/pqc/PrivateKeyEncodings.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,227 @@ +/* + * 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 8347938 + * @library /test/lib + * @summary ensure ML-KEM and ML-DSA encodings consistent with + * RFC 9935 and RFC 9881 + * @modules java.base/com.sun.crypto.provider + * java.base/sun.security.pkcs + * java.base/sun.security.provider + * @run main/othervm PrivateKeyEncodings + */ +import com.sun.crypto.provider.ML_KEM_Impls; +import jdk.test.lib.Asserts; +import jdk.test.lib.security.RepositoryFileReader; +import jdk.test.lib.security.FixedSecureRandom; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.provider.ML_DSA_Impls; + +import javax.crypto.KEM; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.cert.CertificateFactory; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.NamedParameterSpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +public class PrivateKeyEncodings { + + public static void main(String[] args) throws Exception { + // Example keys and certificates in RFC 9935, Appendix C + // (https://datatracker.ietf.org/doc/html/rfc9935#name-examples) + // and RFC 9881, Appendix C + // (https://datatracker.ietf.org/doc/html/rfc9881#name-examples) + // + // These data can be retrieved from the following GitHub releases: + // https://github.com/lamps-wg/kyber-certificates/releases/tag/draft-ietf-lamps-kyber-certificates-11 + // https://github.com/lamps-wg/dilithium-certificates/releases/tag/draft-ietf-lamps-dilithium-certificates-13 + // + // Although the release tags include "draft", these values are the + // same as those in the final RFCs. + try (var kemReader = RepositoryFileReader.of(RepositoryFileReader.KYBER_CERTIFICATES.class, + "kyber-certificates-draft-ietf-lamps-kyber-certificates-11/"); + var dsaReader = RepositoryFileReader.of(RepositoryFileReader.DILITHIUM_CERTIFICATES.class, + "dilithium-certificates-draft-ietf-lamps-dilithium-certificates-13/")) { + good(kemReader, dsaReader); + badkem(kemReader); + baddsa(dsaReader); + } + } + + static void badkem(RepositoryFileReader f) throws Exception { + var kf = KeyFactory.getInstance("ML-KEM"); + + // The first ML-KEM-512-PrivateKey example includes the both CHOICE, + // i.e., both seed and expandedKey are included. The seed and expanded + // values can be checked for inconsistencies. + Asserts.assertThrows(InvalidKeySpecException.class, () -> + kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "example/bad-ML-KEM-512-1.priv")))); + + // The second ML-KEM-512-PrivateKey example includes only expandedKey. + // The expanded private key has a mutated s_0 and a valid public key hash, + // but a pairwise consistency check would find that the public key + // fails to match private. + var k2 = kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "example/bad-ML-KEM-512-2.priv"))); + var pk2 = ML_KEM_Impls.privKeyToPubKey((NamedPKCS8Key) k2); + var enc = KEM.getInstance("ML-KEM").newEncapsulator(pk2).encapsulate(); + var dk = KEM.getInstance("ML-KEM").newDecapsulator(k2).decapsulate(enc.encapsulation()); + Asserts.assertNotEqualsByteArray(enc.key().getEncoded(), dk.getEncoded()); + + // The third ML-KEM-512-PrivateKey example includes only expandedKey. + // The expanded private key has a mutated H(ek); both a public key + // digest check and a pairwise consistency check should fail. + var k3 = kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "example/bad-ML-KEM-512-3.priv"))); + Asserts.assertThrows(InvalidKeyException.class, () -> + KEM.getInstance("ML-KEM").newDecapsulator(k3)); + + // The fourth ML-KEM-512-PrivateKey example includes the both CHOICE, + // i.e., both seed and expandedKey are included. There is mismatch + // of the seed and expanded private key in only the z implicit rejection + // secret; here the private and public vectors match and the pairwise + // consistency check passes, but z is different. + Asserts.assertThrows(InvalidKeySpecException.class, () -> + kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "example/bad-ML-KEM-512-4.priv")))); + } + + static void baddsa(RepositoryFileReader f) throws Exception { + var kf = KeyFactory.getInstance("ML-DSA"); + + // The first ML-DSA-PrivateKey example includes the both CHOICE, i.e., + // both seed and expandedKey are included. The seed and expanded values + // can be checked for inconsistencies. + Asserts.assertThrows(InvalidKeySpecException.class, () -> + kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "examples/bad-ML-DSA-44-1.priv")))); + + // The second ML-DSA-PrivateKey example includes only expandedKey. + // The public key fails to match the tr hash value in the private key. + var k2 = kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "examples/bad-ML-DSA-44-2.priv"))); + Asserts.assertThrows(IllegalArgumentException.class, () -> + ML_DSA_Impls.privKeyToPubKey((NamedPKCS8Key) k2)); + + // The third ML-DSA-PrivateKey example also includes only expandedKey. + // The private s_1 and s_2 vectors imply a t vector whose private low + // bits do not match the t_0 vector portion of the private key + // (its high bits t_1 are the primary content of the public key). + var k3 = kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "examples/bad-ML-DSA-44-3.priv"))); + Asserts.assertThrows(IllegalArgumentException.class, () -> + ML_DSA_Impls.privKeyToPubKey((NamedPKCS8Key) k3)); + } + + static void good(RepositoryFileReader kemReader, RepositoryFileReader dsaReader) + throws Exception { + + var seed = new byte[64]; + for (var i = 0; i < seed.length; i++) { + seed[i] = (byte) i; + } + var cf = CertificateFactory.getInstance("X.509"); + var allPublicKeys = new HashMap(); + + for (var pname: List.of("ML-DSA-44", "ML-DSA-65", "ML-DSA-87", // DSA first, will sign KEM + "ML-KEM-512", "ML-KEM-768", "ML-KEM-1024")) { + + var isKem = pname.startsWith("ML-KEM"); + KeyPairGenerator g = KeyPairGenerator.getInstance(isKem ? "ML-KEM" : "ML-DSA"); + var prop = isKem ? "mlkem" : "mldsa"; + var f = isKem ? kemReader : dsaReader; + var example = isKem ? "example/" : "examples/"; + + g.initialize(new NamedParameterSpec(pname), new FixedSecureRandom(seed)); + var pk = g.generateKeyPair().getPublic(); + allPublicKeys.put(pname, pk); + Asserts.assertEqualsByteArray(readData(f, example + pname + ".pub"), pk.getEncoded()); + + var in = new ByteArrayInputStream(readData(f, example + pname + ".crt")); + var c = cf.generateCertificate(in); + var signer = switch (pname) { + case "ML-KEM-512" -> allPublicKeys.get("ML-DSA-44"); + case "ML-KEM-768" -> allPublicKeys.get("ML-DSA-65"); + case "ML-KEM-1024" -> allPublicKeys.get("ML-DSA-87"); + default -> c.getPublicKey(); + }; + c.verify(signer); + Asserts.assertEquals(c.getPublicKey(), pk); + + for (var type : List.of("seed", "expandedkey", "both")) { + System.err.println(pname + " " + type); + System.setProperty("jdk." + prop + ".pkcs8.encoding", type); + g.initialize(new NamedParameterSpec(pname), new FixedSecureRandom(seed)); + var sk = g.generateKeyPair().getPrivate(); + if (type.equals("expandedkey")) type = "expanded"; + Asserts.assertEqualsByteArray( + readData(f, example + pname + "-" + type + ".priv"), sk.getEncoded()); + checkInterop(pk, sk); + } + } + } + + // Ensures pk and sk interop with each other + static void checkInterop(PublicKey pk, PrivateKey sk) throws Exception { + if (pk.getAlgorithm().startsWith("ML-KEM")) { + var kem = KEM.getInstance("ML-KEM"); + var enc = kem.newEncapsulator(pk).encapsulate(); + var k = kem.newDecapsulator(sk).decapsulate(enc.encapsulation()); + Asserts.assertEqualsByteArray(k.getEncoded(), enc.key().getEncoded()); + } else { + var msg = "hello".getBytes(StandardCharsets.UTF_8); + var s = Signature.getInstance("ML-DSA"); + s.initSign(sk); + s.update(msg); + var sig = s.sign(); + s.initVerify(pk); + s.update(msg); + Asserts.assertTrue(s.verify(sig)); + } + } + + static byte[] readData(RepositoryFileReader f, String entry) throws Exception { + byte[] data = f.read(entry); + var pem = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(data))) + .lines() + .filter(s -> !s.contains("-----")) + .collect(Collectors.joining()); + return Base64.getMimeDecoder().decode(pem); + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/pqc/SeedOrExpanded.java openjdk-21-21.0.13+9/test/jdk/sun/security/provider/pqc/SeedOrExpanded.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/provider/pqc/SeedOrExpanded.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/provider/pqc/SeedOrExpanded.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,194 @@ +/* + * 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 8347938 + * @library /test/lib + * @modules java.base/com.sun.crypto.provider + * java.base/sun.security.pkcs + * java.base/sun.security.provider + * java.base/sun.security.util + * java.base/sun.security.x509 + * @summary check key reading compatibility + * @run main/othervm SeedOrExpanded + */ + +import com.sun.crypto.provider.ML_KEM_Impls; +import jdk.test.lib.Asserts; +import jdk.test.lib.security.DerUtils; +import jdk.test.lib.security.FixedSecureRandom; +import jdk.test.lib.security.SeededSecureRandom; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.provider.ML_DSA_Impls; +import sun.security.util.DerValue; + +import javax.crypto.KEM; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; + +public class SeedOrExpanded { + + static final SeededSecureRandom RAND = SeededSecureRandom.one(); + + public static void main(String[] args) throws Exception { + test("mlkem", "ML-KEM-768"); + test("mldsa", "ML-DSA-65"); + } + + static void test(String type, String alg) throws Exception { + + var seed = RAND.nBytes(alg.contains("ML-KEM") ? 64 : 32); + var g = KeyPairGenerator.getInstance(alg); + + // Generation + + g.initialize(-1, new FixedSecureRandom(seed)); + var kp = g.generateKeyPair(); + var pk = kp.getPublic(); + var kDefault = kp.getPrivate(); + + // Property value is case-insensitive + System.setProperty("jdk." + type + ".pkcs8.encoding", "SEED"); + g.initialize(-1, new FixedSecureRandom(seed)); + var kSeed = g.generateKeyPair().getPrivate(); + System.setProperty("jdk." + type + ".pkcs8.encoding", "expandedkey"); + g.initialize(-1, new FixedSecureRandom(seed)); + var kExpanded = g.generateKeyPair().getPrivate(); + System.setProperty("jdk." + type + ".pkcs8.encoding", "boTH"); + g.initialize(-1, new FixedSecureRandom(seed)); + var kBoth = g.generateKeyPair().getPrivate(); + + // Invalid property value + System.setProperty("jdk." + type + ".pkcs8.encoding", "bogus"); + g.initialize(-1, new FixedSecureRandom(seed)); + Asserts.assertThrows(IllegalArgumentException.class, + () -> g.generateKeyPair().getPrivate()); + + byte[] kExpandedEncoded = kExpanded.getEncoded(); + byte[] kSeedEncoded = kSeed.getEncoded(); + byte[] kBothEncoded = kBoth.getEncoded(); + + // Ensure tags match the CHOICE definition + Asserts.assertEquals((byte) 0x80, DerUtils.innerDerValue(kSeedEncoded, "2c").tag); + Asserts.assertEquals((byte) 0x04, DerUtils.innerDerValue(kExpandedEncoded, "2c").tag); + Asserts.assertEquals((byte) 0x30, DerUtils.innerDerValue(kBothEncoded, "2c").tag); + + byte[] seedData = DerUtils.innerDerValue(kSeedEncoded, "2c") + .withTag(DerValue.tag_OctetString).getOctetString(); + byte[] expandedData = DerUtils.innerDerValue(kExpandedEncoded, "2c").getOctetString(); + + Asserts.assertEqualsByteArray(seed, seedData); + Asserts.assertEqualsByteArray( + seedData, + DerUtils.innerDerValue(kBothEncoded, "2c0").getOctetString()); + Asserts.assertEqualsByteArray( + expandedData, + DerUtils.innerDerValue(kBothEncoded, "2c1").getOctetString()); + + // Ensure seedToExpanded correctly called + if (alg.contains("ML-KEM")) { + Asserts.assertEqualsByteArray(expandedData, + ML_KEM_Impls.seedToExpanded(alg, seedData)); + } else { + Asserts.assertEqualsByteArray(expandedData, + ML_DSA_Impls.seedToExpanded(alg, seedData)); + } + + test(alg, pk, kSeed); + test(alg, pk, kExpanded); + test(alg, pk, kBoth); + + var kf = KeyFactory.getInstance(alg); + + System.setProperty("jdk." + type + ".pkcs8.encoding", "seed"); + Asserts.assertEqualsByteArray( + test(alg, pk, kf.translateKey(kBoth)).getEncoded(), + kSeedEncoded); + Asserts.assertTrue(kf.translateKey(kSeed) == kSeed); + Asserts.assertThrows(InvalidKeyException.class, () -> kf.translateKey(kExpanded)); + + System.setProperty("jdk." + type + ".pkcs8.encoding", "expandedkey"); + Asserts.assertEqualsByteArray( + test(alg, pk, kf.translateKey(kBoth)).getEncoded(), + kExpandedEncoded); + Asserts.assertEqualsByteArray( + test(alg, pk, kf.translateKey(kSeed)).getEncoded(), + kExpandedEncoded); + Asserts.assertTrue(kf.translateKey(kExpanded) == kExpanded); + + System.setProperty("jdk." + type + ".pkcs8.encoding", "both"); + Asserts.assertTrue(kf.translateKey(kBoth) == kBoth); + Asserts.assertEqualsByteArray( + test(alg, pk, kf.translateKey(kSeed)).getEncoded(), + kBothEncoded); + Asserts.assertThrows(InvalidKeyException.class, () -> kf.translateKey(kExpanded)); + + // The following makes sure key is not mistakenly cleaned during + // translations. + var xk = new PrivateKey() { + public String getAlgorithm() { return alg; } + public String getFormat() { return "PKCS#8"; } + public byte[] getEncoded() { return kBothEncoded.clone(); } + }; + test(alg, pk, xk); + var xk2 = (PrivateKey) kf.translateKey(xk); + test(alg, pk, xk2); + test(alg, pk, xk); + } + + static PrivateKey test(String alg, PublicKey pk, Key k) throws Exception { + var sk = (PrivateKey) k; + if (alg.contains("ML-KEM")) { + var kem = KEM.getInstance("ML-KEM"); + var e = kem.newEncapsulator(pk, RAND); + var enc = e.encapsulate(); + var k1 = kem.newDecapsulator(sk).decapsulate(enc.encapsulation()); + Asserts.assertEqualsByteArray(k1.getEncoded(), enc.key().getEncoded()); + if (k instanceof NamedPKCS8Key npk) { + Asserts.assertEqualsByteArray( + ML_KEM_Impls.privKeyToPubKey(npk).getEncoded(), pk.getEncoded()); + } + } else { + var s = Signature.getInstance("ML-DSA"); + var rnd = RAND.nBytes(32); // randomness for signature generation + var msg = RAND.nBytes(20); + s.initSign(sk, new FixedSecureRandom(rnd)); + s.update(msg); + var sig1 = s.sign(); + s.initVerify(pk); + s.update(msg); + Asserts.assertTrue(s.verify(sig1)); + if (k instanceof NamedPKCS8Key npk) { + Asserts.assertEqualsByteArray( + ML_DSA_Impls.privKeyToPubKey(npk).getEncoded(), pk.getEncoded()); + } + } + return sk; + } +} diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Camerfirma.java openjdk-21-21.0.13+9/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Camerfirma.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Camerfirma.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java openjdk-21-21.0.13+9/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java openjdk-21-21.0.13+9/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java openjdk-21-21.0.13+9/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java openjdk-21-21.0.13+9/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java 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, 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 @@ -84,7 +84,7 @@ System.out.println("Generating an XDH cert with -signer option"); SecurityTools.keytool("-keystore ks -storepass changeit " + "-genkeypair -keyalg XDH -alias e1 -dname CN=E1 -signer ca") - .shouldContain("Generating 255 bit XDH key pair and a certificate (Ed25519) issued by with a validity of 90 days") + .shouldContain("Generating 255 bit X25519 key pair and a certificate (Ed25519) issued by with a validity of 90 days") .shouldContain("for: CN=E1") .shouldHaveExitValue(0); @@ -118,7 +118,7 @@ .shouldContain("Alias name: e1") .shouldContain("Certificate chain length: 2") .shouldContain("Signature algorithm name: Ed25519") - .shouldContain("Subject Public Key Algorithm: 255-bit XDH key") + .shouldContain("Subject Public Key Algorithm: 255-bit X25519 key") .shouldHaveExitValue(0); // check to make sure that cert's AKID is created from the SKID of the signing cert @@ -150,7 +150,7 @@ System.out.println("Generating an X448 cert with -signer option"); SecurityTools.keytool("-keystore ks -storepass changeit " + "-genkeypair -keyalg X448 -alias e2 -dname CN=E2 -sigalg SHA384withRSA -signer ca2") - .shouldContain("Generating 448 bit XDH key pair and a certificate (SHA384withRSA) issued by with a validity of 90 days") + .shouldContain("Generating 448 bit X448 key pair and a certificate (SHA384withRSA) issued by with a validity of 90 days") .shouldContain("for: CN=E2") .shouldHaveExitValue(0); @@ -177,7 +177,7 @@ "-list -v") .shouldContain("Alias name: e2") .shouldContain("Signature algorithm name: SHA384withRSA") - .shouldContain("Subject Public Key Algorithm: 448-bit XDH key") + .shouldContain("Subject Public Key Algorithm: 448-bit X448 key") .shouldHaveExitValue(0); kt("-genkeypair -keyalg DSA -alias ca3 -dname CN=CA3 -ext bc:c ", @@ -249,7 +249,7 @@ SecurityTools.keytool("-keystore ksjks -storepass changeit -storetype jks " + "-genkeypair -keyalg XDH -alias e1 -dname CN=E1 " + "-keypass e1keypass -signer ca1 -signerkeypass ca1keypass") - .shouldContain("Generating 255 bit XDH key pair and a certificate (SHA256withDSA) issued by with a validity of 90 days") + .shouldContain("Generating 255 bit X25519 key pair and a certificate (SHA256withDSA) issued by with a validity of 90 days") .shouldContain("for: CN=E1") .shouldContain("The generated certificate #2 of 3 uses a 1024-bit DSA key which is considered a security risk") .shouldContain("The generated certificate #3 of 3 uses a 1024-bit RSA key which is considered a security risk") @@ -285,7 +285,7 @@ .shouldContain("Alias name: e1") .shouldContain("Certificate chain length: 3") .shouldContain("Signature algorithm name: SHA256withDSA") - .shouldContain("Subject Public Key Algorithm: 255-bit XDH key") + .shouldContain("Subject Public Key Algorithm: 255-bit X25519 key") .shouldHaveExitValue(0); } diff -Nru openjdk-21-21.0.12.1+1/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java openjdk-21-21.0.13+9/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -195,6 +195,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); @@ -220,6 +221,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); } @@ -238,11 +240,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-21-21.0.12.1+1/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java openjdk-21-21.0.13+9/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/security/x509/AlgorithmId/NullParams.java openjdk-21-21.0.13+9/test/jdk/sun/security/x509/AlgorithmId/NullParams.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/x509/AlgorithmId/NullParams.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java openjdk-21-21.0.13+9/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/security/x509/IPAddressName/ConstrainsTest.java openjdk-21-21.0.13+9/test/jdk/sun/security/x509/IPAddressName/ConstrainsTest.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/security/x509/IPAddressName/ConstrainsTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcCapacityOutput1.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatGcCapacityOutput1.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcCapacityOutput1.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcMetaCapacityOutput1.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatGcMetaCapacityOutput1.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcMetaCapacityOutput1.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcNewCapacityOutput1.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatGcNewCapacityOutput1.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcNewCapacityOutput1.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcNewOutput1.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatGcNewOutput1.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcNewOutput1.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcOldCapacityOutput1.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatGcOldCapacityOutput1.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcOldCapacityOutput1.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcOldOutput1.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatGcOldOutput1.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcOldOutput1.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcOutput1.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatGcOutput1.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatGcOutput1.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatLineCounts1.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatLineCounts1.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatLineCounts1.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatLineCounts2.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatLineCounts2.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatLineCounts2.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatLineCounts3.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatLineCounts3.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatLineCounts3.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatLineCounts4.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatLineCounts4.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatLineCounts4.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatTimeStamp1.sh openjdk-21-21.0.13+9/test/jdk/sun/tools/jstat/jstatTimeStamp1.sh --- openjdk-21-21.0.12.1+1/test/jdk/sun/tools/jstat/jstatTimeStamp1.sh 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/util/resources/TimeZone/Bug8139107.java openjdk-21-21.0.13+9/test/jdk/sun/util/resources/TimeZone/Bug8139107.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/util/resources/TimeZone/Bug8139107.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/util/resources/TimeZone/Bug8139107.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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/othervm -Djava.locale.providers=JRE,SPI Bug8139107 + * @run junit/othervm -Djava.locale.providers=JRE,SPI 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-21-21.0.12.1+1/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java openjdk-21-21.0.13+9/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java 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 @@ -26,8 +26,8 @@ * @bug 8275721 * @modules jdk.localedata * @summary Checks Chinese time zone names for `UTC` using CLDR are consistent - * @run testng/othervm -Djava.locale.providers=CLDR,COMPAT ChineseTimeZoneNameTest - * @run testng/othervm -Djava.locale.providers=CLDR ChineseTimeZoneNameTest + * @run junit/othervm -Djava.locale.providers=CLDR,COMPAT ChineseTimeZoneNameTest + * @run junit/othervm -Djava.locale.providers=CLDR ChineseTimeZoneNameTest */ import java.time.Instant; @@ -36,11 +36,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"); @@ -48,8 +47,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}, @@ -62,11 +60,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-21-21.0.12.1+1/test/jdk/sun/util/resources/cldr/Bug8202764.java openjdk-21-21.0.13+9/test/jdk/sun/util/resources/cldr/Bug8202764.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/util/resources/cldr/Bug8202764.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java openjdk-21-21.0.13+9/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java --- openjdk-21-21.0.12.1+1/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.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 @@ -24,29 +24,35 @@ /* * @test * @bug 8181157 8202537 8234347 8236548 8261279 + * 8381379 8390388 8390380 8392519 8392377 8393344 8393337 * @modules jdk.localedata * @summary Checks CLDR time zone names are generated correctly at runtime - * @run testng/othervm -Djava.locale.providers=CLDR TimeZoneNamesTest + * @run junit/othervm -Djava.locale.providers=CLDR 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(name="noResourceTZs") - Object[][] data() { + private static Object[][] data() { return new Object[][] { // tzid, locale, style, expected @@ -177,20 +183,38 @@ }; } + 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, 1, 5, 0, 0, 0, 0, ZoneId.of("America/Yellowknife")), "Mountain Standard Time"), + Arguments.of(ZonedDateTime.of(2026, 7, 5, 0, 0, 0, 0, ZoneId.of("America/Yellowknife")), "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"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("America/Rainy_River")), "Central Daylight Time") + ); + } - @Test(dataProvider="noResourceTZs") + @ParameterizedTest + @MethodSource("data") 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 @@ -209,4 +233,19 @@ .isPresent(), "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-21-21.0.12.1+1/test/langtools/TEST.ROOT openjdk-21-21.0.13+9/test/langtools/TEST.ROOT --- openjdk-21-21.0.12.1+1/test/langtools/TEST.ROOT 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/langtools/TEST.ROOT 2026-10-19 12:10:20.000000000 +0000 @@ -15,7 +15,7 @@ groups=TEST.groups # Minimum jtreg version -requiredVersion=7.5.2+1 +requiredVersion=8.2.1+1 # Use new module options useNewOptions=true diff -Nru openjdk-21-21.0.12.1+1/test/langtools/jdk/jshell/RemoteAgentHandshakeTest.java openjdk-21-21.0.13+9/test/langtools/jdk/jshell/RemoteAgentHandshakeTest.java --- openjdk-21-21.0.12.1+1/test/langtools/jdk/jshell/RemoteAgentHandshakeTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java openjdk-21-21.0.13+9/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java --- openjdk-21-21.0.12.1+1/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/lib/jdk/test/lib/Asserts.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/Asserts.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/Asserts.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib/jdk/test/lib/Asserts.java 2026-10-19 12:10:20.000000000 +0000 @@ -238,59 +238,58 @@ } /** - * Asserts that {@code lhs} is the same byte array as {@code rhs}. + * Asserts that {@code actual} has the same content as {@code expected}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param expected The expected value + * @param actual The actual value * @throws RuntimeException if the assertion is not true. * @see #assertEqualsByteArray(byte[], byte[], String) */ - public static void assertEqualsByteArray(byte[] lhs, byte[] rhs) { - assertEqualsByteArray(lhs, rhs, null); + public static void assertEqualsByteArray(byte[] expected, byte[] actual) { + assertEqualsByteArray(expected, actual, null); } /** - * Asserts that {@code lhs} is not the same byte array as {@code rhs}. + * Asserts that {@code actual} does not have the same content as {@code unexpected}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @throws RuntimeException if the assertion is not true. * @see #assertNotEqualsByteArray(byte[], byte[], String) */ - public static void assertNotEqualsByteArray(byte[] lhs, byte[] rhs) { - assertNotEqualsByteArray(lhs, rhs, null); + public static void assertNotEqualsByteArray(byte[] unexpected, byte[] actual) { + assertNotEqualsByteArray(unexpected, actual, null); } /** - * Asserts that {@code lhs} is the same byte array as {@code rhs}. + * Asserts that {@code actual} is the same byte array as {@code expected}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param expected The expected value + * @param actual The actual value * @param msg A description of the assumption; {@code null} for a default message. * @throws RuntimeException if the assertion is not true. */ - public static void assertEqualsByteArray(byte[] lhs, byte[] rhs, String msg) { - if (!Arrays.equals(lhs, rhs)) { + public static void assertEqualsByteArray(byte[] expected, byte[] actual, String msg) { + if (!Arrays.equals(expected, actual)) { msg = Objects.toString(msg, "assertEqualsByteArray") - + ": expected " + HexFormat.of().formatHex(lhs) - + " to equal " + HexFormat.of().formatHex(rhs); + + ": expected " + HexFormat.of().formatHex(expected) + + " but was " + HexFormat.of().formatHex(actual); fail(msg); } } /** - * Asserts that {@code lhs} is not the same byte array as {@code rhs}. + * Asserts that {@code actual} is not the same byte array as {@code unexpected}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @param msg A description of the assumption; {@code null} for a default message. * @throws RuntimeException if the assertion is not true. */ - public static void assertNotEqualsByteArray(byte[] lhs, byte[] rhs, String msg) { - if (Arrays.equals(lhs, rhs)) { + public static void assertNotEqualsByteArray(byte[] unexpected, byte[] actual, String msg) { + if (Arrays.equals(unexpected, actual)) { msg = Objects.toString(msg, "assertNotEqualsByteArray") - + ": expected " + HexFormat.of().formatHex(lhs) - + " to not equal " + HexFormat.of().formatHex(rhs); + + ": expected not equals but was " + HexFormat.of().formatHex(actual); fail(msg); } } @@ -408,50 +407,49 @@ /** * Shorthand for {@link #assertNotEquals(Object, Object)}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @see #assertNotEquals(Object, Object) */ - public static void assertNE(Object lhs, Object rhs) { - assertNotEquals(lhs, rhs); + public static void assertNE(Object unexpected, Object actual) { + assertNotEquals(unexpected, actual); } /** * Shorthand for {@link #assertNotEquals(Object, Object, String)}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @param msg A description of the assumption; {@code null} for a default message. * @see #assertNotEquals(Object, Object, String) */ - public static void assertNE(Object lhs, Object rhs, String msg) { - assertNotEquals(lhs, rhs, msg); + public static void assertNE(Object unexpected, Object actual, String msg) { + assertNotEquals(unexpected, actual, msg); } /** * Calls {@link #assertNotEquals(Object, Object, String)} with a default message. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @see #assertNotEquals(Object, Object, String) */ - public static void assertNotEquals(Object lhs, Object rhs) { - assertNotEquals(lhs, rhs, null); + public static void assertNotEquals(Object unexpected, Object actual) { + assertNotEquals(unexpected, actual, null); } /** - * Asserts that {@code lhs} is not equal to {@code rhs}. + * Asserts that {@code actual} is not equal to {@code unexpected}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @param msg A description of the assumption; {@code null} for a default message. * @throws RuntimeException if the assertion is not true. */ - public static void assertNotEquals(Object lhs, Object rhs, String msg) { - if ((lhs == rhs) || (lhs != null && lhs.equals(rhs))) { + public static void assertNotEquals(Object unexpected, Object actual, String msg) { + if ((unexpected == actual) || (unexpected != null && unexpected.equals(actual))) { msg = Objects.toString(msg, "assertNotEquals") - + ": expected " + Objects.toString(lhs) - + " to not equal " + Objects.toString(rhs); + + ": expected not equals but was " + Objects.toString(actual); fail(msg); } } diff -Nru openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/Utils.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/Utils.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/Utils.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib/jdk/test/lib/Utils.java 2026-10-19 12:10:20.000000000 +0000 @@ -45,9 +45,11 @@ 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.security.MessageDigest; @@ -56,6 +58,7 @@ 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; @@ -1033,25 +1036,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-21-21.0.12.1+1/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -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-21-21.0.12.1+1/test/lib/jdk/test/lib/process/Proc.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/process/Proc.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/process/Proc.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib/jdk/test/lib/process/Proc.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, 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 @@ -320,6 +320,15 @@ } } } + String patchPath = System.getProperty("test.patch.path"); + if (patchPath != null) { + try (var subs = Files.newDirectoryStream(Path.of(patchPath))) { + for (var sub : subs) { + var name = sub.getFileName(); + cmd.add("--patch-module=" + name + "=" + sub); + } + } + } var lcp = fullcp(); if (lcp != null) { diff -Nru openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/CertificateBuilder.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/CertificateBuilder.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/CertificateBuilder.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/CertificateBuilder.java 2026-10-19 12:10:20.000000000 +0000 @@ -48,13 +48,13 @@ import sun.security.x509.NameConstraintsExtension; import sun.security.x509.SubjectKeyIdentifierExtension; import sun.security.x509.BasicConstraintsExtension; +import sun.security.x509.CertificateSerialNumber; import sun.security.x509.ExtendedKeyUsageExtension; import sun.security.x509.DistributionPoint; import sun.security.x509.DNSName; import sun.security.x509.GeneralName; import sun.security.x509.GeneralNames; import sun.security.x509.KeyUsageExtension; -import sun.security.x509.SerialNumber; import sun.security.x509.SubjectAlternativeNameExtension; import sun.security.x509.URIName; import sun.security.x509.KeyIdentifier; @@ -452,11 +452,8 @@ * * @param bitSettings Boolean array for all nine bit settings in the order * documented in RFC 5280 section 4.2.1.3. - * - * @throws IOException if an encoding error occurs. */ - public CertificateBuilder addKeyUsageExt(boolean[] bitSettings) - throws IOException { + public CertificateBuilder addKeyUsageExt(boolean[] bitSettings) { return addExtension(new KeyUsageExtension(bitSettings)); } @@ -469,11 +466,9 @@ * @param maxPathLen The maximum path length issued by this CA. Values * less than zero will omit this field from the resulting extension and * no path length constraint will be asserted. - * - * @throws IOException if an encoding error occurs. */ public CertificateBuilder addBasicConstraintsExt(boolean crit, boolean isCA, - int maxPathLen) throws IOException { + int maxPathLen) { return addExtension(new BasicConstraintsExtension(crit, isCA, maxPathLen)); } @@ -564,7 +559,27 @@ } /** - * Build the certificate. + * Build the certificate using the default algorithm for the provided + * signing key. + * + * @param issuerCert The certificate of the issuing authority, or + * {@code null} if the resulting certificate is self-signed. + * @param issuerKey The private key of the issuing authority + * + * @return The resulting {@link X509Certificate} + * + * @throws IOException if an encoding error occurs. + * @throws CertificateException If the certificate cannot be generated + * by the underlying {@link CertificateFactory} + */ + public X509Certificate build(X509Certificate issuerCert, + PrivateKey issuerKey) throws IOException, CertificateException { + return build(issuerCert, issuerKey, + SignatureUtil.getDefaultSigAlgForKey(issuerKey)); + } + + /** + * Build the certificate using the key and specified signing algorithm. * * @param issuerCert The certificate of the issuing authority, or * {@code null} if the resulting certificate is self-signed. @@ -576,14 +591,10 @@ * @throws IOException if an encoding error occurs. * @throws CertificateException If the certificate cannot be generated * by the underlying {@link CertificateFactory} - * @throws NoSuchAlgorithmException If an invalid signature algorithm - * is provided. */ public X509Certificate build(X509Certificate issuerCert, PrivateKey issuerKey, String algName) - throws IOException, CertificateException, NoSuchAlgorithmException { - // TODO: add some basic checks (key usage, basic constraints maybe) - + throws IOException, CertificateException { byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, algName); ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert); return (X509Certificate)factory.generateCertificate(bais); @@ -612,15 +623,14 @@ */ private byte[] encodeTopLevel(X509Certificate issuerCert, PrivateKey issuerKey, String algName) - throws CertificateException, IOException, NoSuchAlgorithmException { + throws CertificateException, IOException { - AlgorithmId signAlg = AlgorithmId.get(algName); + AlgorithmId signAlg; DerOutputStream outerSeq = new DerOutputStream(); DerOutputStream topLevelItems = new DerOutputStream(); try { - Signature sig = SignatureUtil.fromKey(signAlg.getName(), issuerKey, (Provider)null); - // Rewrite signAlg, RSASSA-PSS needs some parameters. + Signature sig = SignatureUtil.fromKey(algName, issuerKey, ""); signAlg = SignatureUtil.fromSignature(sig, issuerKey); tbsCertBytes = encodeTbsCert(issuerCert, signAlg); sig.update(tbsCertBytes); @@ -677,7 +687,9 @@ } // Serial Number - SerialNumber sn = new SerialNumber(serialNumber); + CertificateSerialNumber sn = (serialNumber != null) ? + new CertificateSerialNumber(serialNumber) : + CertificateSerialNumber.newRandom64bit(new SecureRandom()); sn.encode(tbsCertItems); // Algorithm ID @@ -694,8 +706,12 @@ // Validity period (set as UTCTime) DerOutputStream valSeq = new DerOutputStream(); - valSeq.putUTCTime(notBefore); - valSeq.putUTCTime(notAfter); + Instant now = Instant.now(); + Date startDate = (notBefore != null) ? notBefore : Date.from(now); + valSeq.putUTCTime(startDate); + Date endDate = (notAfter != null) ? notAfter : + Date.from(now.plus(90, ChronoUnit.DAYS)); + valSeq.putUTCTime(endDate); tbsCertItems.write(DerValue.tag_Sequence, valSeq); // Subject Name @@ -735,6 +751,9 @@ */ private void encodeExtensions(DerOutputStream tbsStream) throws IOException { + if (extensions.isEmpty()) { + return; + } DerOutputStream extSequence = new DerOutputStream(); DerOutputStream extItems = new DerOutputStream(); diff -Nru openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/DerUtils.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/DerUtils.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/DerUtils.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/lib/jdk/test/lib/security/FixedSecureRandom.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/FixedSecureRandom.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/FixedSecureRandom.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/FixedSecureRandom.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.test.lib.security; + +import java.io.ByteArrayOutputStream; +import java.security.SecureRandom; + +/// A custom implementation of `SecureRandom` that outputs a +/// predefined sequence of bytes. +/// +/// The `FixedSecureRandom` class is designed for testing and +/// controlled environments where predictable output is required. +/// Upon creation, the class is initialized with a fixed byte array. +/// Each call to `nextBytes()` will return these bytes in sequence, +/// ensuring that the output matches the provided input exactly. +/// An `IllegalStateException` will be thrown when the predefined +/// bytes are exhausted. +public class FixedSecureRandom extends SecureRandom { + + private byte[] buffer; + private int offset; + + // Multiple segments of ordered predefined bytes can be + // provided for convenience. For example, ML-KEM.KeyGen + // requires 2 blocks of 32-byte random data. + public FixedSecureRandom(byte[]... data) { + var os = new ByteArrayOutputStream(); + for (byte[] b : data) { + os.writeBytes(b); + } + buffer = os.toByteArray(); + offset = 0; + } + + @Override + public void nextBytes(byte[] bytes) { + if (bytes.length > buffer.length - offset) { + throw new IllegalStateException("Not enough bytes"); + } + System.arraycopy(buffer, offset, bytes, 0, bytes.length); + offset += bytes.length; + } + + /// {@return whether there are remaining used bytes} + /// + /// This method is useful to detect whether an algorithm + /// implementation has indeed consumed the required number + /// of bytes correctly. + public boolean hasRemaining() { + return offset != buffer.length; + } +} diff -Nru openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/RepositoryFileReader.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/RepositoryFileReader.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/RepositoryFileReader.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/RepositoryFileReader.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.test.lib.security; + +import jdk.test.lib.artifacts.Artifact; +import jdk.test.lib.artifacts.ArtifactResolver; +import jdk.test.lib.artifacts.ArtifactResolverException; +import jtreg.SkippedException; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/// A helper class to read files from a code repository. +/// +/// By default, the code repository is stored on the artifact server +/// as a ZIP file. +/// +/// Users can specify the "jdk.tests.repos.pattern" system property to read +/// the files from an alternative location. The value of this system property +/// represents the URL for each file entry where: +/// - "%o" maps to the last part of [organization name][Artifact#organization()], +/// - "%n" maps to [name][Artifact#name()], +/// - "%r" maps to [version][Artifact#revision()], +/// - "%e" maps to the name of the file entry to read. +/// +/// For example, with the [CMS_ML_DSA] class inside this test: +/// - The pattern `file:///Users/tester/repos/external/%o/%n/%e` resolves to +/// a local file like `/Users/tester/repos/external/lamps-wg/cms-ml-dsa/entry`. +/// - The pattern `https://raw.repos.com/%o/%n/%r/%e` resolves to +/// `https://raw.repos.com/lamps-wg/cms-ml-dsa/c8f0cf7/entry`. +/// +public sealed interface RepositoryFileReader extends AutoCloseable { + + /// Reads the content of `entry` as a byte array. + byte[] read(String entry) throws IOException; + + /// Overrides the method with a different exception type + /// to avoid compiler warnings about `InterruptedException`. + @Override + void close() throws IOException; + + /// Returns a `RepositoryFileReader`. + /// @param klass the `Artifact` class + /// @param zipPrefix the prefix used in the ZIP file. See + /// [ZipReader#ZipReader(ZipFile, String)]. + static RepositoryFileReader of(Class klass, String zipPrefix) { + Artifact artifact = klass.getAnnotation(Artifact.class); + var org = artifact.organization(); + var prop = System.getProperty("jdk.tests.repos.pattern"); + if (prop != null && org.startsWith("jpg.tests.jdk.repos.")) { + prop = prop.replace("%o", org.substring(org.lastIndexOf('.') + 1)); + prop = prop.replace("%n", artifact.name()); + prop = prop.replace("%r", artifact.revision()); + System.out.println("Creating URLReader on " + prop); + return new URLReader(prop); + } else { + try { + Path p = ArtifactResolver.resolve(klass).entrySet().stream() + .findAny().get().getValue(); + System.out.println("Creating ZipReader on " + p); + return new ZipReader(new ZipFile(p.toFile()), zipPrefix); + } catch (ArtifactResolverException | IOException e) { + throw new SkippedException("Cannot find " + artifact.name(), e); + } + } + } + + /// A `RepositoryFileReader` to read file from a URL. + /// @param base the base URL string, contains "%e" mapping to entry name + record URLReader(String base) implements RepositoryFileReader { + @Override + public void close() { + // nothing to do + } + + @Override + public byte[] read(String entry) throws IOException { + System.out.println("Reading " + entry + "..."); + try (var is = new URI(base.replace("%e", entry)).toURL().openStream()) { + return is.readAllBytes(); + } catch (URISyntaxException e) { + throw new IOException("Cannot create URI", e); + } + } + } + + /// A `RepositoryFileReader` to read file from a ZIP file. + /// @param zf the `ZipFile` + /// @param zipPrefix optional prefix string inside the ZIP file. For example, + /// if an entry "folder/file" is represented as "archive/folder/file" + /// inside the ZIP, "archive/" should be provided as `zipPrefix`. + record ZipReader(ZipFile zf, String zipPrefix) implements RepositoryFileReader { + @Override + public void close() throws IOException { + zf.close(); + } + + @Override + public byte[] read(String entry) throws IOException { + System.out.println("Reading " + entry + "..."); + ZipEntry ze = zf.getEntry(zipPrefix + entry); + if (ze != null) { + return zf.getInputStream(ze).readAllBytes(); + } else { + throw new RuntimeException("Entry not found: " + entry); + } + } + } + + @Artifact( + organization = "jpg.tests.jdk.repos.lamps-wg", + name = "dilithium-certificates", + revision = "785a549", + extension = "zip", + unpack = false) + public static class DILITHIUM_CERTIFICATES { + } + + @Artifact( + organization = "jpg.tests.jdk.repos.lamps-wg", + name = "cms-ml-dsa", + revision = "c8f0cf7", + extension = "zip", + unpack = false) + public static class CMS_ML_DSA { + } + + @Artifact( + organization = "jpg.tests.jdk.repos.lamps-wg", + name = "kyber-certificates", + revision = "29f3215", + extension = "zip", + unpack = false) + public static class KYBER_CERTIFICATES { + } +} diff -Nru openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/SeededSecureRandom.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/SeededSecureRandom.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/SeededSecureRandom.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/SeededSecureRandom.java 2026-10-19 12:10:20.000000000 +0000 @@ -65,4 +65,10 @@ rnd.nextBytes(out); return out; } + + public byte[] nBytes(int n) { + var out = new byte[n]; + nextBytes(out); + return out; + } } diff -Nru openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/SimpleOCSPServer.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/SimpleOCSPServer.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/security/SimpleOCSPServer.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib/jdk/test/lib/security/SimpleOCSPServer.java 2026-10-19 12:10:20.000000000 +0000 @@ -25,6 +25,7 @@ import java.io.*; import java.net.*; +import java.nio.charset.StandardCharsets; import java.security.*; import java.security.cert.CRLReason; import java.security.cert.X509Certificate; @@ -61,7 +62,7 @@ static final int FREE_PORT = 0; // CertStatus values - public static enum CertStatus { + public enum CertStatus { CERT_STATUS_GOOD, CERT_STATUS_REVOKED, CERT_STATUS_UNKNOWN, @@ -69,14 +70,14 @@ // Fields used for the networking portion of the responder private ServerSocket servSocket; - private InetAddress listenAddress; + private final InetAddress listenAddress; private int listenPort; // Keystore information (certs, keys, etc.) - private KeyStore keystore; - private X509Certificate issuerCert; - private X509Certificate signerCert; - private PrivateKey signerKey; + private final KeyStore keystore; + private final X509Certificate issuerCert; + private final X509Certificate signerCert; + private final PrivateKey signerKey; // Fields used for the operational portions of the server private boolean logEnabled = false; @@ -91,9 +92,9 @@ // Fields used in the generation of responses private long nextUpdateInterval = -1; private Date nextUpdate = null; - private ResponderId respId; - private AlgorithmId sigAlgId; - private Map statusDb = + private final ResponderId respId; + private String sigAlgName; + private final Map statusDb = Collections.synchronizedMap(new HashMap<>()); /** @@ -140,25 +141,24 @@ public SimpleOCSPServer(InetAddress addr, int port, KeyStore ks, String password, String issuerAlias, String signerAlias) throws GeneralSecurityException, IOException { - Objects.requireNonNull(ks, "Null keystore provided"); + keystore = Objects.requireNonNull(ks, "Null keystore provided"); Objects.requireNonNull(issuerAlias, "Null issuerName provided"); utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT")); - keystore = ks; - issuerCert = (X509Certificate)ks.getCertificate(issuerAlias); + issuerCert = (X509Certificate)keystore.getCertificate(issuerAlias); if (issuerCert == null) { throw new IllegalArgumentException("Certificate for alias " + issuerAlias + " not found"); } if (signerAlias != null) { - signerCert = (X509Certificate)ks.getCertificate(signerAlias); + signerCert = (X509Certificate)keystore.getCertificate(signerAlias); if (signerCert == null) { throw new IllegalArgumentException("Certificate for alias " + signerAlias + " not found"); } - signerKey = (PrivateKey)ks.getKey(signerAlias, + signerKey = (PrivateKey)keystore.getKey(signerAlias, password.toCharArray()); if (signerKey == null) { throw new IllegalArgumentException("PrivateKey for alias " + @@ -166,14 +166,14 @@ } } else { signerCert = issuerCert; - signerKey = (PrivateKey)ks.getKey(issuerAlias, + signerKey = (PrivateKey)keystore.getKey(issuerAlias, password.toCharArray()); if (signerKey == null) { throw new IllegalArgumentException("PrivateKey for alias " + issuerAlias + " not found"); } } - sigAlgId = AlgorithmId.get(SignatureUtil.getDefaultSigAlgForKey(signerKey)); + sigAlgName = SignatureUtil.getDefaultSigAlgForKey(signerKey); respId = new ResponderId(signerCert.getSubjectX500Principal()); listenAddress = addr; listenPort = port; @@ -495,8 +495,14 @@ public void setSignatureAlgorithm(String algName) throws NoSuchAlgorithmException { if (!started) { - sigAlgId = AlgorithmId.get(algName); - log("Signature algorithm set to " + sigAlgId.getName()); + // We don't care about the AlgorithmId object, we're just + // using it to validate the algName parameter. + AlgorithmId.get(algName); + sigAlgName = algName; + log("Signature algorithm set to " + algName); + } else { + log("Signature algorithm cannot be set on a running server, " + + "stop the server first"); } } @@ -604,9 +610,9 @@ * object may be used to construct OCSP responses. */ public static class CertStatusInfo { - private CertStatus certStatusType; + private final CertStatus certStatusType; private CRLReason reason; - private Date revocationTime; + private final Date revocationTime; /** * Create a Certificate status object by providing the status only. @@ -745,7 +751,7 @@ // This will be tokenized so we know if we are dealing with // a GET or POST. String[] headerTokens = readLine(in).split(" "); - LocalOcspRequest ocspReq = null; + LocalOcspRequest ocspReq; LocalOcspResponse ocspResp = null; ResponseStatus respStat = ResponseStatus.INTERNAL_ERROR; try { @@ -794,7 +800,7 @@ out.flush(); log("Closing " + ocspSocket); - } catch (IOException | CertificateException exc) { + } catch (IOException | GeneralSecurityException exc) { err(exc); } } @@ -826,10 +832,10 @@ append("\r\n"); } sb.append("\r\n"); + log(resp.toString()); - out.write(sb.toString().getBytes("UTF-8")); + out.write(sb.toString().getBytes(StandardCharsets.UTF_8)); out.write(respBytes); - log(resp.toString()); } /** @@ -940,7 +946,7 @@ // "/" off before decoding. return new LocalOcspRequest(Base64.getMimeDecoder().decode( URLDecoder.decode(headerTokens[1].replaceAll("/", ""), - "UTF-8"))); + StandardCharsets.UTF_8))); } /** @@ -974,8 +980,7 @@ bos.write(b); } } - - return new String(bos.toByteArray(), "UTF-8"); + return bos.toString(StandardCharsets.UTF_8); } } @@ -1052,7 +1057,6 @@ if (sigItems[2].isContextSpecific((byte)0)) { DerValue[] certDerItems = sigItems[2].data.getSequence(4); - int i = 0; for (DerValue dv : certDerItems) { X509Certificate xc = new X509CertImpl(dv); certificates.add(xc); @@ -1131,7 +1135,7 @@ * Return the list of X.509 Certificates in this OCSP request. * * @return an unmodifiable {@code List} of zero or more - * {@cpde X509Certificate} objects. + * {@code X509Certificate} objects. */ private List getCertificates() { return Collections.unmodifiableList(certificates); @@ -1295,7 +1299,8 @@ private final Map responseExtensions; private byte[] signature; private final List certificates; - private final byte[] encodedResponse; + private final Signature signEngine; + private final AlgorithmId sigAlgId; /** * Constructor for the generation of non-successful responses @@ -1305,9 +1310,11 @@ * @throws IOException if an error happens during encoding * @throws NullPointerException if {@code respStat} is {@code null} * or {@code respStat} is successful. + * @throws GeneralSecurityException if errors occur while obtaining + * the signature object or any algorithm identifier parameters. */ public LocalOcspResponse(OCSPResponse.ResponseStatus respStat) - throws IOException { + throws IOException, GeneralSecurityException { this(respStat, null, null); } @@ -1324,10 +1331,13 @@ * @throws NullPointerException if {@code respStat} is {@code null} * or {@code respStat} is successful, and a {@code null} {@code itemMap} * has been provided. + * @throws GeneralSecurityException if errors occur while obtaining + * the signature object or any algorithm identifier parameters. */ public LocalOcspResponse(OCSPResponse.ResponseStatus respStat, Map itemMap, - Map reqExtensions) throws IOException { + Map reqExtensions) + throws IOException, GeneralSecurityException { responseStatus = Objects.requireNonNull(respStat, "Illegal null response status"); if (responseStatus == ResponseStatus.SUCCESSFUL) { @@ -1348,13 +1358,18 @@ certificates.add(signerCert); } certificates.add(issuerCert); + // Create the signature object and AlgorithmId that we'll use + // later to create the signature on this response. + signEngine = SignatureUtil.fromKey(sigAlgName, signerKey, ""); + sigAlgId = SignatureUtil.fromSignature(signEngine, signerKey); } else { respItemMap = null; producedAtDate = null; responseExtensions = null; certificates = null; + signEngine = null; + sigAlgId = null; } - encodedResponse = this.getBytes(); } /** @@ -1436,13 +1451,9 @@ basicORItemStream.write(tbsResponseBytes); try { - // Create the signature - Signature sig = SignatureUtil.fromKey( - sigAlgId.getName(), signerKey, (Provider)null); - sig.update(tbsResponseBytes); - signature = sig.sign(); - // Rewrite signAlg, RSASSA-PSS needs some parameters. - sigAlgId = SignatureUtil.fromSignature(sig, signerKey); + // Create the signature with the initialized Signature object + signEngine.update(tbsResponseBytes); + signature = signEngine.sign(); sigAlgId.encode(basicORItemStream); basicORItemStream.putBitString(signature); } catch (GeneralSecurityException exc) { diff -Nru openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/util/ZipUtils.java openjdk-21-21.0.13+9/test/lib/jdk/test/lib/util/ZipUtils.java --- openjdk-21-21.0.12.1+1/test/lib/jdk/test/lib/util/ZipUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/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-21-21.0.12.1+1/test/lib-test/TEST.ROOT openjdk-21-21.0.13+9/test/lib-test/TEST.ROOT --- openjdk-21-21.0.12.1+1/test/lib-test/TEST.ROOT 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/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=7.5.2+1 +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-21-21.0.12.1+1/test/lib-test/jdk/test/lib/AssertsTest.java openjdk-21-21.0.13+9/test/lib-test/jdk/test/lib/AssertsTest.java --- openjdk-21-21.0.12.1+1/test/lib-test/jdk/test/lib/AssertsTest.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib-test/jdk/test/lib/AssertsTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -25,12 +25,12 @@ import java.lang.SuppressWarnings; import java.util.Arrays; -import java.util.HexFormat; import static jdk.test.lib.Asserts.*; /* * @test + * @bug 8340493 * @library /test/lib * @summary Tests the different assertions in the Assert class */ @@ -49,6 +49,29 @@ } } + // equals() always returns true + public static class Bar { + private final int i; + public Bar(int i) { + this.i = i; + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean equals(Object obj) { + return true; + } + + @Override + public String toString() { + return Integer.toString(i); + } + } + public static void main(String[] args) throws Exception { testLessThan(); testLessThanOrEqual(); @@ -62,6 +85,19 @@ testTrue(); testFalse(); testFail(); + + testErrorMessages(); + } + + public static void testErrorMessages() throws Exception { + try { + Asserts.assertNotEquals(new Bar(1), new Bar(2)); + throw new Exception("Should fail"); + } catch (RuntimeException e) { + if (!e.getMessage().contains("was 2")) { + throw new Exception("msg is " + e.getMessage()); + } + } } private static void testLessThan() throws Exception { @@ -216,8 +252,7 @@ " to throw a RuntimeException"); } - private static void expectPass(Assertion assertion, byte[] b1, byte[] b2) - throws Exception { + private static void expectPass(Assertion assertion, byte[] b1, byte[] b2) { if (assertion == Assertion.EQBA) { String msg = "Expected " + Assertion.asString("assertEqualsByteArray", Arrays.toString(b1), Arrays.toString(b2)) + " to pass"; diff -Nru openjdk-21-21.0.12.1+1/test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java openjdk-21-21.0.13+9/test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java --- openjdk-21-21.0.12.1+1/test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8349759 + * @summary Test the CertificateBuilder and SimpleOCSPServer test utility + * classes using a range of signature algorithms and parameters. + * The goal is to test with both no-parameter and parameterized + * signature algorithms and use the CertPathValidator to validate + * the correctness of the certificate and OCSP server-side structures. + * @modules java.base/sun.security.x509 + * java.base/sun.security.provider.certpath + * java.base/sun.security.util + * @library /test/lib + * @run main/othervm CPVAlgTestWithOCSP RSA + * @run main/othervm CPVAlgTestWithOCSP RSA:3072 + * @run main/othervm CPVAlgTestWithOCSP DSA + * @run main/othervm CPVAlgTestWithOCSP DSA:3072 + * @run main/othervm CPVAlgTestWithOCSP RSASSA-PSS + * @run main/othervm CPVAlgTestWithOCSP RSASSA-PSS:3072 + * @run main/othervm CPVAlgTestWithOCSP RSASSA-PSS:4096:SHA-512:SHA3-384:128:1 + * @run main/othervm CPVAlgTestWithOCSP EC + * @run main/othervm CPVAlgTestWithOCSP EC:secp521r1 + * @run main/othervm CPVAlgTestWithOCSP Ed25519 + */ + +import java.math.BigInteger; +import java.security.*; +import java.security.cert.*; +import java.security.cert.Certificate; +import java.security.spec.*; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import jdk.test.lib.security.SimpleOCSPServer; +import jdk.test.lib.security.CertificateBuilder; + +import static java.security.cert.PKIXRevocationChecker.Option.NO_FALLBACK; + +public class CPVAlgTestWithOCSP { + + static final String passwd = "passphrase"; + static final String ROOT_ALIAS = "root"; + static final boolean[] CA_KU_FLAGS = {true, false, false, false, false, + true, true, false, false}; + static final boolean[] EE_KU_FLAGS = {true, false, false, false, false, + false, false, false, false}; + static final List EE_EKU_OIDS = List.of("1.3.6.1.5.5.7.3.1", + "1.3.6.1.5.5.7.3.2"); + + public static void main(String[] args) throws Exception { + if (args == null || args.length < 1) { + throw new RuntimeException( + "Usage: CPVAlgTestWithOCSP "); + } + String keyGenAlg = args[0]; + + // Generate Root and EE keys + KeyPairGenerator keyGen = getKpGen(keyGenAlg); + KeyPair rootCaKP = keyGen.genKeyPair(); + KeyPair eeKp = keyGen.genKeyPair(); + + // Set up the Root CA Cert + // Make a 3 year validity starting from 60 days ago + long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); + long end = start + TimeUnit.DAYS.toMillis(1085); + CertificateBuilder cbld = new CertificateBuilder(); + cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany"). + setPublicKey(rootCaKP.getPublic()). + setSerialNumber(new BigInteger("1")). + setValidity(new Date(start), new Date(end)). + addSubjectKeyIdExt(rootCaKP.getPublic()). + addAuthorityKeyIdExt(rootCaKP.getPublic()). + addBasicConstraintsExt(true, true, -1). + addKeyUsageExt(CA_KU_FLAGS); + + // Make our Root CA Cert! + X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate()); + log("Root CA Created:\n%s", rootCert); + + // Now build a keystore and add the keys and cert + KeyStore.Builder keyStoreBuilder = + KeyStore.Builder.newInstance("PKCS12", null, + new KeyStore.PasswordProtection("adminadmin0".toCharArray())); + KeyStore rootKeystore = keyStoreBuilder.getKeyStore(); + Certificate[] rootChain = {rootCert}; + rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(), + passwd.toCharArray(), rootChain); + + // Now fire up the OCSP responder + SimpleOCSPServer rootOcsp = new SimpleOCSPServer(rootKeystore, + passwd, ROOT_ALIAS, null); + rootOcsp.enableLog(true); + rootOcsp.setNextUpdateInterval(3600); + rootOcsp.start(); + + // Wait 60 seconds for server ready + boolean readyStatus = rootOcsp.awaitServerReady(60, TimeUnit.SECONDS); + if (!readyStatus) { + throw new RuntimeException("Server not ready"); + } + int rootOcspPort = rootOcsp.getPort(); + String rootRespURI = "http://localhost:" + rootOcspPort; + log("Root OCSP Responder URI is %s", rootRespURI); + + // Let's make an EE cert + // Make a 1 year validity starting from 60 days ago + start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); + end = start + TimeUnit.DAYS.toMillis(365); + cbld.reset().setSubjectName("CN=Brave Sir Robin, O=SomeCompany"). + setPublicKey(eeKp.getPublic()). + setValidity(new Date(start), new Date(end)). + addSubjectKeyIdExt(eeKp.getPublic()). + addAuthorityKeyIdExt(rootCaKP.getPublic()). + addKeyUsageExt(EE_KU_FLAGS). + addExtendedKeyUsageExt(EE_EKU_OIDS). + addSubjectAltNameDNSExt(Collections.singletonList("localhost")). + addAIAExt(Collections.singletonList(rootRespURI)); + X509Certificate eeCert = cbld.build(rootCert, rootCaKP.getPrivate()); + log("EE CA Created:\n%s", eeCert); + + // Provide end entity cert revocation info to the Root CA + // OCSP responder. + Map revInfo = + new HashMap<>(); + revInfo.put(eeCert.getSerialNumber(), + new SimpleOCSPServer.CertStatusInfo( + SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); + rootOcsp.updateStatusDb(revInfo); + + // validate chain + CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); + PKIXRevocationChecker prc = + (PKIXRevocationChecker) cpv.getRevocationChecker(); + prc.setOptions(EnumSet.of(NO_FALLBACK)); + PKIXParameters params = + new PKIXParameters(Set.of(new TrustAnchor(rootCert, null))); + params.addCertPathChecker(prc); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertPath cp = cf.generateCertPath(List.of(eeCert)); + cpv.validate(cp, params); + } + + private static KeyPairGenerator getKpGen(String keyGenAlg) + throws GeneralSecurityException { + String[] algComps = keyGenAlg.split(":"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance(algComps[0]); + int bitLen; + + // Handle any parameters in additional tokenized fields + switch (algComps[0].toUpperCase()) { + case "EC": + // The curve name will be the second token, or secp256r1 + // if not provided. + String curveName = (algComps.length >= 2) ? algComps[1] : + "secp256r1"; + kpg.initialize(new ECGenParameterSpec(curveName)); + break; + case "RSA": + case "DSA": + // Form is RSA|DSA[:] + bitLen = (algComps.length >= 2) ? + Integer.parseInt(algComps[1]) : 2048; + kpg.initialize(bitLen); + break; + case "RSASSA-PSS": + // Form is RSASSA-PSS[:[:HASH:MGFHASH:SALTLEN:TR]] + switch (algComps.length) { + case 1: // Default key length and parameters + kpg.initialize(2048); + break; + case 2: // Specified key length, default params + kpg.initialize(Integer.parseInt(algComps[1])); + break; + default: // len > 2, key length and specified parameters + bitLen = Integer.parseInt(algComps[1]); + String hashAlg = algComps[2]; + MGF1ParameterSpec mSpec = (algComps.length >= 4) ? + new MGF1ParameterSpec(algComps[3]) : + MGF1ParameterSpec.SHA256; + int saltLen = (algComps.length >= 5) ? + Integer.parseInt(algComps[4]) : 32; + int trail = (algComps.length >= 6) ? + Integer.parseInt(algComps[5]) : + PSSParameterSpec.TRAILER_FIELD_BC; + PSSParameterSpec pSpec = new PSSParameterSpec(hashAlg, + "MGF1", mSpec, saltLen, trail); + kpg.initialize(new RSAKeyGenParameterSpec(bitLen, + RSAKeyGenParameterSpec.F4, pSpec)); + break; + } + + // Default: just use the KPG as-is, no additional init needed. + } + + return kpg; + } + + /** + * Log a message on stdout + * + * @param format the format string for the log entry + * @param args zero or more arguments corresponding to the format string + */ + private static void log(String format, Object ... args) { + System.out.format(format + "\n", args); + } +} diff -Nru openjdk-21-21.0.12.1+1/test/lib-test/jdk/test/lib/security/FixedSecureRandomTest.java openjdk-21-21.0.13+9/test/lib-test/jdk/test/lib/security/FixedSecureRandomTest.java --- openjdk-21-21.0.12.1+1/test/lib-test/jdk/test/lib/security/FixedSecureRandomTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/lib-test/jdk/test/lib/security/FixedSecureRandomTest.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * 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. + */ +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import jdk.test.lib.security.FixedSecureRandom; + +/* + * @test + * @library /test/lib + * @summary ensure FixedSecureRandom works as expected + */ +public class FixedSecureRandomTest { + public static void main(String[] args) throws Exception { + var fsr = new FixedSecureRandom(new byte[] {1, 2, 3}, + new byte[] {4, 5, 6}); + var b1 = new byte[2]; + fsr.nextBytes(b1); + Asserts.assertEqualsByteArray(new byte[] {1, 2}, b1); + Asserts.assertTrue(fsr.hasRemaining()); + fsr.nextBytes(b1); + Asserts.assertEqualsByteArray(new byte[] {3, 4}, b1); + Asserts.assertTrue(fsr.hasRemaining()); + fsr.nextBytes(b1); + Asserts.assertEqualsByteArray(new byte[] {5, 6}, b1); + Asserts.assertFalse(fsr.hasRemaining()); + Utils.runAndCheckException(() -> fsr.nextBytes(b1), + IllegalStateException.class); + } +} diff -Nru openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/java/security/HSS.java openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/java/security/HSS.java --- openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/java/security/HSS.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/java/security/HSS.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,388 +0,0 @@ -/* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.openjdk.bench.java.security; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Level; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Param; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; - -import java.io.IOException; -import java.util.HexFormat; -import java.security.ProviderException; -import java.security.PublicKey; -import java.security.Security; -import java.security.Provider; -import java.security.KeyFactory; -import java.security.Signature; -import java.util.concurrent.TimeUnit; - -import sun.security.util.RawKeySpec; - -/** - * Benchmark measuring HSS/LMS - */ -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.MICROSECONDS) -@Warmup(iterations = 5, time = 1) -@Measurement(iterations = 5, time = 1) -@Fork(value = 3, jvmArgs = {"--add-exports", "java.base/sun.security.util=ALL-UNNAMED"}) - -public class HSS { - - static byte[] decode(String s) { - return HexFormat.of().parseHex(s - .replaceAll("//.*", "") - .replaceAll("\\s", "")); - } - - public static Signature getVerifier(byte[] pk) throws Exception { - var kf = KeyFactory.getInstance("HSS/LMS", Security.getProvider("SUN")); - var pk1 = kf.generatePublic(new RawKeySpec(pk)); - - var vv = Signature.getInstance("HSS/LMS"); - vv.initVerify(pk1); - return vv; - } - - public static void verify(Signature v, byte[] pk, byte[] msg, byte[] sig) - throws Exception { - v.update(msg); - if (!v.verify(sig)) { - throw new RuntimeException(); - } - } - - @State(Scope.Benchmark) - public static class test01 { - byte[] pk; - byte[] msg; - byte[] sig; - - @Param({"Test 1"}) - private String test; - - @Setup - public void setup() throws Exception { - pk = decode(""" - 00000002 - 00000005 - 00000004 - 0e975b10a6b33473d01baa138c155e81d7b7156b389b2a6a09d49f42c1ac4984 - 2d977e65fceb6bc80e06eace38ce0116 - """); - msg = decode(""" - 312e20546869732069732061207465737420666f72204853532f4c4d53207768 - 6963682069732076657279206c6f6e6720616e64206e6f74206d65616e742074 - 6f207265616420627920612068756d616e206265696e672e - """); - sig = decode(""" - 00000001 - 00000005 - 00000004 - a63c20fdbd752910d2a87d25c4ba6bb233d5dd363e5f44a25f766a477f13aa79 - 1474acc5f205d27f1f89234282a2f27205bb914efa34ea8bdd8d7eab6e748614 - 79b5e6088451c07b079196d0d897edc8974e3d2fa244e38242c6831b9124a298 - ed74872b0c6c5cd1c25fcc5279fb1bc30d4b1ee122b9292aedbcfd7e49d4d54b - a1a330d88774e6de909a81624c3440b687495758c83b0439fb104d9e7a695a9e - 62247b52162121c1a80999d11e4211cd23c374a1a23e57dfc49792427806276f - c03cc2d0958990c030e2f8c85e2922547e4ae4918833357ed8ff16ae189fbc76 - 1da5a2e02f824d4ebd8ff731f9c3a8268d3056c1917129a918981bb35079a73b - bac9cba7a99a4536ed4420def0d1ca3b9702be27c6d638fb3a8449edf699d349 - fbd44a8c80985d85946d31221942541143ede3b557929c7f2de6840b0910b6ab - c0dac975200be5f36fbcb5d0ebe0c79d7c8b1218e6afa1fb487399f53ac2a10e - e70113fdc20ab4e1689122568eeeacd0da903cb56ddfe54d386e6f7ab7971878 - e3dddcf7f78e31ce95c9aa6dfa26501027e42f7066ee5a94c4ccf6647d85776f - b244ffa85794e873a12634a5468967f05a9a5efc4276944ec9664aaf9b684db4 - bd417669f2e151f174ae1eed01565b563eabf8177fbbeb2ab61667dcb7423a86 - 2dbea29581cada5c0ebab53c0811ec8ebab234b7dbb30456837e82bd5e23e8a8 - a75f4331a4da821abc63d50b1bdc4bd861a0ba1ebfad6db2fd5d44e587ce9bf3 - 095f314be58411b4b2ea5f0fd10bf091c5038bb8290b5964d6f24edb2aecccf2 - eb81cbcecaf1e1320853e326a8af9bb1f456105ea58b42ae9d994e35c505a74b - 50e04e406b247ff34e3ba27ddb4d7d2a6ade1e2652c25da88a8c6a76024c7c7d - 7e879597438e608741ac8bd3f35c9212db9978d7d54fda331df3e302e3b59201 - 4be842a48a0abc58f5421c8f9d32e191aad082ac04bde2e3695e346d2af5e20a - 00c232def87a5a3dfca8809b1260a43403242b303197a5329b951632aab0738c - b45a51c76f1c97a6c836f40c5165e0c68c16a8ab50b078c2b8fe09f280838648 - c6c74d59fc2c1a46ce424e28bdc7c44a683902b06e9995c67e4efd3981f5424a - 3930100b11bf7ef17c99c5d27a661e8d366ee49441278959c59e7af1ae25bd93 - a504291b3e834c5b68c1e84ee885c6e0152c7cf015aac2065ec19ba3b16166b9 - 02621389a60efea12d8b4a5b5d59ab8145c804bb45694d443b09d4111faa2ba6 - e7e48d3bfa3d1c48b427f383b393c7d0e422fd1e958e14e5866cf6dfd06764c0 - fe384c6ae8e1650860dbc12b0e2731ece7ea40e11fdeba8ae7dff74375d7d717 - 2ab0fb15d6c40b1677a2079b5a4af563fc4c08363176ce4da74b1ef34b0b8627 - 1d405a442b60a554fa88d0320363e7b818bf532d3fbc52764479886d3f4d3d7b - b35d0402b17025abad9cc1525e722cca4c961497f784e55f46d8f8067e4705c3 - 6b62c260391575cfaa949ad99a98e9ca2a55d4e2241c33b3dd8b2505a804c6f7 - 67617d02ebaefaa6cd02cc93041395d1c47be820abc647bd531549aee307cbca - 00000005 - d443111b4f3c3e02ea3043a3db682e8720e10e67852a4331f55deaf62ff8673b - fc8e3fed9740f6cd4a276556c40de3ce8c7c0e60d7b2744f2a481a0d7854b703 - cc47a30d27ed823933e6d87c5573c135c0ced4c944f766de92f216756824c4a4 - d80b9d5337dee0498becbd5b248920283dac655346a847f93555d9a469c66858 - 51891eb06cdfa25179c9054ee8795477c4806df8790becc8eb9ea458656f82a1 - 00000005 - 00000004 - bb8df6a42d2b9f29644c2c99967d2cc569b3a8470a960d6fa954aafe5e15660a - 9fa56cc9a583d7b1dab98da3e6c121c1 - 0000000a - 00000004 - 3431bace4875824faf76e488612472b3a535893056745f0f20e615806d87ba36 - ab0935d2b080fd6281fa5fca325926ba219c04a02aa2e2faca7ba0f885cb90ce - 5bf07a6dfb60f55541092cbb9386ab47438debaed31b648cb3cab090ab2c3eaf - 386a2024899e4cb83e75340933c564a22c060e5ac792316123d004125babf59e - 082dc93d4817ab8a7cd772fe28a400060ca4dcecc001203a474f294031c44dcf - ebc3c73f672556cda6ad193883c5c95fb1587042b733f936dc0977cbc4aa13b9 - fd22794a7204968e0cdb73cc19061447617bfdcef141fb9b87538232d92b1482 - 54b0917f252efc8766d6b09b0215c675ab5d41c87630121e5e536bcfea3fc134 - f57de38eff427a531ed403d903c1c96b5fd71d8431c03ca8d521a2c686051e0a - 5a57e199d65b0a60a086f70a3e42ad6b343e5565e996e7bb678ebdc1e01f9041 - 289f45c3e0f56e5aeb269cfe70deca17153ee46388ac0d88b24ee7a32c607726 - 1664a5d10fb5f64ed925351b2475494920acb7272962da31c8db6f76baadbc83 - 9d94373f8a203ac3c62fad998913277153e1db8872f75cb3ab18f4b6ae785d35 - 54785bd261b66535f34a756e8749f6d2a6049c9bf8aa991b1c5d79eae63ebde0 - 99f853608dae24d68d4709c0898bf1e1fb44198a23fd7a7ecd653db67688153f - f2a1c399cb3379903e31e4c4f06ef50671eb071a2084d16b08270ff203d51c1a - 5334d777d169c331db8e3e1c6653649d69cf1a3853423c7de5e688b10d741aa3 - 5233ef53440db7a3bd6b9a613183820ea7ec1e7469d1743cf1d8aefb599f6f1c - 08865c99afd652558b73955734b36794351c246c9822e96bc276cfa7cd942f6a - afcdb162a361332ee79a128c6ccf67d0ae3dec0b0a80e716c572162e9eb9230d - 83c3d758d4efecdfb573864f7fc1f203cf0c64d2fc9a68029ea67d7e53885c60 - c7dffc6e1af3c0460a64a8b21c62107f7a3408b724e478d0018eaee33e60350b - 7e355758d236bf8fbaa82d43955a9df4a5073ab1eab25269e89c9278097ed20c - 0d46b0722c9a0ab613ae09a5220dfffb930f013f83262f524061fb47f16dde4e - 48ba37d1e73c5b63bfd3f80ea1b36ad690476e0338271555de0e8a88a2f4ec14 - e05ab9753633ee4b792a715c6c7c1d01209619c4a4070235fb1022781f5ee437 - 8514cf87b6b274bcf25551fec891fba127dcf09bbbaad957ea1e4f512b64d787 - f32538f53fdffe99e3914e9c9815c812b0bc6c1aee4d9d5a5cacd7f0d6f5ecc5 - 958a595788400787615d3ab0bccdf9fc94c6bcf7154c0975d90fb60fafe0834a - 1cd44979b52548c875094b1adc9c63b5de19f3e888db7a0b7a2c238b4090c55f - f57734c24e69df21697c650c1d8f5f62e067bda229e4ec3e9da93e6fa76a9ff9 - 48327baba8c7b8b14a63291fd7fd6847e20f6653edabbc21e257827be4089fbc - 39047197e40ad2553bcdc603c82a1b80c03bf5a461f31e073295a4cbbc02530f - be5a6c3092813f37ae9e2ec7ee8c0dc1a2379cbcfe2ad550e90f0a73f4e789a1 - 270a3332e277e7113ed38527c241817d391b5a2742b6a4cb789a407525f35982 - 00000005 - e6ffc1535a60978d93a81a64564b61821c7125542c0fe5996a93e0da0f5f8a71 - 2d2e444d1bd96837bf0354ca844e90b82bf08746bbc95189e2268bfa686e88f9 - f90f35a095a2ab26402fc87ddf3656edfb16fe3816ffaf99e983915ebbcf2f51 - 85f294d491c47fb90d3ce9046d2f05da6a723ac342a32154d1c18b465b49308f - 41ca2f0475adf5ed46413766a6057bc810aeb6dd593691b84752b883c8a1a422 - """); - } - } - - @State(Scope.Benchmark) - public static class test02 { - byte[] pk; - byte[] msg; - byte[] sig; - - @Param({"Test 2"}) - private String test; - - @Setup - public void setup() throws Exception { - pk = decode(""" - 00000002 - 00000006 - 00000003 - ff466afe664c2581845b2c6af92aeb6e5c4dd15affc86c82ef4e807ad3c648a6 - 4561666c975fd9cb150d6c7acd6e577f - """); - msg = decode(""" - 322e20546869732069732061207465737420666f72204853532f4c4d53207768 - 6963682069732076657279206c6f6e6720616e64206e6f74206d65616e742074 - 6f207265616420627920612068756d616e206265696e672e - """); - sig = decode(""" - 00000001 - 00000003 - 00000003 - 8b0b372cbd26c8e43b5feee870169c7c8345f7d353980ec3f6f6b81c696c672c - 7d0cfc8f74de7a0950f30151ab06c218c4ca0dc425a713060e1f14a3009ed09f - 565b6f6a07d6fee14a618a34fd02dd43745c7c11572f3e2c9a7d7c80d1d16e5c - ca11706861fb5359bb1a8e78d2da42d528d913cc593b414fe8ceb03e71171fb6 - 6722dd5677c5bd6446c372356e8d4dba0da50ce696b80deeac51fac231e59241 - 84706f9dd5820a430a1d0404071a3ce75f14a8fbee1573ad893cf2f5dea0fe21 - f899305b15fb971b785cb7432ca8a92b13fe055d7a1ddc46628b9591291bceba - 0c9c6d76d8c24b919c2c1b6d5c1dcdcfc177e6c7ac67ef0af08222d6780bd686 - 439b78a5575494330d824b8b6962652b15b3d5d4f8ce2216033741f51b6e3aab - c69817097649124460c9ddd7ffb14df8ed1de436f0958e193ba118334fc12859 - 68ae32b6c3d1af8b8c95e4a620e442efb221ae5eb1953c7b8dfe645587916a4e - c26f60ca2b088accfcf5f8f724b558c527f31cf3ed9311315a629d81f2702704 - 56f237d745ea92ba6777d934df150ed9b3e10ce5a8a16011118081287463793c - 3818c2448b10e1ede5bfa8da646d9417a97ae70db9aa8df030c6019dab6ebb18 - 6b9d4db14b3d9b33d1df3b23169963e371e2ec25bc3d932b8503ccbbe85d5675 - c433e62b5926de825420727da4c6bd70dd93fc4fcf9062d4f2acb96699b910db - 9788ffd122d88911f98e12fc57551b8282e5f296cc0dd075121c88e1a5838c3e - 239e2968af2eceec9ee4f7c3433d3145f2b7345d7c418febd0839fd45771debe - 52c0cefb71a38b55ddfb9b8386ec6e7fb39047df9e963d056d6e0b02a2620ba1 - f58264de9b09347ac0320919df80e5a66ebee3d6e801792b19a31c07cf28fff5 - 85b4788aec445d4d04ca005f6a240d8e90c6bc2398df5ec6a9a1858549b67026 - b6c4a91d10faf47fcc7afa56d228d0518fb7a786d2f24decc476203fd84150e9 - 165f11ec6eb168934bb7055ae2ae0f499ec8205565fcd397c6cb1c8f0bafa90f - 6c61a08a4657a19009085217ac255081bf280c726f2c818c543bde5fd2a67549 - efccf9e0d35144f5c8af2c69dda3b01b7333a31d6d6210475f0168db67c22940 - 4d36818b6d530fb23941ae4c63226ec6135e598c879d6ab88928f84da104ee82 - 30d96494b818b9d7004b2f15c7565dee0f611d1faf2ef538c70f2c08919e7919 - 25b81e658743cf8903e40a1323bec2530288820f2c46e85f0622e50eed0a93fe - 5cf92db7d672d2d3186710c0b7e509afd1d498cb21936befc8029c936f9e1f6c - 587071dae0b5999e407929199f4bf03dea05bded0ddc6ccba2a8e880e972f876 - 142c99fbefd3a362b27416cc2aadd8c595ab31cc53af7cfd87362118e9cb409c - 32cf3600eecd314073e8393fe390e3ed60d105a7d054143227874e96a1a16ce8 - 1f9a17f03aa647ef08670e5ba7e561c025775a574ee84bd294b808c2908b7112 - d02f4d6462be588bf27d418545a64dc6fc472e743c913bf7f702356872166a4c - 9fcda456ca69651832c72786546a9e9011511bfdf7351f2333f944ac82e5f14e - a1be1ad7b0b01caf273c9f3ef540cc79c47c7b32a8febcf8e3c34a3a0641e09a - fbcb9a1c6bbf594e44faad8671d6e4c9d8bc053db2ebdd2e22ddd8a154462b23 - 6b47d1fc2205a4e7405d8e883189d8b863b31152459e602bc6c30d0baed658a6 - 4f2ac6858ea5e11ac3fae173f1a251cd7e5b26693bf994a952cc12a9b684a919 - 77510077cc11002a325697eb0a7f86f7b45275e13e89d959a593d51c98cbb48f - bea795ac5d5e61c4360431bb0712096c1e88a03d2367b2772f34ca938a4c0180 - 68aa0f90314b6b23ae01437178bbf812590e347a7759581748d877a31c94a7eb - 9e839b0f2654a354faae234a819fbab9c32374f3b99ea7deb42e6a169e03d59a - 0ff3a6b4809059fcd4e5c426e5d580f6fff8e49be1c9a1baacad5b1cf0284060 - 6969a2c6d04fbb30952ea3f792a60e517cdd3cd8f427c335b9a66ba6ac321657 - beb77de5e2b8d4a8f5c425665b9cadd6a379b7ef5ba513cfb2b2022d8e057637 - 38d0edad6a24b1e57d7ebd11434a1e6fb00c1f5f9228bcdd2f24c468b7b4408c - 35b54e09fe59ed0dbab9760b3fe415c277e39a0bdd74783d7d0feb4d7428b609 - 319f8e667899fb52c822076dfd07286d8c6058c2fcf8618cb77d0ba1077f49c8 - 8f8ef55e980307dfa8d9a3076d8a7ba32f1c822e1c6bf7beb997e03181bade32 - b0b69507210466acd24cc9e13e4913c7e31dbfcf84021fe947e37f469de19488 - 097852097888f11de144fc03606c68d63c7309c054853e1c66ca1b499898fd8b - 5edc934e7f368022c2576e18db909b88a8f9c6caa5fdc00f7da47995ad2e21f9 - b9e3133321ec6e7f6d43ee30b5376b846ce6390e1168b0543e4a50d961f82588 - 58569f6a98e5bcad0dd90c4b88e982f34e7ad2897d8218aaa9284d947ddba4eb - 25a1f02ea59504d82c1e570a2804dd9fbde7dfaaa40996e9aeb0a3d65c27e3cf - d81005ad070375c868ac754bd849700c52b10828deab05eefd2d0575a3ef7338 - d7ae9fe2c1c6c0f38abb7a63381a6903035ce87b93e0c4927e6b15a32d8bf86c - fd9f9bd21366a2a264ebf96bb1213ae8bf7e193bd3eb041a7beebc8d5c474b2d - 1a2afd2488dd1f5176e99b11d6986bd8a30f2c4de7abc0a8b9d18e591c2e7deb - 05944d7661cce336f0c08ed3283a8500d91030e2553b1fa7839ff232ac8f70ee - e1656c964a627bec73bf015b10b59551a38cc0a7b95b4cce2f8292ea28c85c20 - d51a97d0e0c59f99b9af2fc7585cb97999c298885522e6bd8a102cbeb891eeca - a7d3a2402c0a00ab85f66f0267fbb707ea1052f1f926e4328bfc31cbbfab6689 - 5f290ffb90970a62e506ef39513a7d3792c0c3f8d7cd285db8326c6b0d5d4323 - 261ef9ccaefb1fa8e68b9de82345578729904ad9de4f2c5640fddef0c4f54ca2 - e12115befeecd8145be43d3ade502970e255cae2af3cc221569592056eb9f61f - fe511566f235325bac531d8b25bcbf31429426d002f265a4971927246efe218e - 00000006 - c3aba396848a87900478ae558564722df671d145ad178dd9ef736fc5c353a8db - 82e4d9999c4c2e0fae928a66cd3aaf71678ff745d5726d65b0dd6a0ee5f85ca5 - cecd79ef77e4aa47d284a0bdb71662148029d8d891e2381bb7e6045efae1f641 - 505c4b31a8d5acae51cbef029b047e52a5b495aabeae20ee94f8c56ae9b0ac6c - 2d01207d212698865cb0a47e73b6247e777118a617c4b49a558dd4f1d0886f19 - cc2344598bf5cd9039bf7879d37abc66aa3947caf939425adc599d3d1190747c - dce7f61a12f92bd2c1ad95eda9a3b2af26c8ee652b9be2f36e1f80b2ef37bd23 - 2a0d94cc605402848df45afd8ae36d729b25f00d1a09e8fbac6e323669227506 - d0b7b2bab0b320bf58e69a6879e67880c6818ce83f8630c91ab0e82a3f54ceeb - 1053a66d540d800956b248e951695e52c4290014c4fd7eee8c93393e593cf54c - 00000005 - 00000004 - 0f5cf24b2d72360a58d71392202a49fbef628a53b11e3617bbc1723a879a89e4 - c64e0e5dea7faf8cac58d4e7fcd71774 - 00000004 - 00000004 - 4849cdc5ce9923584e66bda4a1e96c856ead6a30672d94cab9ba1dcffe30843a - 646bd1ecba04f13bf7c6d7d8aabebfa8cb9a2190cd93d65d921ab7035cc81951 - d073609e5dedeb6ef7d00e2ed4c2680772077a9ce3f99ca74eb97f91339a81b1 - bb1c0dc10ad799ea594d4e7760463b4e441661c5f8e09ee9cc82c461dcfdf13d - 391db836b3d30fb42d33cabccb8ef9c81d054114e298a8100ac8ba9bcee4f518 - afd7bd2a158db134dd5ed299435ab7d2dc32db8b7fe35b24186e3c4b6114f7d0 - 46ba7de17e65ce9e1c5618c308c650a828d1c0f786a3d6a69ebbf04e51449308 - 868ecd7a5ce8f87f796396dc4837d08740376205249d8517a47c2ba816ab6c9c - 8bd8fd841ba4667ec53d353a661ea9e5ffa1769d981e4a31178e4f5ad3d99623 - d58c0ab2514b3c5306f3c83927f1b11a3784a384322780b100b44369f80b340f - 8212ad7f5092c44178a22a54110da8f8d3e8ac473aaa687587ea725806f44eaa - c1e340bb7aa801b455914418c1cdd6b59007f4ac5e9d519f2158762e40957507 - 3d6f30736f065bb74cd2c5d60b917cbad94af657ef37c1b92938c959e21d23f1 - 6950c38c2f6eeede9b1675dcc4b4985bf892f3a2a0ac601bcde4acde5ccdf71f - 0a850d9813f92f7279482ae2697fed0722d456d8557ab5bb3fd49421f8d2e71f - 06769fcd695fc186ecb0236051b534bb6a6641d859fd013afa975c0bf889b900 - 433581712b4b04c758fc121deea327817456f70135c3db767e16041f933186c4 - 081fe52635b917bc809c2063d035e14fb512a452c8f443f2a66362ea6b08ddd1 - 6d3a04065611cc962ccad06598fce7821837302ba00d57a83654130f582ce62c - 3266cae361d7db6f2b740ed7f90dca1ff4bf9ec4a0b7cbce226390bc2c38b3bf - a27a40508139f985749420e6fc4ebafcf4799248661e1134e5442f1ef8714739 - 1d589b45ecb61ac90ad6f82cb2bc3f006b62c40dcda5c362b5d4a8c56e42f672 - 1b8598de29d5d6c1293b3751d48ccff5c5805a59a41c00a6758913c86861f2ad - 2400f93fec76e1062db46e4e21f70d7881b7c91bafb9cd34afbfb05ce072fb3d - d4d9970ea49b57ed3ac73a2d75973f8d2a29de6e963d10bc62b695359d5807ed - 7ea0eb6908207698d08e96b619755872e840248550f053cc2597a65df404577d - 828c4604dc143cd42df691daae06a50502d7ad26d577478a00131fb4de24e780 - 39b56b4fb1408a26fa72a9f5db80fe39e49e414a27d57ab3abef508628812bea - 6f61e9e182148ddd920efb7493d3b68a79c3946c8dec31fe6963e8c2dea92dd7 - 9f789b20036b493bbdf605f45654498b93493181b71f261194f1faa6180f23ae - 6417720055d0b966a650e5f217bbfb1c711470fc9014874f8283d6efcabed894 - ec72f5887580f5fb9eb5e9be81a9e1f8ad650acd07069d499720815d052f4e11 - 8d14be427742a206f275a1b6570f684feb8c4cd62cbc89d0a93de601a7f0ff40 - 4125b7d29c1820d0b26490efde697f1699f4490a8b5db33a07af8df86da46817 - 2ebb99d63c45a3786d2be23395d5761f1c59ee591e5ecf35ba5cf2b5d39e8615 - 00000005 - 2510a21e43c9b53b86557646b2c891ba432813ca61fffb57c4a8e598753542c1 - a179d3af5254a37c01eeb4393d626771858d06041c76f1960e754e9e04aeb91b - 1d9b7736193f49e15c47f44a8f1c8aca6133c34eeb682fdccf94886fe80d971a - b4a0bb3b72197d2d5b2111da8647be1675983e8ed1c0d8ec7cada282dc698656 - 95f1e8806c7892b65fc17103ee3b5366b3fe31e57e653336be283962f488eaa5 - """); - } - } - - @State(Scope.Thread) - public static class verifier01 { - Signature v; - - @Setup - public void setup(test01 test) throws Exception { - v = getVerifier(test.pk); - } - } - @State(Scope.Thread) - public static class verifier02 { - Signature v; - - @Setup - public void setup(test02 test) throws Exception { - v = getVerifier(test.pk); - } - } - - @Benchmark - public void verify01(test01 test, verifier01 v) throws Exception { - HSS.verify(v.v, test.pk, test.msg, test.sig); - } - @Benchmark - public void verify02(test02 test, verifier02 v) throws Exception { - HSS.verify(v.v, test.pk, test.msg, test.sig); - } -} diff -Nru openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/full/HSSBench.java openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/full/HSSBench.java --- openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/full/HSSBench.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/full/HSSBench.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.javax.crypto.full; + +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.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import sun.security.util.RawKeySpec; + +import java.security.KeyFactory; +import java.security.Security; +import java.security.Signature; +import java.util.HexFormat; +import java.util.concurrent.TimeUnit; + +/** + * Benchmark measuring HSS/LMS + */ +@Warmup(iterations = 3, time = 3) +@Measurement(iterations = 8, time = 2) +@Fork(value = 5, jvmArgs = {"-XX:+AlwaysPreTouch", "--add-exports", "java.base/sun.security.util=ALL-UNNAMED"}) +@OutputTimeUnit(TimeUnit.SECONDS) +@State(Scope.Thread) +@BenchmarkMode(Mode.Throughput) +public class HSSBench { + + @Param({"HSS/LMS"}) + private String algorithm; // do not change. Added for visibility + + static byte[] decode(String s) { + return HexFormat.of().parseHex(s + .replaceAll("//.*", "") + .replaceAll("\\s", "")); + } + + public static Signature getVerifier(byte[] pk) throws Exception { + var kf = KeyFactory.getInstance("HSS/LMS", Security.getProvider("SUN")); + var pk1 = kf.generatePublic(new RawKeySpec(pk)); + + var vv = Signature.getInstance("HSS/LMS"); + vv.initVerify(pk1); + return vv; + } + + public static void verify(Signature v, byte[] msg, byte[] sig) + throws Exception { + v.update(msg); + if (!v.verify(sig)) { + throw new RuntimeException(); + } + } + + public static class TestData01 { + static final byte[] pk = decode(""" + 00000002 + 00000005 + 00000004 + 0e975b10a6b33473d01baa138c155e81d7b7156b389b2a6a09d49f42c1ac4984 + 2d977e65fceb6bc80e06eace38ce0116 + """); + static final byte[] msg = decode(""" + 312e20546869732069732061207465737420666f72204853532f4c4d53207768 + 6963682069732076657279206c6f6e6720616e64206e6f74206d65616e742074 + 6f207265616420627920612068756d616e206265696e672e + """); + static final byte[] sig = decode(""" + 00000001 + 00000005 + 00000004 + a63c20fdbd752910d2a87d25c4ba6bb233d5dd363e5f44a25f766a477f13aa79 + 1474acc5f205d27f1f89234282a2f27205bb914efa34ea8bdd8d7eab6e748614 + 79b5e6088451c07b079196d0d897edc8974e3d2fa244e38242c6831b9124a298 + ed74872b0c6c5cd1c25fcc5279fb1bc30d4b1ee122b9292aedbcfd7e49d4d54b + a1a330d88774e6de909a81624c3440b687495758c83b0439fb104d9e7a695a9e + 62247b52162121c1a80999d11e4211cd23c374a1a23e57dfc49792427806276f + c03cc2d0958990c030e2f8c85e2922547e4ae4918833357ed8ff16ae189fbc76 + 1da5a2e02f824d4ebd8ff731f9c3a8268d3056c1917129a918981bb35079a73b + bac9cba7a99a4536ed4420def0d1ca3b9702be27c6d638fb3a8449edf699d349 + fbd44a8c80985d85946d31221942541143ede3b557929c7f2de6840b0910b6ab + c0dac975200be5f36fbcb5d0ebe0c79d7c8b1218e6afa1fb487399f53ac2a10e + e70113fdc20ab4e1689122568eeeacd0da903cb56ddfe54d386e6f7ab7971878 + e3dddcf7f78e31ce95c9aa6dfa26501027e42f7066ee5a94c4ccf6647d85776f + b244ffa85794e873a12634a5468967f05a9a5efc4276944ec9664aaf9b684db4 + bd417669f2e151f174ae1eed01565b563eabf8177fbbeb2ab61667dcb7423a86 + 2dbea29581cada5c0ebab53c0811ec8ebab234b7dbb30456837e82bd5e23e8a8 + a75f4331a4da821abc63d50b1bdc4bd861a0ba1ebfad6db2fd5d44e587ce9bf3 + 095f314be58411b4b2ea5f0fd10bf091c5038bb8290b5964d6f24edb2aecccf2 + eb81cbcecaf1e1320853e326a8af9bb1f456105ea58b42ae9d994e35c505a74b + 50e04e406b247ff34e3ba27ddb4d7d2a6ade1e2652c25da88a8c6a76024c7c7d + 7e879597438e608741ac8bd3f35c9212db9978d7d54fda331df3e302e3b59201 + 4be842a48a0abc58f5421c8f9d32e191aad082ac04bde2e3695e346d2af5e20a + 00c232def87a5a3dfca8809b1260a43403242b303197a5329b951632aab0738c + b45a51c76f1c97a6c836f40c5165e0c68c16a8ab50b078c2b8fe09f280838648 + c6c74d59fc2c1a46ce424e28bdc7c44a683902b06e9995c67e4efd3981f5424a + 3930100b11bf7ef17c99c5d27a661e8d366ee49441278959c59e7af1ae25bd93 + a504291b3e834c5b68c1e84ee885c6e0152c7cf015aac2065ec19ba3b16166b9 + 02621389a60efea12d8b4a5b5d59ab8145c804bb45694d443b09d4111faa2ba6 + e7e48d3bfa3d1c48b427f383b393c7d0e422fd1e958e14e5866cf6dfd06764c0 + fe384c6ae8e1650860dbc12b0e2731ece7ea40e11fdeba8ae7dff74375d7d717 + 2ab0fb15d6c40b1677a2079b5a4af563fc4c08363176ce4da74b1ef34b0b8627 + 1d405a442b60a554fa88d0320363e7b818bf532d3fbc52764479886d3f4d3d7b + b35d0402b17025abad9cc1525e722cca4c961497f784e55f46d8f8067e4705c3 + 6b62c260391575cfaa949ad99a98e9ca2a55d4e2241c33b3dd8b2505a804c6f7 + 67617d02ebaefaa6cd02cc93041395d1c47be820abc647bd531549aee307cbca + 00000005 + d443111b4f3c3e02ea3043a3db682e8720e10e67852a4331f55deaf62ff8673b + fc8e3fed9740f6cd4a276556c40de3ce8c7c0e60d7b2744f2a481a0d7854b703 + cc47a30d27ed823933e6d87c5573c135c0ced4c944f766de92f216756824c4a4 + d80b9d5337dee0498becbd5b248920283dac655346a847f93555d9a469c66858 + 51891eb06cdfa25179c9054ee8795477c4806df8790becc8eb9ea458656f82a1 + 00000005 + 00000004 + bb8df6a42d2b9f29644c2c99967d2cc569b3a8470a960d6fa954aafe5e15660a + 9fa56cc9a583d7b1dab98da3e6c121c1 + 0000000a + 00000004 + 3431bace4875824faf76e488612472b3a535893056745f0f20e615806d87ba36 + ab0935d2b080fd6281fa5fca325926ba219c04a02aa2e2faca7ba0f885cb90ce + 5bf07a6dfb60f55541092cbb9386ab47438debaed31b648cb3cab090ab2c3eaf + 386a2024899e4cb83e75340933c564a22c060e5ac792316123d004125babf59e + 082dc93d4817ab8a7cd772fe28a400060ca4dcecc001203a474f294031c44dcf + ebc3c73f672556cda6ad193883c5c95fb1587042b733f936dc0977cbc4aa13b9 + fd22794a7204968e0cdb73cc19061447617bfdcef141fb9b87538232d92b1482 + 54b0917f252efc8766d6b09b0215c675ab5d41c87630121e5e536bcfea3fc134 + f57de38eff427a531ed403d903c1c96b5fd71d8431c03ca8d521a2c686051e0a + 5a57e199d65b0a60a086f70a3e42ad6b343e5565e996e7bb678ebdc1e01f9041 + 289f45c3e0f56e5aeb269cfe70deca17153ee46388ac0d88b24ee7a32c607726 + 1664a5d10fb5f64ed925351b2475494920acb7272962da31c8db6f76baadbc83 + 9d94373f8a203ac3c62fad998913277153e1db8872f75cb3ab18f4b6ae785d35 + 54785bd261b66535f34a756e8749f6d2a6049c9bf8aa991b1c5d79eae63ebde0 + 99f853608dae24d68d4709c0898bf1e1fb44198a23fd7a7ecd653db67688153f + f2a1c399cb3379903e31e4c4f06ef50671eb071a2084d16b08270ff203d51c1a + 5334d777d169c331db8e3e1c6653649d69cf1a3853423c7de5e688b10d741aa3 + 5233ef53440db7a3bd6b9a613183820ea7ec1e7469d1743cf1d8aefb599f6f1c + 08865c99afd652558b73955734b36794351c246c9822e96bc276cfa7cd942f6a + afcdb162a361332ee79a128c6ccf67d0ae3dec0b0a80e716c572162e9eb9230d + 83c3d758d4efecdfb573864f7fc1f203cf0c64d2fc9a68029ea67d7e53885c60 + c7dffc6e1af3c0460a64a8b21c62107f7a3408b724e478d0018eaee33e60350b + 7e355758d236bf8fbaa82d43955a9df4a5073ab1eab25269e89c9278097ed20c + 0d46b0722c9a0ab613ae09a5220dfffb930f013f83262f524061fb47f16dde4e + 48ba37d1e73c5b63bfd3f80ea1b36ad690476e0338271555de0e8a88a2f4ec14 + e05ab9753633ee4b792a715c6c7c1d01209619c4a4070235fb1022781f5ee437 + 8514cf87b6b274bcf25551fec891fba127dcf09bbbaad957ea1e4f512b64d787 + f32538f53fdffe99e3914e9c9815c812b0bc6c1aee4d9d5a5cacd7f0d6f5ecc5 + 958a595788400787615d3ab0bccdf9fc94c6bcf7154c0975d90fb60fafe0834a + 1cd44979b52548c875094b1adc9c63b5de19f3e888db7a0b7a2c238b4090c55f + f57734c24e69df21697c650c1d8f5f62e067bda229e4ec3e9da93e6fa76a9ff9 + 48327baba8c7b8b14a63291fd7fd6847e20f6653edabbc21e257827be4089fbc + 39047197e40ad2553bcdc603c82a1b80c03bf5a461f31e073295a4cbbc02530f + be5a6c3092813f37ae9e2ec7ee8c0dc1a2379cbcfe2ad550e90f0a73f4e789a1 + 270a3332e277e7113ed38527c241817d391b5a2742b6a4cb789a407525f35982 + 00000005 + e6ffc1535a60978d93a81a64564b61821c7125542c0fe5996a93e0da0f5f8a71 + 2d2e444d1bd96837bf0354ca844e90b82bf08746bbc95189e2268bfa686e88f9 + f90f35a095a2ab26402fc87ddf3656edfb16fe3816ffaf99e983915ebbcf2f51 + 85f294d491c47fb90d3ce9046d2f05da6a723ac342a32154d1c18b465b49308f + 41ca2f0475adf5ed46413766a6057bc810aeb6dd593691b84752b883c8a1a422 + """); + } + + public static class TestData02 { + static final byte[] pk = decode(""" + 00000002 + 00000006 + 00000003 + ff466afe664c2581845b2c6af92aeb6e5c4dd15affc86c82ef4e807ad3c648a6 + 4561666c975fd9cb150d6c7acd6e577f + """); + static final byte[] msg = decode(""" + 322e20546869732069732061207465737420666f72204853532f4c4d53207768 + 6963682069732076657279206c6f6e6720616e64206e6f74206d65616e742074 + 6f207265616420627920612068756d616e206265696e672e + """); + static final byte[] sig = decode(""" + 00000001 + 00000003 + 00000003 + 8b0b372cbd26c8e43b5feee870169c7c8345f7d353980ec3f6f6b81c696c672c + 7d0cfc8f74de7a0950f30151ab06c218c4ca0dc425a713060e1f14a3009ed09f + 565b6f6a07d6fee14a618a34fd02dd43745c7c11572f3e2c9a7d7c80d1d16e5c + ca11706861fb5359bb1a8e78d2da42d528d913cc593b414fe8ceb03e71171fb6 + 6722dd5677c5bd6446c372356e8d4dba0da50ce696b80deeac51fac231e59241 + 84706f9dd5820a430a1d0404071a3ce75f14a8fbee1573ad893cf2f5dea0fe21 + f899305b15fb971b785cb7432ca8a92b13fe055d7a1ddc46628b9591291bceba + 0c9c6d76d8c24b919c2c1b6d5c1dcdcfc177e6c7ac67ef0af08222d6780bd686 + 439b78a5575494330d824b8b6962652b15b3d5d4f8ce2216033741f51b6e3aab + c69817097649124460c9ddd7ffb14df8ed1de436f0958e193ba118334fc12859 + 68ae32b6c3d1af8b8c95e4a620e442efb221ae5eb1953c7b8dfe645587916a4e + c26f60ca2b088accfcf5f8f724b558c527f31cf3ed9311315a629d81f2702704 + 56f237d745ea92ba6777d934df150ed9b3e10ce5a8a16011118081287463793c + 3818c2448b10e1ede5bfa8da646d9417a97ae70db9aa8df030c6019dab6ebb18 + 6b9d4db14b3d9b33d1df3b23169963e371e2ec25bc3d932b8503ccbbe85d5675 + c433e62b5926de825420727da4c6bd70dd93fc4fcf9062d4f2acb96699b910db + 9788ffd122d88911f98e12fc57551b8282e5f296cc0dd075121c88e1a5838c3e + 239e2968af2eceec9ee4f7c3433d3145f2b7345d7c418febd0839fd45771debe + 52c0cefb71a38b55ddfb9b8386ec6e7fb39047df9e963d056d6e0b02a2620ba1 + f58264de9b09347ac0320919df80e5a66ebee3d6e801792b19a31c07cf28fff5 + 85b4788aec445d4d04ca005f6a240d8e90c6bc2398df5ec6a9a1858549b67026 + b6c4a91d10faf47fcc7afa56d228d0518fb7a786d2f24decc476203fd84150e9 + 165f11ec6eb168934bb7055ae2ae0f499ec8205565fcd397c6cb1c8f0bafa90f + 6c61a08a4657a19009085217ac255081bf280c726f2c818c543bde5fd2a67549 + efccf9e0d35144f5c8af2c69dda3b01b7333a31d6d6210475f0168db67c22940 + 4d36818b6d530fb23941ae4c63226ec6135e598c879d6ab88928f84da104ee82 + 30d96494b818b9d7004b2f15c7565dee0f611d1faf2ef538c70f2c08919e7919 + 25b81e658743cf8903e40a1323bec2530288820f2c46e85f0622e50eed0a93fe + 5cf92db7d672d2d3186710c0b7e509afd1d498cb21936befc8029c936f9e1f6c + 587071dae0b5999e407929199f4bf03dea05bded0ddc6ccba2a8e880e972f876 + 142c99fbefd3a362b27416cc2aadd8c595ab31cc53af7cfd87362118e9cb409c + 32cf3600eecd314073e8393fe390e3ed60d105a7d054143227874e96a1a16ce8 + 1f9a17f03aa647ef08670e5ba7e561c025775a574ee84bd294b808c2908b7112 + d02f4d6462be588bf27d418545a64dc6fc472e743c913bf7f702356872166a4c + 9fcda456ca69651832c72786546a9e9011511bfdf7351f2333f944ac82e5f14e + a1be1ad7b0b01caf273c9f3ef540cc79c47c7b32a8febcf8e3c34a3a0641e09a + fbcb9a1c6bbf594e44faad8671d6e4c9d8bc053db2ebdd2e22ddd8a154462b23 + 6b47d1fc2205a4e7405d8e883189d8b863b31152459e602bc6c30d0baed658a6 + 4f2ac6858ea5e11ac3fae173f1a251cd7e5b26693bf994a952cc12a9b684a919 + 77510077cc11002a325697eb0a7f86f7b45275e13e89d959a593d51c98cbb48f + bea795ac5d5e61c4360431bb0712096c1e88a03d2367b2772f34ca938a4c0180 + 68aa0f90314b6b23ae01437178bbf812590e347a7759581748d877a31c94a7eb + 9e839b0f2654a354faae234a819fbab9c32374f3b99ea7deb42e6a169e03d59a + 0ff3a6b4809059fcd4e5c426e5d580f6fff8e49be1c9a1baacad5b1cf0284060 + 6969a2c6d04fbb30952ea3f792a60e517cdd3cd8f427c335b9a66ba6ac321657 + beb77de5e2b8d4a8f5c425665b9cadd6a379b7ef5ba513cfb2b2022d8e057637 + 38d0edad6a24b1e57d7ebd11434a1e6fb00c1f5f9228bcdd2f24c468b7b4408c + 35b54e09fe59ed0dbab9760b3fe415c277e39a0bdd74783d7d0feb4d7428b609 + 319f8e667899fb52c822076dfd07286d8c6058c2fcf8618cb77d0ba1077f49c8 + 8f8ef55e980307dfa8d9a3076d8a7ba32f1c822e1c6bf7beb997e03181bade32 + b0b69507210466acd24cc9e13e4913c7e31dbfcf84021fe947e37f469de19488 + 097852097888f11de144fc03606c68d63c7309c054853e1c66ca1b499898fd8b + 5edc934e7f368022c2576e18db909b88a8f9c6caa5fdc00f7da47995ad2e21f9 + b9e3133321ec6e7f6d43ee30b5376b846ce6390e1168b0543e4a50d961f82588 + 58569f6a98e5bcad0dd90c4b88e982f34e7ad2897d8218aaa9284d947ddba4eb + 25a1f02ea59504d82c1e570a2804dd9fbde7dfaaa40996e9aeb0a3d65c27e3cf + d81005ad070375c868ac754bd849700c52b10828deab05eefd2d0575a3ef7338 + d7ae9fe2c1c6c0f38abb7a63381a6903035ce87b93e0c4927e6b15a32d8bf86c + fd9f9bd21366a2a264ebf96bb1213ae8bf7e193bd3eb041a7beebc8d5c474b2d + 1a2afd2488dd1f5176e99b11d6986bd8a30f2c4de7abc0a8b9d18e591c2e7deb + 05944d7661cce336f0c08ed3283a8500d91030e2553b1fa7839ff232ac8f70ee + e1656c964a627bec73bf015b10b59551a38cc0a7b95b4cce2f8292ea28c85c20 + d51a97d0e0c59f99b9af2fc7585cb97999c298885522e6bd8a102cbeb891eeca + a7d3a2402c0a00ab85f66f0267fbb707ea1052f1f926e4328bfc31cbbfab6689 + 5f290ffb90970a62e506ef39513a7d3792c0c3f8d7cd285db8326c6b0d5d4323 + 261ef9ccaefb1fa8e68b9de82345578729904ad9de4f2c5640fddef0c4f54ca2 + e12115befeecd8145be43d3ade502970e255cae2af3cc221569592056eb9f61f + fe511566f235325bac531d8b25bcbf31429426d002f265a4971927246efe218e + 00000006 + c3aba396848a87900478ae558564722df671d145ad178dd9ef736fc5c353a8db + 82e4d9999c4c2e0fae928a66cd3aaf71678ff745d5726d65b0dd6a0ee5f85ca5 + cecd79ef77e4aa47d284a0bdb71662148029d8d891e2381bb7e6045efae1f641 + 505c4b31a8d5acae51cbef029b047e52a5b495aabeae20ee94f8c56ae9b0ac6c + 2d01207d212698865cb0a47e73b6247e777118a617c4b49a558dd4f1d0886f19 + cc2344598bf5cd9039bf7879d37abc66aa3947caf939425adc599d3d1190747c + dce7f61a12f92bd2c1ad95eda9a3b2af26c8ee652b9be2f36e1f80b2ef37bd23 + 2a0d94cc605402848df45afd8ae36d729b25f00d1a09e8fbac6e323669227506 + d0b7b2bab0b320bf58e69a6879e67880c6818ce83f8630c91ab0e82a3f54ceeb + 1053a66d540d800956b248e951695e52c4290014c4fd7eee8c93393e593cf54c + 00000005 + 00000004 + 0f5cf24b2d72360a58d71392202a49fbef628a53b11e3617bbc1723a879a89e4 + c64e0e5dea7faf8cac58d4e7fcd71774 + 00000004 + 00000004 + 4849cdc5ce9923584e66bda4a1e96c856ead6a30672d94cab9ba1dcffe30843a + 646bd1ecba04f13bf7c6d7d8aabebfa8cb9a2190cd93d65d921ab7035cc81951 + d073609e5dedeb6ef7d00e2ed4c2680772077a9ce3f99ca74eb97f91339a81b1 + bb1c0dc10ad799ea594d4e7760463b4e441661c5f8e09ee9cc82c461dcfdf13d + 391db836b3d30fb42d33cabccb8ef9c81d054114e298a8100ac8ba9bcee4f518 + afd7bd2a158db134dd5ed299435ab7d2dc32db8b7fe35b24186e3c4b6114f7d0 + 46ba7de17e65ce9e1c5618c308c650a828d1c0f786a3d6a69ebbf04e51449308 + 868ecd7a5ce8f87f796396dc4837d08740376205249d8517a47c2ba816ab6c9c + 8bd8fd841ba4667ec53d353a661ea9e5ffa1769d981e4a31178e4f5ad3d99623 + d58c0ab2514b3c5306f3c83927f1b11a3784a384322780b100b44369f80b340f + 8212ad7f5092c44178a22a54110da8f8d3e8ac473aaa687587ea725806f44eaa + c1e340bb7aa801b455914418c1cdd6b59007f4ac5e9d519f2158762e40957507 + 3d6f30736f065bb74cd2c5d60b917cbad94af657ef37c1b92938c959e21d23f1 + 6950c38c2f6eeede9b1675dcc4b4985bf892f3a2a0ac601bcde4acde5ccdf71f + 0a850d9813f92f7279482ae2697fed0722d456d8557ab5bb3fd49421f8d2e71f + 06769fcd695fc186ecb0236051b534bb6a6641d859fd013afa975c0bf889b900 + 433581712b4b04c758fc121deea327817456f70135c3db767e16041f933186c4 + 081fe52635b917bc809c2063d035e14fb512a452c8f443f2a66362ea6b08ddd1 + 6d3a04065611cc962ccad06598fce7821837302ba00d57a83654130f582ce62c + 3266cae361d7db6f2b740ed7f90dca1ff4bf9ec4a0b7cbce226390bc2c38b3bf + a27a40508139f985749420e6fc4ebafcf4799248661e1134e5442f1ef8714739 + 1d589b45ecb61ac90ad6f82cb2bc3f006b62c40dcda5c362b5d4a8c56e42f672 + 1b8598de29d5d6c1293b3751d48ccff5c5805a59a41c00a6758913c86861f2ad + 2400f93fec76e1062db46e4e21f70d7881b7c91bafb9cd34afbfb05ce072fb3d + d4d9970ea49b57ed3ac73a2d75973f8d2a29de6e963d10bc62b695359d5807ed + 7ea0eb6908207698d08e96b619755872e840248550f053cc2597a65df404577d + 828c4604dc143cd42df691daae06a50502d7ad26d577478a00131fb4de24e780 + 39b56b4fb1408a26fa72a9f5db80fe39e49e414a27d57ab3abef508628812bea + 6f61e9e182148ddd920efb7493d3b68a79c3946c8dec31fe6963e8c2dea92dd7 + 9f789b20036b493bbdf605f45654498b93493181b71f261194f1faa6180f23ae + 6417720055d0b966a650e5f217bbfb1c711470fc9014874f8283d6efcabed894 + ec72f5887580f5fb9eb5e9be81a9e1f8ad650acd07069d499720815d052f4e11 + 8d14be427742a206f275a1b6570f684feb8c4cd62cbc89d0a93de601a7f0ff40 + 4125b7d29c1820d0b26490efde697f1699f4490a8b5db33a07af8df86da46817 + 2ebb99d63c45a3786d2be23395d5761f1c59ee591e5ecf35ba5cf2b5d39e8615 + 00000005 + 2510a21e43c9b53b86557646b2c891ba432813ca61fffb57c4a8e598753542c1 + a179d3af5254a37c01eeb4393d626771858d06041c76f1960e754e9e04aeb91b + 1d9b7736193f49e15c47f44a8f1c8aca6133c34eeb682fdccf94886fe80d971a + b4a0bb3b72197d2d5b2111da8647be1675983e8ed1c0d8ec7cada282dc698656 + 95f1e8806c7892b65fc17103ee3b5366b3fe31e57e653336be283962f488eaa5 + """); + } + + @State(Scope.Thread) + public static class Verifier01 { + Signature v; + + @Setup + public void setup() throws Exception { + v = getVerifier(TestData01.pk); + } + } + @State(Scope.Thread) + public static class Verifier02 { + Signature v; + + @Setup + public void setup() throws Exception { + v = getVerifier(TestData02.pk); + } + } + + @Benchmark + public void verify01(Verifier01 v) throws Exception { + verify(v.v, TestData01.msg, TestData01.sig); + } + @Benchmark + public void verify02(Verifier02 v) throws Exception { + verify(v.v, TestData02.msg, TestData02.sig); + } +} diff -Nru openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java --- openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * 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.javax.crypto.full; + +import org.openjdk.jmh.annotations.Benchmark; +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 javax.crypto.KEM; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; + +public class KEMBench extends CryptoBase { + + public static final int SET_SIZE = 128; + + @Param({"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024" }) + private String algorithm; + + 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); + keys = new KeyPair[SET_SIZE]; + for (int i = 0; i < keys.length; i++) { + keys[i] = generator.generateKeyPair(); + } + messages = new byte[SET_SIZE][]; + for (int i = 0; i < messages.length; i++) { + KEM.Encapsulator enc = kem.newEncapsulator(keys[i].getPublic()); + KEM.Encapsulated encap = enc.encapsulate(); + messages[i] = encap.encapsulation(); + } + } + + @Benchmark + @OperationsPerInvocation(SET_SIZE) + public void encapsulate(Blackhole bh) throws InvalidKeyException { + for (KeyPair kp : keys) { + bh.consume(kem.newEncapsulator(kp.getPublic()).encapsulate().encapsulation()); + } + } + + @Benchmark + @OperationsPerInvocation(SET_SIZE) + 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])); + } + } + +} diff -Nru openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java --- openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.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 @@ -45,7 +45,9 @@ setupProvider(); generator = (prov == null) ? KeyPairGenerator.getInstance(algorithm) : KeyPairGenerator.getInstance(algorithm, prov); - generator.initialize(keyLength); + if (keyLength > 0) { // not all key pair generators allow the use of key length + generator.initialize(keyLength); + } } @Benchmark @@ -97,4 +99,23 @@ @Param({"255", "448"}) private int keyLength; } + + public static class MLDSA extends KeyPairGeneratorBench { + + @Param({"ML-DSA-44", "ML-DSA-65", "ML-DSA-87" }) + private String algorithm; + + @Param({"0"}) // ML-DSA key length is not supported + private int keyLength; + } + + public static class MLKEM extends KeyPairGeneratorBench { + + @Param({"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024" }) + private String algorithm; + + @Param({"0"}) // ML-KEM key length is not supported + private int keyLength; + } + } diff -Nru openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/full/SignatureBench.java openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/full/SignatureBench.java --- openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/full/SignatureBench.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/full/SignatureBench.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,9 @@ public void setup() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { setupProvider(); KeyPairGenerator kpg = KeyPairGenerator.getInstance(getKeyPairGeneratorName()); - kpg.initialize(keyLength); + if (keyLength > 0) { // not all key pair generators allow the use of key length + kpg.initialize(keyLength); + } KeyPair keys = kpg.generateKeyPair(); this.privateKey = keys.getPrivate(); this.publicKey = keys.getPublic(); @@ -136,4 +138,13 @@ } + public static class MLDSA extends SignatureBench { + + @Param({"ML-DSA-44", "ML-DSA-65", "ML-DSA-87" }) + private String algorithm; + + @Param({"0"}) // ML-DSA key length is not supported + private int keyLength; + } + } diff -Nru openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/small/HSSBench.java openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/small/HSSBench.java --- openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/small/HSSBench.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/small/HSSBench.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.javax.crypto.small; + +public class HSSBench extends org.openjdk.bench.javax.crypto.full.HSSBench { + +} diff -Nru openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/small/KEMBench.java openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/small/KEMBench.java --- openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/small/KEMBench.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/small/KEMBench.java 2026-10-19 12:10:20.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.javax.crypto.small; + +import org.openjdk.jmh.annotations.Param; + +public class KEMBench extends org.openjdk.bench.javax.crypto.full.KEMBench { + + @Param({"ML-KEM-768"}) + private String algorithm; + +} diff -Nru openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/small/KeyPairGeneratorBench.java openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/small/KeyPairGeneratorBench.java --- openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/small/KeyPairGeneratorBench.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/small/KeyPairGeneratorBench.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,4 +32,22 @@ @Param({"2048"}) private int keyLength; + public static class MLDSA extends KeyPairGeneratorBench { + + @Param({"ML-DSA-65"}) + private String algorithm; + + @Param({"0"}) // ML_DSA key length is not supported + private int keyLength; + } + + public static class MLKEM extends KeyPairGeneratorBench { + + @Param({"ML-KEM-768"}) + private String algorithm; + + @Param({"0"}) // ML-KEM key length is not supported + private int keyLength; + } + } diff -Nru openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/small/SignatureBench.java openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/small/SignatureBench.java --- openjdk-21-21.0.12.1+1/test/micro/org/openjdk/bench/javax/crypto/small/SignatureBench.java 2026-08-07 11:31:48.000000000 +0000 +++ openjdk-21-21.0.13+9/test/micro/org/openjdk/bench/javax/crypto/small/SignatureBench.java 2026-10-19 12:10:20.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,4 +52,17 @@ } + public static class MLDSA extends SignatureBench { + + @Param({"ML-DSA-65" }) + private String algorithm; + + @Param({"1024"}) + int dataSize; + + @Param({"0"}) // ML-DSA key length is not supported + private int keyLength; + } + + }