diff --git a/7092821-java.security.Provider.getService-is-synchro.patch b/7092821-java.security.Provider.getService-is-synchro.patch new file mode 100644 index 0000000000000000000000000000000000000000..a20593fbc510c7cb8dab00f7d108500458b18b73 --- /dev/null +++ b/7092821-java.security.Provider.getService-is-synchro.patch @@ -0,0 +1,4815 @@ +From 834e8792532d89505e5cabfdbca0de3481b5c8ed Mon Sep 17 00:00:00 2001 +From: z00558301 +Date: Wed, 8 Jun 2022 09:38:47 +0800 +Subject: [PATCH 06/10] 7092821: java.security.Provider.getService() is + synchronized and became scalability bottleneck + +Bug url: https://bugs.openjdk.java.net/browse/JDK-7092821 +--- + .../com/sun/crypto/provider/SunJCE.java | 1300 ++++++++--------- + .../security/AlgorithmParameterGenerator.java | 5 +- + .../share/classes/java/security/Provider.java | 129 +- + .../classes/java/security/SecureRandom.java | 70 +- + .../share/classes/javax/crypto/Cipher.java | 8 +- + .../classes/javax/crypto/JceSecurity.java | 2 - + .../classes/javax/crypto/KeyAgreement.java | 4 +- + .../classes/javax/crypto/KeyGenerator.java | 4 +- + .../classes/sun/security/provider/Sun.java | 25 +- + .../sun/security/provider/SunEntries.java | 333 ++--- + .../provider/VerificationProvider.java | 28 +- + .../classes/sun/security/rsa/SunRsaSign.java | 25 +- + .../sun/security/rsa/SunRsaSignEntries.java | 171 +-- + .../classes/sun/security/ssl/SunJSSE.java | 136 +- + .../Provider/BaseProviderValidator.java | 76 + + .../security/Provider/GetServiceRace.java | 98 ++ + .../security/Provider/LegacyPutAlias.java | 86 ++ + .../Provider/ProviderValidationUtil.java | 270 ++++ + .../security/Provider/SunJCEValidator.java | 574 ++++++++ + .../security/Provider/SunJSSEValidator.java | 137 ++ + .../Provider/SunRsaSignValidator.java | 154 ++ + .../java/security/Provider/SunValidator.java | 263 ++++ + .../security/SecureRandom/DefaultAlgo.java | 117 ++ + .../provider/GetServiceBenchmark.java | 83 ++ + 24 files changed, 2965 insertions(+), 1133 deletions(-) + create mode 100644 jdk/test/java/security/Provider/BaseProviderValidator.java + create mode 100644 jdk/test/java/security/Provider/GetServiceRace.java + create mode 100644 jdk/test/java/security/Provider/LegacyPutAlias.java + create mode 100644 jdk/test/java/security/Provider/ProviderValidationUtil.java + create mode 100644 jdk/test/java/security/Provider/SunJCEValidator.java + create mode 100644 jdk/test/java/security/Provider/SunJSSEValidator.java + create mode 100644 jdk/test/java/security/Provider/SunRsaSignValidator.java + create mode 100644 jdk/test/java/security/Provider/SunValidator.java + create mode 100644 jdk/test/java/security/SecureRandom/DefaultAlgo.java + create mode 100644 jdk/test/micro/org/openeuler/bench/security/provider/GetServiceBenchmark.java + +diff --git a/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java b/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java +index 1e5b5dd0..66a26db2 100644 +--- a/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java ++++ b/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java +@@ -28,7 +28,10 @@ package com.sun.crypto.provider; + import java.security.AccessController; + import java.security.Provider; + import java.security.SecureRandom; +- ++import java.security.PrivilegedAction; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.List; + + /** + * The "SunJCE" Cryptographic Service Provider. +@@ -78,16 +81,6 @@ public final class SunJCE extends Provider { + "(implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, " + + "Diffie-Hellman, HMAC)"; + +- private static final String OID_PKCS12_RC4_128 = "1.2.840.113549.1.12.1.1"; +- private static final String OID_PKCS12_RC4_40 = "1.2.840.113549.1.12.1.2"; +- private static final String OID_PKCS12_DESede = "1.2.840.113549.1.12.1.3"; +- private static final String OID_PKCS12_RC2_128 = "1.2.840.113549.1.12.1.5"; +- private static final String OID_PKCS12_RC2_40 = "1.2.840.113549.1.12.1.6"; +- private static final String OID_PKCS5_MD5_DES = "1.2.840.113549.1.5.3"; +- private static final String OID_PKCS5_PBKDF2 = "1.2.840.113549.1.5.12"; +- private static final String OID_PKCS5_PBES2 = "1.2.840.113549.1.5.13"; +- private static final String OID_PKCS3 = "1.2.840.113549.1.3.1"; +- + /* Are we debugging? -- for developers */ + static final boolean debug = false; + +@@ -102,10 +95,115 @@ public final class SunJCE extends Provider { + } + static SecureRandom getRandom() { return SecureRandomHolder.RANDOM; } + ++ // create an aliases List from the specified aliases ++ public static List createAliases(String ... aliases) { ++ return Arrays.asList(aliases); ++ } ++ ++ // create an aliases List from the specified oid followed by other aliases ++ public static List createAliasesWithOid(String ... oids) { ++ String[] result = Arrays.copyOf(oids, oids.length + 1); ++ result[result.length - 1] = "OID." + oids[0]; ++ return Arrays.asList(result); ++ } ++ ++ private void ps(String type, String algo, String cn, ++ List aliases, HashMap attrs) { ++ putService(new Provider.Service(this, type, algo, cn, aliases, attrs)); ++ } ++ + public SunJCE() { + /* We are the "SunJCE" provider */ + super("SunJCE", 1.8d, info); + ++ // if there is no security manager installed, put directly into ++ // the provider ++ if (System.getSecurityManager() == null) { ++ putEntries(); ++ } else { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ @Override ++ public Void run() { ++ putEntries(); ++ return null; ++ } ++ }); ++ } ++ if (instance == null) { ++ instance = this; ++ } ++ } ++ ++ void putEntries() { ++ // common aliases and oids ++ List aesAliases = createAliases("Rijndael"); ++ List desEdeAliases = createAliases("TripleDES"); ++ List arcFourAliases = createAliases("RC4"); ++ List sunTlsMSAliases = createAliases( ++ "SunTls12MasterSecret", "SunTlsExtendedMasterSecret" ++ ); ++ List sunTlsKMAliases = createAliases("SunTls12KeyMaterial"); ++ List sunTlsRsaPMSAliases = createAliases("SunTls12RsaPremasterSecret"); ++ ++ String aes128Oid = "2.16.840.1.101.3.4.1."; ++ String aes192Oid = "2.16.840.1.101.3.4.1.2"; ++ String aes256Oid = "2.16.840.1.101.3.4.1.4"; ++ ++ List pkcs12RC4_128Aliases = ++ createAliasesWithOid("1.2.840.113549.1.12.1.1"); ++ ++ List pkcs12RC4_40Aliases = ++ createAliasesWithOid("1.2.840.113549.1.12.1.2"); ++ ++ List pkcs12DESedeAliases = ++ createAliasesWithOid("1.2.840.113549.1.12.1.3"); ++ ++ List pkcs12RC2_128Aliases = ++ createAliasesWithOid("1.2.840.113549.1.12.1.5"); ++ ++ List pkcs12RC2_40Aliases = ++ createAliasesWithOid("1.2.840.113549.1.12.1.6"); ++ ++ List pkcs5MD5_DESAliases = ++ createAliasesWithOid("1.2.840.113549.1.5.3", "PBE"); ++ ++ List pkcs5PBKDF2Aliases = ++ createAliasesWithOid("1.2.840.113549.1.5.12"); ++ ++ List pkcs5PBES2Aliases = ++ createAliasesWithOid("1.2.840.113549.1.5.13"); ++ ++ List diffieHellmanAliases = ++ createAliasesWithOid("1.2.840.113549.1.3.1", "DH"); ++ ++ String macOidBase = "1.2.840.113549.2."; ++ List macSHA1Aliases = createAliasesWithOid(macOidBase + "7"); ++ List macSHA224Aliases = createAliasesWithOid(macOidBase + "8"); ++ List macSHA256Aliases = createAliasesWithOid(macOidBase + "9"); ++ List macSHA384Aliases = createAliasesWithOid(macOidBase + "10"); ++ List macSHA512Aliases = createAliasesWithOid(macOidBase + "11"); ++ ++ // reuse attribute map and reset before each reuse ++ HashMap attrs = new HashMap<>(3); ++ attrs.put("SupportedModes", "ECB"); ++ attrs.put("SupportedPaddings", "NOPADDING|PKCS1PADDING|OAEPPADDING" ++ + "|OAEPWITHMD5ANDMGF1PADDING" ++ + "|OAEPWITHSHA1ANDMGF1PADDING" ++ + "|OAEPWITHSHA-1ANDMGF1PADDING" ++ + "|OAEPWITHSHA-224ANDMGF1PADDING" ++ + "|OAEPWITHSHA-256ANDMGF1PADDING" ++ + "|OAEPWITHSHA-384ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512/224ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512/256ANDMGF1PADDING"); ++ attrs.put("SupportedKeyClasses", ++ "java.security.interfaces.RSAPublicKey" + ++ "|java.security.interfaces.RSAPrivateKey"); ++ ps("Cipher", "RSA", ++ "com.sun.crypto.provider.RSACipher", null, attrs); ++ ++ // common block cipher modes, pads ++ + final String BLOCK_MODES = "ECB|CBC|PCBC|CTR|CTS|CFB|OFB" + + "|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64" + + "|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64"; +@@ -114,694 +212,529 @@ public final class SunJCE extends Provider { + "|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128"; + final String BLOCK_PADS = "NOPADDING|PKCS5PADDING|ISO10126PADDING"; + +- AccessController.doPrivileged( +- new java.security.PrivilegedAction() { +- public Object run() { +- +- /* +- * Cipher engines +- */ +- put("Cipher.RSA", "com.sun.crypto.provider.RSACipher"); +- put("Cipher.RSA SupportedModes", "ECB"); +- put("Cipher.RSA SupportedPaddings", +- "NOPADDING|PKCS1PADDING|OAEPPADDING" +- + "|OAEPWITHMD5ANDMGF1PADDING" +- + "|OAEPWITHSHA1ANDMGF1PADDING" +- + "|OAEPWITHSHA-1ANDMGF1PADDING" +- + "|OAEPWITHSHA-224ANDMGF1PADDING" +- + "|OAEPWITHSHA-256ANDMGF1PADDING" +- + "|OAEPWITHSHA-384ANDMGF1PADDING" +- + "|OAEPWITHSHA-512ANDMGF1PADDING" +- + "|OAEPWITHSHA-512/224ANDMGF1PADDING" +- + "|OAEPWITHSHA-512/256ANDMGF1PADDING"); +- put("Cipher.RSA SupportedKeyClasses", +- "java.security.interfaces.RSAPublicKey" + +- "|java.security.interfaces.RSAPrivateKey"); +- +- put("Cipher.DES", "com.sun.crypto.provider.DESCipher"); +- put("Cipher.DES SupportedModes", BLOCK_MODES); +- put("Cipher.DES SupportedPaddings", BLOCK_PADS); +- put("Cipher.DES SupportedKeyFormats", "RAW"); +- +- put("Cipher.DESede", "com.sun.crypto.provider.DESedeCipher"); +- put("Alg.Alias.Cipher.TripleDES", "DESede"); +- put("Cipher.DESede SupportedModes", BLOCK_MODES); +- put("Cipher.DESede SupportedPaddings", BLOCK_PADS); +- put("Cipher.DESede SupportedKeyFormats", "RAW"); +- +- put("Cipher.DESedeWrap", +- "com.sun.crypto.provider.DESedeWrapCipher"); +- put("Cipher.DESedeWrap SupportedModes", "CBC"); +- put("Cipher.DESedeWrap SupportedPaddings", "NOPADDING"); +- put("Cipher.DESedeWrap SupportedKeyFormats", "RAW"); +- +- // PBES1 +- +- put("Cipher.PBEWithMD5AndDES", +- "com.sun.crypto.provider.PBEWithMD5AndDESCipher"); +- put("Alg.Alias.Cipher.OID."+OID_PKCS5_MD5_DES, +- "PBEWithMD5AndDES"); +- put("Alg.Alias.Cipher."+OID_PKCS5_MD5_DES, +- "PBEWithMD5AndDES"); +- +- put("Cipher.PBEWithMD5AndTripleDES", +- "com.sun.crypto.provider.PBEWithMD5AndTripleDESCipher"); +- +- put("Cipher.PBEWithSHA1AndDESede", +- "com.sun.crypto.provider.PKCS12PBECipherCore$" + +- "PBEWithSHA1AndDESede"); +- put("Alg.Alias.Cipher.OID." + OID_PKCS12_DESede, +- "PBEWithSHA1AndDESede"); +- put("Alg.Alias.Cipher." + OID_PKCS12_DESede, +- "PBEWithSHA1AndDESede"); +- +- put("Cipher.PBEWithSHA1AndRC2_40", +- "com.sun.crypto.provider.PKCS12PBECipherCore$" + +- "PBEWithSHA1AndRC2_40"); +- put("Alg.Alias.Cipher.OID." + OID_PKCS12_RC2_40, +- "PBEWithSHA1AndRC2_40"); +- put("Alg.Alias.Cipher." + OID_PKCS12_RC2_40, +- "PBEWithSHA1AndRC2_40"); +- +- put("Cipher.PBEWithSHA1AndRC2_128", +- "com.sun.crypto.provider.PKCS12PBECipherCore$" + +- "PBEWithSHA1AndRC2_128"); +- put("Alg.Alias.Cipher.OID." + OID_PKCS12_RC2_128, +- "PBEWithSHA1AndRC2_128"); +- put("Alg.Alias.Cipher." + OID_PKCS12_RC2_128, +- "PBEWithSHA1AndRC2_128"); +- +- put("Cipher.PBEWithSHA1AndRC4_40", +- "com.sun.crypto.provider.PKCS12PBECipherCore$" + +- "PBEWithSHA1AndRC4_40"); +- put("Alg.Alias.Cipher.OID." + OID_PKCS12_RC4_40, +- "PBEWithSHA1AndRC4_40"); +- put("Alg.Alias.Cipher." + OID_PKCS12_RC4_40, +- "PBEWithSHA1AndRC4_40"); +- +- put("Cipher.PBEWithSHA1AndRC4_128", +- "com.sun.crypto.provider.PKCS12PBECipherCore$" + +- "PBEWithSHA1AndRC4_128"); +- put("Alg.Alias.Cipher.OID." + OID_PKCS12_RC4_128, +- "PBEWithSHA1AndRC4_128"); +- put("Alg.Alias.Cipher." + OID_PKCS12_RC4_128, +- "PBEWithSHA1AndRC4_128"); +- +- //PBES2 +- +- put("Cipher.PBEWithHmacSHA1AndAES_128", +- "com.sun.crypto.provider.PBES2Core$HmacSHA1AndAES_128"); +- +- put("Cipher.PBEWithHmacSHA224AndAES_128", +- "com.sun.crypto.provider.PBES2Core$" + +- "HmacSHA224AndAES_128"); +- +- put("Cipher.PBEWithHmacSHA256AndAES_128", +- "com.sun.crypto.provider.PBES2Core$" + +- "HmacSHA256AndAES_128"); +- +- put("Cipher.PBEWithHmacSHA384AndAES_128", +- "com.sun.crypto.provider.PBES2Core$" + +- "HmacSHA384AndAES_128"); +- +- put("Cipher.PBEWithHmacSHA512AndAES_128", +- "com.sun.crypto.provider.PBES2Core$" + +- "HmacSHA512AndAES_128"); +- +- put("Cipher.PBEWithHmacSHA1AndAES_256", +- "com.sun.crypto.provider.PBES2Core$HmacSHA1AndAES_256"); +- +- put("Cipher.PBEWithHmacSHA224AndAES_256", +- "com.sun.crypto.provider.PBES2Core$" + +- "HmacSHA224AndAES_256"); +- +- put("Cipher.PBEWithHmacSHA256AndAES_256", +- "com.sun.crypto.provider.PBES2Core$" + +- "HmacSHA256AndAES_256"); +- +- put("Cipher.PBEWithHmacSHA384AndAES_256", +- "com.sun.crypto.provider.PBES2Core$" + +- "HmacSHA384AndAES_256"); +- +- put("Cipher.PBEWithHmacSHA512AndAES_256", +- "com.sun.crypto.provider.PBES2Core$" + +- "HmacSHA512AndAES_256"); +- +- put("Cipher.Blowfish", +- "com.sun.crypto.provider.BlowfishCipher"); +- put("Cipher.Blowfish SupportedModes", BLOCK_MODES); +- put("Cipher.Blowfish SupportedPaddings", BLOCK_PADS); +- put("Cipher.Blowfish SupportedKeyFormats", "RAW"); +- +- put("Cipher.AES", "com.sun.crypto.provider.AESCipher$General"); +- put("Alg.Alias.Cipher.Rijndael", "AES"); +- put("Cipher.AES SupportedModes", BLOCK_MODES128); +- put("Cipher.AES SupportedPaddings", BLOCK_PADS); +- put("Cipher.AES SupportedKeyFormats", "RAW"); +- +- put("Cipher.AES_128/ECB/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_ECB_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.1", "AES_128/ECB/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.1", "AES_128/ECB/NoPadding"); +- put("Cipher.AES_128/CBC/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_CBC_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.2", "AES_128/CBC/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.2", "AES_128/CBC/NoPadding"); +- put("Cipher.AES_128/OFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_OFB_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.3", "AES_128/OFB/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.3", "AES_128/OFB/NoPadding"); +- put("Cipher.AES_128/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_CFB_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.4", "AES_128/CFB/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.4", "AES_128/CFB/NoPadding"); +- put("Cipher.AES_128/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_GCM_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.6", "AES_128/GCM/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.6", "AES_128/GCM/NoPadding"); +- +- put("Cipher.AES_192/ECB/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_ECB_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.21", "AES_192/ECB/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.21", "AES_192/ECB/NoPadding"); +- put("Cipher.AES_192/CBC/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_CBC_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.22", "AES_192/CBC/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.22", "AES_192/CBC/NoPadding"); +- put("Cipher.AES_192/OFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_OFB_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.23", "AES_192/OFB/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.23", "AES_192/OFB/NoPadding"); +- put("Cipher.AES_192/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_CFB_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.24", "AES_192/CFB/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.24", "AES_192/CFB/NoPadding"); +- put("Cipher.AES_192/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_GCM_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.26", "AES_192/GCM/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.26", "AES_192/GCM/NoPadding"); +- +- put("Cipher.AES_256/ECB/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_ECB_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.41", "AES_256/ECB/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.41", "AES_256/ECB/NoPadding"); +- put("Cipher.AES_256/CBC/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_CBC_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.42", "AES_256/CBC/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.42", "AES_256/CBC/NoPadding"); +- put("Cipher.AES_256/OFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_OFB_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.43", "AES_256/OFB/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.43", "AES_256/OFB/NoPadding"); +- put("Cipher.AES_256/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_CFB_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.44", "AES_256/CFB/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.44", "AES_256/CFB/NoPadding"); +- put("Cipher.AES_256/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_GCM_NoPadding"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.46", "AES_256/GCM/NoPadding"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.46", "AES_256/GCM/NoPadding"); +- +- put("Cipher.AESWrap", "com.sun.crypto.provider.AESWrapCipher$General"); +- put("Cipher.AESWrap SupportedModes", "ECB"); +- put("Cipher.AESWrap SupportedPaddings", "NOPADDING"); +- put("Cipher.AESWrap SupportedKeyFormats", "RAW"); +- +- put("Cipher.AESWrap_128", "com.sun.crypto.provider.AESWrapCipher$AES128"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.5", "AESWrap_128"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.5", "AESWrap_128"); +- put("Cipher.AESWrap_192", "com.sun.crypto.provider.AESWrapCipher$AES192"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.25", "AESWrap_192"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.25", "AESWrap_192"); +- put("Cipher.AESWrap_256", "com.sun.crypto.provider.AESWrapCipher$AES256"); +- put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.45", "AESWrap_256"); +- put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.45", "AESWrap_256"); +- +- put("Cipher.RC2", +- "com.sun.crypto.provider.RC2Cipher"); +- put("Cipher.RC2 SupportedModes", BLOCK_MODES); +- put("Cipher.RC2 SupportedPaddings", BLOCK_PADS); +- put("Cipher.RC2 SupportedKeyFormats", "RAW"); +- +- put("Cipher.ARCFOUR", +- "com.sun.crypto.provider.ARCFOURCipher"); +- put("Alg.Alias.Cipher.RC4", "ARCFOUR"); +- put("Cipher.ARCFOUR SupportedModes", "ECB"); +- put("Cipher.ARCFOUR SupportedPaddings", "NOPADDING"); +- put("Cipher.ARCFOUR SupportedKeyFormats", "RAW"); +- +- /* +- * Key(pair) Generator engines +- */ +- put("KeyGenerator.DES", +- "com.sun.crypto.provider.DESKeyGenerator"); +- +- put("KeyGenerator.DESede", +- "com.sun.crypto.provider.DESedeKeyGenerator"); +- put("Alg.Alias.KeyGenerator.TripleDES", "DESede"); +- +- put("KeyGenerator.Blowfish", +- "com.sun.crypto.provider.BlowfishKeyGenerator"); +- +- put("KeyGenerator.AES", +- "com.sun.crypto.provider.AESKeyGenerator"); +- put("Alg.Alias.KeyGenerator.Rijndael", "AES"); +- +- put("KeyGenerator.RC2", +- "com.sun.crypto.provider.KeyGeneratorCore$" + +- "RC2KeyGenerator"); +- put("KeyGenerator.ARCFOUR", +- "com.sun.crypto.provider.KeyGeneratorCore$" + +- "ARCFOURKeyGenerator"); +- put("Alg.Alias.KeyGenerator.RC4", "ARCFOUR"); +- +- put("KeyGenerator.HmacMD5", +- "com.sun.crypto.provider.HmacMD5KeyGenerator"); +- +- put("KeyGenerator.HmacSHA1", +- "com.sun.crypto.provider.HmacSHA1KeyGenerator"); +- put("Alg.Alias.KeyGenerator.OID.1.2.840.113549.2.7", "HmacSHA1"); +- put("Alg.Alias.KeyGenerator.1.2.840.113549.2.7", "HmacSHA1"); +- +- put("KeyGenerator.HmacSHA224", +- "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA2KG$SHA224"); +- put("Alg.Alias.KeyGenerator.OID.1.2.840.113549.2.8", "HmacSHA224"); +- put("Alg.Alias.KeyGenerator.1.2.840.113549.2.8", "HmacSHA224"); +- +- put("KeyGenerator.HmacSHA256", +- "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA2KG$SHA256"); +- put("Alg.Alias.KeyGenerator.OID.1.2.840.113549.2.9", "HmacSHA256"); +- put("Alg.Alias.KeyGenerator.1.2.840.113549.2.9", "HmacSHA256"); +- +- put("KeyGenerator.HmacSHA384", +- "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA2KG$SHA384"); +- put("Alg.Alias.KeyGenerator.OID.1.2.840.113549.2.10", "HmacSHA384"); +- put("Alg.Alias.KeyGenerator.1.2.840.113549.2.10", "HmacSHA384"); +- +- put("KeyGenerator.HmacSHA512", +- "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA2KG$SHA512"); +- put("Alg.Alias.KeyGenerator.OID.1.2.840.113549.2.11", "HmacSHA512"); +- put("Alg.Alias.KeyGenerator.1.2.840.113549.2.11", "HmacSHA512"); +- +- put("KeyPairGenerator.DiffieHellman", +- "com.sun.crypto.provider.DHKeyPairGenerator"); +- put("Alg.Alias.KeyPairGenerator.DH", "DiffieHellman"); +- put("Alg.Alias.KeyPairGenerator.OID."+OID_PKCS3, +- "DiffieHellman"); +- put("Alg.Alias.KeyPairGenerator."+OID_PKCS3, +- "DiffieHellman"); +- +- /* +- * Algorithm parameter generation engines +- */ +- put("AlgorithmParameterGenerator.DiffieHellman", +- "com.sun.crypto.provider.DHParameterGenerator"); +- put("Alg.Alias.AlgorithmParameterGenerator.DH", +- "DiffieHellman"); +- put("Alg.Alias.AlgorithmParameterGenerator.OID."+OID_PKCS3, +- "DiffieHellman"); +- put("Alg.Alias.AlgorithmParameterGenerator."+OID_PKCS3, +- "DiffieHellman"); +- +- /* +- * Key Agreement engines +- */ +- put("KeyAgreement.DiffieHellman", +- "com.sun.crypto.provider.DHKeyAgreement"); +- put("Alg.Alias.KeyAgreement.DH", "DiffieHellman"); +- put("Alg.Alias.KeyAgreement.OID."+OID_PKCS3, "DiffieHellman"); +- put("Alg.Alias.KeyAgreement."+OID_PKCS3, "DiffieHellman"); +- +- put("KeyAgreement.DiffieHellman SupportedKeyClasses", +- "javax.crypto.interfaces.DHPublicKey" + +- "|javax.crypto.interfaces.DHPrivateKey"); +- +- /* +- * Algorithm Parameter engines +- */ +- put("AlgorithmParameters.DiffieHellman", +- "com.sun.crypto.provider.DHParameters"); +- put("Alg.Alias.AlgorithmParameters.DH", "DiffieHellman"); +- put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS3, +- "DiffieHellman"); +- put("Alg.Alias.AlgorithmParameters."+OID_PKCS3, +- "DiffieHellman"); +- +- put("AlgorithmParameters.DES", +- "com.sun.crypto.provider.DESParameters"); +- +- put("AlgorithmParameters.DESede", +- "com.sun.crypto.provider.DESedeParameters"); +- put("Alg.Alias.AlgorithmParameters.TripleDES", "DESede"); +- +- put("AlgorithmParameters.PBE", +- "com.sun.crypto.provider.PBEParameters"); +- +- put("AlgorithmParameters.PBEWithMD5AndDES", +- "com.sun.crypto.provider.PBEParameters"); +- put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS5_MD5_DES, +- "PBEWithMD5AndDES"); +- put("Alg.Alias.AlgorithmParameters."+OID_PKCS5_MD5_DES, +- "PBEWithMD5AndDES"); +- +- put("AlgorithmParameters.PBEWithMD5AndTripleDES", +- "com.sun.crypto.provider.PBEParameters"); +- +- put("AlgorithmParameters.PBEWithSHA1AndDESede", +- "com.sun.crypto.provider.PBEParameters"); +- put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS12_DESede, +- "PBEWithSHA1AndDESede"); +- put("Alg.Alias.AlgorithmParameters."+OID_PKCS12_DESede, +- "PBEWithSHA1AndDESede"); +- +- put("AlgorithmParameters.PBEWithSHA1AndRC2_40", +- "com.sun.crypto.provider.PBEParameters"); +- put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS12_RC2_40, +- "PBEWithSHA1AndRC2_40"); +- put("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC2_40, +- "PBEWithSHA1AndRC2_40"); +- +- put("AlgorithmParameters.PBEWithSHA1AndRC2_128", +- "com.sun.crypto.provider.PBEParameters"); +- put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS12_RC2_128, +- "PBEWithSHA1AndRC2_128"); +- put("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC2_128, +- "PBEWithSHA1AndRC2_128"); +- +- put("AlgorithmParameters.PBEWithSHA1AndRC4_40", +- "com.sun.crypto.provider.PBEParameters"); +- put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS12_RC4_40, +- "PBEWithSHA1AndRC4_40"); +- put("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC4_40, +- "PBEWithSHA1AndRC4_40"); +- +- put("AlgorithmParameters.PBEWithSHA1AndRC4_128", +- "com.sun.crypto.provider.PBEParameters"); +- put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS12_RC4_128, +- "PBEWithSHA1AndRC4_128"); +- put("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC4_128, +- "PBEWithSHA1AndRC4_128"); +- +- put("AlgorithmParameters.PBES2", +- "com.sun.crypto.provider.PBES2Parameters$General"); +- put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS5_PBES2, +- "PBES2"); +- put("Alg.Alias.AlgorithmParameters." + OID_PKCS5_PBES2, +- "PBES2"); +- +- put("AlgorithmParameters.PBEWithHmacSHA1AndAES_128", +- "com.sun.crypto.provider.PBES2Parameters$HmacSHA1AndAES_128"); +- +- put("AlgorithmParameters.PBEWithHmacSHA224AndAES_128", +- "com.sun.crypto.provider.PBES2Parameters$HmacSHA224AndAES_128"); +- +- put("AlgorithmParameters.PBEWithHmacSHA256AndAES_128", +- "com.sun.crypto.provider.PBES2Parameters$HmacSHA256AndAES_128"); +- +- put("AlgorithmParameters.PBEWithHmacSHA384AndAES_128", +- "com.sun.crypto.provider.PBES2Parameters$HmacSHA384AndAES_128"); +- +- put("AlgorithmParameters.PBEWithHmacSHA512AndAES_128", +- "com.sun.crypto.provider.PBES2Parameters$HmacSHA512AndAES_128"); +- +- put("AlgorithmParameters.PBEWithHmacSHA1AndAES_256", +- "com.sun.crypto.provider.PBES2Parameters$HmacSHA1AndAES_256"); +- +- put("AlgorithmParameters.PBEWithHmacSHA224AndAES_256", +- "com.sun.crypto.provider.PBES2Parameters$HmacSHA224AndAES_256"); +- +- put("AlgorithmParameters.PBEWithHmacSHA256AndAES_256", +- "com.sun.crypto.provider.PBES2Parameters$HmacSHA256AndAES_256"); +- +- put("AlgorithmParameters.PBEWithHmacSHA384AndAES_256", +- "com.sun.crypto.provider.PBES2Parameters$HmacSHA384AndAES_256"); +- +- put("AlgorithmParameters.PBEWithHmacSHA512AndAES_256", +- "com.sun.crypto.provider.PBES2Parameters$HmacSHA512AndAES_256"); +- +- put("AlgorithmParameters.Blowfish", +- "com.sun.crypto.provider.BlowfishParameters"); +- +- put("AlgorithmParameters.AES", +- "com.sun.crypto.provider.AESParameters"); +- put("Alg.Alias.AlgorithmParameters.Rijndael", "AES"); +- put("AlgorithmParameters.GCM", +- "com.sun.crypto.provider.GCMParameters"); +- +- +- put("AlgorithmParameters.RC2", +- "com.sun.crypto.provider.RC2Parameters"); +- +- put("AlgorithmParameters.OAEP", +- "com.sun.crypto.provider.OAEPParameters"); +- +- /* +- * Key factories +- */ +- put("KeyFactory.DiffieHellman", +- "com.sun.crypto.provider.DHKeyFactory"); +- put("Alg.Alias.KeyFactory.DH", "DiffieHellman"); +- put("Alg.Alias.KeyFactory.OID."+OID_PKCS3, +- "DiffieHellman"); +- put("Alg.Alias.KeyFactory."+OID_PKCS3, "DiffieHellman"); +- +- /* +- * Secret-key factories +- */ +- put("SecretKeyFactory.DES", +- "com.sun.crypto.provider.DESKeyFactory"); +- +- put("SecretKeyFactory.DESede", +- "com.sun.crypto.provider.DESedeKeyFactory"); +- put("Alg.Alias.SecretKeyFactory.TripleDES", "DESede"); +- +- put("SecretKeyFactory.PBEWithMD5AndDES", +- "com.sun.crypto.provider.PBEKeyFactory$PBEWithMD5AndDES" +- ); +- put("Alg.Alias.SecretKeyFactory.OID."+OID_PKCS5_MD5_DES, +- "PBEWithMD5AndDES"); +- put("Alg.Alias.SecretKeyFactory."+OID_PKCS5_MD5_DES, +- "PBEWithMD5AndDES"); +- +- put("Alg.Alias.SecretKeyFactory.PBE", +- "PBEWithMD5AndDES"); +- +- /* +- * Internal in-house crypto algorithm used for +- * the JCEKS keystore type. Since this was developed +- * internally, there isn't an OID corresponding to this +- * algorithm. +- */ +- put("SecretKeyFactory.PBEWithMD5AndTripleDES", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithMD5AndTripleDES" +- ); +- +- put("SecretKeyFactory.PBEWithSHA1AndDESede", +- "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndDESede" +- ); +- put("Alg.Alias.SecretKeyFactory.OID."+OID_PKCS12_DESede, +- "PBEWithSHA1AndDESede"); +- put("Alg.Alias.SecretKeyFactory." + OID_PKCS12_DESede, +- "PBEWithSHA1AndDESede"); +- +- put("SecretKeyFactory.PBEWithSHA1AndRC2_40", +- "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC2_40" +- ); +- put("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC2_40, +- "PBEWithSHA1AndRC2_40"); +- put("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC2_40, +- "PBEWithSHA1AndRC2_40"); +- +- put("SecretKeyFactory.PBEWithSHA1AndRC2_128", +- "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC2_128" +- ); +- put("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC2_128, +- "PBEWithSHA1AndRC2_128"); +- put("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC2_128, +- "PBEWithSHA1AndRC2_128"); +- +- put("SecretKeyFactory.PBEWithSHA1AndRC4_40", +- "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC4_40" +- ); +- +- put("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC4_40, +- "PBEWithSHA1AndRC4_40"); +- put("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC4_40, +- "PBEWithSHA1AndRC4_40"); +- +- put("SecretKeyFactory.PBEWithSHA1AndRC4_128", +- "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC4_128" +- ); +- +- put("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC4_128, +- "PBEWithSHA1AndRC4_128"); +- put("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC4_128, +- "PBEWithSHA1AndRC4_128"); +- +- put("SecretKeyFactory.PBEWithHmacSHA1AndAES_128", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithHmacSHA1AndAES_128"); +- +- put("SecretKeyFactory.PBEWithHmacSHA224AndAES_128", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithHmacSHA224AndAES_128"); +- +- put("SecretKeyFactory.PBEWithHmacSHA256AndAES_128", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithHmacSHA256AndAES_128"); +- +- put("SecretKeyFactory.PBEWithHmacSHA384AndAES_128", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithHmacSHA384AndAES_128"); +- +- put("SecretKeyFactory.PBEWithHmacSHA512AndAES_128", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithHmacSHA512AndAES_128"); +- +- put("SecretKeyFactory.PBEWithHmacSHA1AndAES_256", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithHmacSHA1AndAES_256"); +- +- put("SecretKeyFactory.PBEWithHmacSHA224AndAES_256", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithHmacSHA224AndAES_256"); +- +- put("SecretKeyFactory.PBEWithHmacSHA256AndAES_256", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithHmacSHA256AndAES_256"); +- +- put("SecretKeyFactory.PBEWithHmacSHA384AndAES_256", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithHmacSHA384AndAES_256"); +- +- put("SecretKeyFactory.PBEWithHmacSHA512AndAES_256", +- "com.sun.crypto.provider.PBEKeyFactory$" + +- "PBEWithHmacSHA512AndAES_256"); +- +- // PBKDF2 +- +- put("SecretKeyFactory.PBKDF2WithHmacSHA1", +- "com.sun.crypto.provider.PBKDF2Core$HmacSHA1"); +- put("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS5_PBKDF2, +- "PBKDF2WithHmacSHA1"); +- put("Alg.Alias.SecretKeyFactory." + OID_PKCS5_PBKDF2, +- "PBKDF2WithHmacSHA1"); +- +- put("SecretKeyFactory.PBKDF2WithHmacSHA224", +- "com.sun.crypto.provider.PBKDF2Core$HmacSHA224"); +- put("SecretKeyFactory.PBKDF2WithHmacSHA256", +- "com.sun.crypto.provider.PBKDF2Core$HmacSHA256"); +- put("SecretKeyFactory.PBKDF2WithHmacSHA384", +- "com.sun.crypto.provider.PBKDF2Core$HmacSHA384"); +- put("SecretKeyFactory.PBKDF2WithHmacSHA512", +- "com.sun.crypto.provider.PBKDF2Core$HmacSHA512"); +- +- /* +- * MAC +- */ +- put("Mac.HmacMD5", "com.sun.crypto.provider.HmacMD5"); +- put("Mac.HmacSHA1", "com.sun.crypto.provider.HmacSHA1"); +- put("Alg.Alias.Mac.OID.1.2.840.113549.2.7", "HmacSHA1"); +- put("Alg.Alias.Mac.1.2.840.113549.2.7", "HmacSHA1"); +- put("Mac.HmacSHA224", +- "com.sun.crypto.provider.HmacCore$HmacSHA224"); +- put("Alg.Alias.Mac.OID.1.2.840.113549.2.8", "HmacSHA224"); +- put("Alg.Alias.Mac.1.2.840.113549.2.8", "HmacSHA224"); +- put("Mac.HmacSHA256", +- "com.sun.crypto.provider.HmacCore$HmacSHA256"); +- put("Alg.Alias.Mac.OID.1.2.840.113549.2.9", "HmacSHA256"); +- put("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA256"); +- put("Mac.HmacSHA384", +- "com.sun.crypto.provider.HmacCore$HmacSHA384"); +- put("Alg.Alias.Mac.OID.1.2.840.113549.2.10", "HmacSHA384"); +- put("Alg.Alias.Mac.1.2.840.113549.2.10", "HmacSHA384"); +- put("Mac.HmacSHA512", +- "com.sun.crypto.provider.HmacCore$HmacSHA512"); +- put("Alg.Alias.Mac.OID.1.2.840.113549.2.11", "HmacSHA512"); +- put("Alg.Alias.Mac.1.2.840.113549.2.11", "HmacSHA512"); +- +- put("Mac.HmacPBESHA1", +- "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA1"); +- put("Mac.HmacPBESHA224", +- "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA224"); +- put("Mac.HmacPBESHA256", +- "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA256"); +- put("Mac.HmacPBESHA384", +- "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA384"); +- put("Mac.HmacPBESHA512", +- "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA512"); +- put("Mac.HmacPBESHA512/224", +- "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA512_224"); +- put("Mac.HmacPBESHA512/256", +- "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA512_256"); +- +- // PBMAC1 +- +- put("Mac.PBEWithHmacSHA1", +- "com.sun.crypto.provider.PBMAC1Core$HmacSHA1"); +- put("Mac.PBEWithHmacSHA224", +- "com.sun.crypto.provider.PBMAC1Core$HmacSHA224"); +- put("Mac.PBEWithHmacSHA256", +- "com.sun.crypto.provider.PBMAC1Core$HmacSHA256"); +- put("Mac.PBEWithHmacSHA384", +- "com.sun.crypto.provider.PBMAC1Core$HmacSHA384"); +- put("Mac.PBEWithHmacSHA512", +- "com.sun.crypto.provider.PBMAC1Core$HmacSHA512"); +- +- put("Mac.SslMacMD5", +- "com.sun.crypto.provider.SslMacCore$SslMacMD5"); +- put("Mac.SslMacSHA1", +- "com.sun.crypto.provider.SslMacCore$SslMacSHA1"); +- +- put("Mac.HmacMD5 SupportedKeyFormats", "RAW"); +- put("Mac.HmacSHA1 SupportedKeyFormats", "RAW"); +- put("Mac.HmacSHA224 SupportedKeyFormats", "RAW"); +- put("Mac.HmacSHA256 SupportedKeyFormats", "RAW"); +- put("Mac.HmacSHA384 SupportedKeyFormats", "RAW"); +- put("Mac.HmacSHA512 SupportedKeyFormats", "RAW"); +- put("Mac.HmacPBESHA1 SupportedKeyFormats", "RAW"); +- put("Mac.HmacPBESHA224 SupportedKeyFormats", "RAW"); +- put("Mac.HmacPBESHA256 SupportedKeyFormats", "RAW"); +- put("Mac.HmacPBESHA384 SupportedKeyFormats", "RAW"); +- put("Mac.HmacPBESHA512 SupportedKeyFormats", "RAW"); +- put("Mac.HmacPBESHA512/224 SupportedKeyFormats", "RAW"); +- put("Mac.HmacPBESHA512/256 SupportedKeyFormats", "RAW"); +- put("Mac.PBEWithHmacSHA1 SupportedKeyFormatS", "RAW"); +- put("Mac.PBEWithHmacSHA224 SupportedKeyFormats", "RAW"); +- put("Mac.PBEWithHmacSHA256 SupportedKeyFormats", "RAW"); +- put("Mac.PBEWithHmacSHA384 SupportedKeyFormats", "RAW"); +- put("Mac.PBEWithHmacSHA512 SupportedKeyFormats", "RAW"); +- put("Mac.SslMacMD5 SupportedKeyFormats", "RAW"); +- put("Mac.SslMacSHA1 SupportedKeyFormats", "RAW"); +- +- /* +- * KeyStore +- */ +- put("KeyStore.JCEKS", "com.sun.crypto.provider.JceKeyStore"); +- +- /* +- * SSL/TLS mechanisms +- * +- * These are strictly internal implementations and may +- * be changed at any time. These names were chosen +- * because PKCS11/SunPKCS11 does not yet have TLS1.2 +- * mechanisms, and it will cause calls to come here. +- */ +- put("KeyGenerator.SunTlsPrf", +- "com.sun.crypto.provider.TlsPrfGenerator$V10"); +- put("KeyGenerator.SunTls12Prf", +- "com.sun.crypto.provider.TlsPrfGenerator$V12"); +- +- put("KeyGenerator.SunTlsMasterSecret", +- "com.sun.crypto.provider.TlsMasterSecretGenerator"); +- put("Alg.Alias.KeyGenerator.SunTls12MasterSecret", +- "SunTlsMasterSecret"); +- put("Alg.Alias.KeyGenerator.SunTlsExtendedMasterSecret", +- "SunTlsMasterSecret"); +- +- put("KeyGenerator.SunTlsKeyMaterial", +- "com.sun.crypto.provider.TlsKeyMaterialGenerator"); +- put("Alg.Alias.KeyGenerator.SunTls12KeyMaterial", +- "SunTlsKeyMaterial"); +- +- put("KeyGenerator.SunTlsRsaPremasterSecret", +- "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator"); +- put("Alg.Alias.KeyGenerator.SunTls12RsaPremasterSecret", +- "SunTlsRsaPremasterSecret"); +- +- return null; +- } +- }); +- +- if (instance == null) { +- instance = this; +- } ++ attrs.clear(); ++ attrs.put("SupportedModes", BLOCK_MODES); ++ attrs.put("SupportedPaddings", BLOCK_PADS); ++ attrs.put("SupportedKeyFormats", "RAW"); ++ ps("Cipher", "DES", ++ "com.sun.crypto.provider.DESCipher", null, attrs); ++ ps("Cipher", "DESede", "com.sun.crypto.provider.DESedeCipher", ++ desEdeAliases, attrs); ++ ps("Cipher", "Blowfish", ++ "com.sun.crypto.provider.BlowfishCipher", null, attrs); ++ ++ ps("Cipher", "RC2", ++ "com.sun.crypto.provider.RC2Cipher", null, attrs); ++ ++ attrs.clear(); ++ attrs.put("SupportedModes", BLOCK_MODES128); ++ attrs.put("SupportedPaddings", BLOCK_PADS); ++ attrs.put("SupportedKeyFormats", "RAW"); ++ ps("Cipher", "AES", "com.sun.crypto.provider.AESCipher$General", ++ aesAliases, attrs); ++ ++ attrs.clear(); ++ attrs.put("SupportedKeyFormats", "RAW"); ++ ps("Cipher", "AES_128/ECB/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES128_ECB_NoPadding", ++ createAliasesWithOid(aes128Oid+"1"), attrs); ++ ps("Cipher", "AES_128/CBC/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES128_CBC_NoPadding", ++ createAliasesWithOid(aes128Oid+"2"), attrs); ++ ps("Cipher", "AES_128/OFB/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES128_OFB_NoPadding", ++ createAliasesWithOid(aes128Oid+"3"), attrs); ++ ps("Cipher", "AES_128/CFB/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES128_CFB_NoPadding", ++ createAliasesWithOid(aes128Oid+"4"), attrs); ++ ps("Cipher", "AES_128/GCM/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES128_GCM_NoPadding", ++ createAliasesWithOid(aes128Oid+"6"), attrs); ++ ++ ps("Cipher", "AES_192/ECB/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES192_ECB_NoPadding", ++ createAliasesWithOid(aes192Oid+"1"), attrs); ++ ps("Cipher", "AES_192/CBC/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES192_CBC_NoPadding", ++ createAliasesWithOid(aes192Oid+"2"), attrs); ++ ps("Cipher", "AES_192/OFB/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES192_OFB_NoPadding", ++ createAliasesWithOid(aes192Oid+"3"), attrs); ++ ps("Cipher", "AES_192/CFB/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES192_CFB_NoPadding", ++ createAliasesWithOid(aes192Oid+"4"), attrs); ++ ps("Cipher", "AES_192/GCM/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES192_GCM_NoPadding", ++ createAliasesWithOid(aes192Oid+"6"), attrs); ++ ++ ps("Cipher", "AES_256/ECB/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES256_ECB_NoPadding", ++ createAliasesWithOid(aes256Oid+"1"), attrs); ++ ps("Cipher", "AES_256/CBC/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES256_CBC_NoPadding", ++ createAliasesWithOid(aes256Oid+"2"), attrs); ++ ps("Cipher", "AES_256/OFB/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES256_OFB_NoPadding", ++ createAliasesWithOid(aes256Oid+"3"), attrs); ++ ps("Cipher", "AES_256/CFB/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES256_CFB_NoPadding", ++ createAliasesWithOid(aes256Oid+"4"), attrs); ++ ps("Cipher", "AES_256/GCM/NoPadding", ++ "com.sun.crypto.provider.AESCipher$AES256_GCM_NoPadding", ++ createAliasesWithOid(aes256Oid+"6"), attrs); ++ ++ attrs.clear(); ++ attrs.put("SupportedModes", "CBC"); ++ attrs.put("SupportedPaddings", "NOPADDING"); ++ attrs.put("SupportedKeyFormats", "RAW"); ++ ps("Cipher", "DESedeWrap", ++ "com.sun.crypto.provider.DESedeWrapCipher", null, attrs); ++ ++ attrs.clear(); ++ attrs.put("SupportedModes", "ECB"); ++ attrs.put("SupportedPaddings", "NOPADDING"); ++ attrs.put("SupportedKeyFormats", "RAW"); ++ ps("Cipher", "ARCFOUR", "com.sun.crypto.provider.ARCFOURCipher", ++ arcFourAliases, attrs); ++ ps("Cipher", "AESWrap", "com.sun.crypto.provider.AESWrapCipher$General", ++ null, attrs); ++ ps("Cipher", "AESWrap_128", ++ "com.sun.crypto.provider.AESWrapCipher$AES128", ++ createAliasesWithOid(aes128Oid+"5"), attrs); ++ ps("Cipher", "AESWrap_192", ++ "com.sun.crypto.provider.AESWrapCipher$AES192", ++ createAliasesWithOid(aes192Oid+"5"), attrs); ++ ps("Cipher", "AESWrap_256", ++ "com.sun.crypto.provider.AESWrapCipher$AES256", ++ createAliasesWithOid(aes256Oid+"5"), attrs); ++ ++ attrs.clear(); ++ attrs.put("SupportedKeyFormats", "RAW"); ++ ++ // PBES1 ++ ps("Cipher", "PBEWithMD5AndDES", ++ "com.sun.crypto.provider.PBEWithMD5AndDESCipher", ++ pkcs5MD5_DESAliases, null); ++ ps("Cipher", "PBEWithMD5AndTripleDES", ++ "com.sun.crypto.provider.PBEWithMD5AndTripleDESCipher", ++ null, null); ++ ps("Cipher", "PBEWithSHA1AndDESede", ++ "com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndDESede", ++ pkcs12DESedeAliases, null); ++ ps("Cipher", "PBEWithSHA1AndRC2_40", ++ "com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndRC2_40", ++ pkcs12RC2_40Aliases, null); ++ ps("Cipher", "PBEWithSHA1AndRC2_128", ++ "com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndRC2_128", ++ pkcs12RC2_128Aliases, null); ++ ps("Cipher", "PBEWithSHA1AndRC4_40", ++ "com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndRC4_40", ++ pkcs12RC4_40Aliases, null); ++ ++ ps("Cipher", "PBEWithSHA1AndRC4_128", ++ "com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndRC4_128", ++ pkcs12RC4_128Aliases, null); ++ ++ // PBES2 ++ ps("Cipher", "PBEWithHmacSHA1AndAES_128", ++ "com.sun.crypto.provider.PBES2Core$HmacSHA1AndAES_128", ++ null, null); ++ ++ ps("Cipher", "PBEWithHmacSHA224AndAES_128", ++ "com.sun.crypto.provider.PBES2Core$HmacSHA224AndAES_128", ++ null, null); ++ ++ ps("Cipher", "PBEWithHmacSHA256AndAES_128", ++ "com.sun.crypto.provider.PBES2Core$HmacSHA256AndAES_128", ++ null, null); ++ ++ ps("Cipher", "PBEWithHmacSHA384AndAES_128", ++ "com.sun.crypto.provider.PBES2Core$HmacSHA384AndAES_128", ++ null, null); ++ ++ ps("Cipher", "PBEWithHmacSHA512AndAES_128", ++ "com.sun.crypto.provider.PBES2Core$HmacSHA512AndAES_128", ++ null, null); ++ ++ ps("Cipher", "PBEWithHmacSHA1AndAES_256", ++ "com.sun.crypto.provider.PBES2Core$HmacSHA1AndAES_256", ++ null, null); ++ ++ ps("Cipher", "PBEWithHmacSHA224AndAES_256", ++ "com.sun.crypto.provider.PBES2Core$HmacSHA224AndAES_256", ++ null, null); ++ ++ ps("Cipher", "PBEWithHmacSHA256AndAES_256", ++ "com.sun.crypto.provider.PBES2Core$HmacSHA256AndAES_256", ++ null, null); ++ ++ ps("Cipher", "PBEWithHmacSHA384AndAES_256", ++ "com.sun.crypto.provider.PBES2Core$HmacSHA384AndAES_256", ++ null, null); ++ ++ ps("Cipher", "PBEWithHmacSHA512AndAES_256", ++ "com.sun.crypto.provider.PBES2Core$HmacSHA512AndAES_256", ++ null, null); ++ ++ /* ++ * Key(pair) Generator engines ++ */ ++ ps("KeyGenerator", "DES", ++ "com.sun.crypto.provider.DESKeyGenerator", ++ null, null); ++ ps("KeyGenerator", "DESede", ++ "com.sun.crypto.provider.DESedeKeyGenerator", ++ desEdeAliases, null); ++ ps("KeyGenerator", "Blowfish", ++ "com.sun.crypto.provider.BlowfishKeyGenerator", ++ null, null); ++ ps("KeyGenerator", "AES", ++ "com.sun.crypto.provider.AESKeyGenerator", ++ aesAliases, null); ++ ps("KeyGenerator", "RC2", ++ "com.sun.crypto.provider.KeyGeneratorCore$RC2KeyGenerator", ++ null, null); ++ ps("KeyGenerator", "ARCFOUR", ++ "com.sun.crypto.provider.KeyGeneratorCore$ARCFOURKeyGenerator", ++ arcFourAliases, null); ++ ps("KeyGenerator", "HmacMD5", ++ "com.sun.crypto.provider.HmacMD5KeyGenerator", ++ null, null); ++ ++ ps("KeyGenerator", "HmacSHA1", ++ "com.sun.crypto.provider.HmacSHA1KeyGenerator", ++ macSHA1Aliases, null); ++ ps("KeyGenerator", "HmacSHA224", ++ "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA2KG$SHA224", ++ macSHA224Aliases, null); ++ ps("KeyGenerator", "HmacSHA256", ++ "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA2KG$SHA256", ++ macSHA256Aliases, null); ++ ps("KeyGenerator", "HmacSHA384", ++ "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA2KG$SHA384", ++ macSHA384Aliases, null); ++ ps("KeyGenerator", "HmacSHA512", ++ "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA2KG$SHA512", ++ macSHA512Aliases, null); ++ ++ ps("KeyPairGenerator", "DiffieHellman", ++ "com.sun.crypto.provider.DHKeyPairGenerator", ++ diffieHellmanAliases, null); ++ ++ /* ++ * Algorithm parameter generation engines ++ */ ++ ps("AlgorithmParameterGenerator", ++ "DiffieHellman", "com.sun.crypto.provider.DHParameterGenerator", ++ diffieHellmanAliases, null); ++ ++ /* ++ * Key Agreement engines ++ */ ++ attrs.clear(); ++ attrs.put("SupportedKeyClasses", "javax.crypto.interfaces.DHPublicKey" + ++ "|javax.crypto.interfaces.DHPrivateKey"); ++ ps("KeyAgreement", "DiffieHellman", ++ "com.sun.crypto.provider.DHKeyAgreement", ++ diffieHellmanAliases, attrs); ++ ++ /* ++ * Algorithm Parameter engines ++ */ ++ ps("AlgorithmParameters", "DiffieHellman", ++ "com.sun.crypto.provider.DHParameters", ++ diffieHellmanAliases, null); ++ ++ ps("AlgorithmParameters", "DES", ++ "com.sun.crypto.provider.DESParameters", ++ null, null); ++ ++ ps("AlgorithmParameters", "DESede", ++ "com.sun.crypto.provider.DESedeParameters", ++ desEdeAliases, null); ++ ++ ps("AlgorithmParameters", "PBEWithMD5AndDES", ++ "com.sun.crypto.provider.PBEParameters", ++ pkcs5MD5_DESAliases, null); ++ ++ ps("AlgorithmParameters", "PBEWithMD5AndTripleDES", ++ "com.sun.crypto.provider.PBEParameters", ++ null, null); ++ ++ ps("AlgorithmParameters", "PBEWithSHA1AndDESede", ++ "com.sun.crypto.provider.PBEParameters", ++ pkcs12DESedeAliases, null); ++ ++ ps("AlgorithmParameters", "PBEWithSHA1AndRC2_40", ++ "com.sun.crypto.provider.PBEParameters", ++ pkcs12RC2_40Aliases, null); ++ ++ ps("AlgorithmParameters", "PBEWithSHA1AndRC2_128", ++ "com.sun.crypto.provider.PBEParameters", ++ pkcs12RC2_128Aliases, null); ++ ++ ps("AlgorithmParameters", "PBEWithSHA1AndRC4_40", ++ "com.sun.crypto.provider.PBEParameters", ++ pkcs12RC4_40Aliases, null); ++ ++ ps("AlgorithmParameters", "PBEWithSHA1AndRC4_128", ++ "com.sun.crypto.provider.PBEParameters", ++ pkcs12RC4_128Aliases, null); ++ ++ ps("AlgorithmParameters", "PBES2", ++ "com.sun.crypto.provider.PBES2Parameters$General", ++ pkcs5PBES2Aliases, null); ++ ++ ps("AlgorithmParameters", "PBEWithHmacSHA1AndAES_128", ++ "com.sun.crypto.provider.PBES2Parameters$HmacSHA1AndAES_128", ++ null, null); ++ ++ ps("AlgorithmParameters", "PBEWithHmacSHA224AndAES_128", ++ "com.sun.crypto.provider.PBES2Parameters$HmacSHA224AndAES_128", ++ null, null); ++ ++ ps("AlgorithmParameters", "PBEWithHmacSHA256AndAES_128", ++ "com.sun.crypto.provider.PBES2Parameters$HmacSHA256AndAES_128", ++ null, null); ++ ++ ps("AlgorithmParameters", "PBEWithHmacSHA384AndAES_128", ++ "com.sun.crypto.provider.PBES2Parameters$HmacSHA384AndAES_128", ++ null, null); ++ ++ ps("AlgorithmParameters", "PBEWithHmacSHA512AndAES_128", ++ "com.sun.crypto.provider.PBES2Parameters$HmacSHA512AndAES_128", ++ null, null); ++ ++ ps("AlgorithmParameters", "PBEWithHmacSHA1AndAES_256", ++ "com.sun.crypto.provider.PBES2Parameters$HmacSHA1AndAES_256", ++ null, null); ++ ++ ps("AlgorithmParameters", "PBEWithHmacSHA224AndAES_256", ++ "com.sun.crypto.provider.PBES2Parameters$HmacSHA224AndAES_256", ++ null, null); ++ ++ ps("AlgorithmParameters", "PBEWithHmacSHA256AndAES_256", ++ "com.sun.crypto.provider.PBES2Parameters$HmacSHA256AndAES_256", ++ null, null); ++ ++ ps("AlgorithmParameters", "PBEWithHmacSHA384AndAES_256", ++ "com.sun.crypto.provider.PBES2Parameters$HmacSHA384AndAES_256", ++ null, null); ++ ++ ps("AlgorithmParameters", "PBEWithHmacSHA512AndAES_256", ++ "com.sun.crypto.provider.PBES2Parameters$HmacSHA512AndAES_256", ++ null, null); ++ ++ ps("AlgorithmParameters", "Blowfish", ++ "com.sun.crypto.provider.BlowfishParameters", ++ null, null); ++ ++ ps("AlgorithmParameters", "AES", ++ "com.sun.crypto.provider.AESParameters", ++ aesAliases, null); ++ ++ ps("AlgorithmParameters", "GCM", ++ "com.sun.crypto.provider.GCMParameters", ++ null, null); ++ ++ ps("AlgorithmParameters", "RC2", ++ "com.sun.crypto.provider.RC2Parameters", ++ null, null); ++ ++ ps("AlgorithmParameters", "OAEP", ++ "com.sun.crypto.provider.OAEPParameters", ++ null, null); ++ ++ /* ++ * Key factories ++ */ ++ ps("KeyFactory", "DiffieHellman", ++ "com.sun.crypto.provider.DHKeyFactory", ++ diffieHellmanAliases, null); ++ ++ /* ++ * Secret-key factories ++ */ ++ ps("SecretKeyFactory", "DES", ++ "com.sun.crypto.provider.DESKeyFactory", ++ null, null); ++ ++ ps("SecretKeyFactory", "DESede", ++ "com.sun.crypto.provider.DESedeKeyFactory", ++ desEdeAliases, null); ++ ++ ps("SecretKeyFactory", "PBEWithMD5AndDES", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithMD5AndDES", ++ pkcs5MD5_DESAliases, null); ++ ++ /* ++ * Internal in-house crypto algorithm used for ++ * the JCEKS keystore type. Since this was developed ++ * internally, there isn't an OID corresponding to this ++ * algorithm. ++ */ ++ ps("SecretKeyFactory", "PBEWithMD5AndTripleDES", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithMD5AndTripleDES", ++ null, null); ++ ++ ps("SecretKeyFactory", "PBEWithSHA1AndDESede", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndDESede", ++ pkcs12DESedeAliases, null); ++ ++ ps("SecretKeyFactory", "PBEWithSHA1AndRC2_40", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC2_40", ++ pkcs12RC2_40Aliases, null); ++ ++ ps("SecretKeyFactory", "PBEWithSHA1AndRC2_128", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC2_128", ++ pkcs12RC2_128Aliases, null); ++ ++ ps("SecretKeyFactory", "PBEWithSHA1AndRC4_40", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC4_40", ++ pkcs12RC4_40Aliases,null); ++ ++ ps("SecretKeyFactory", "PBEWithSHA1AndRC4_128", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC4_128", ++ pkcs12RC4_128Aliases, null); ++ ++ ps("SecretKeyFactory", "PBEWithHmacSHA1AndAES_128", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithHmacSHA1AndAES_128", ++ null, null); ++ ++ ps("SecretKeyFactory", "PBEWithHmacSHA224AndAES_128", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithHmacSHA224AndAES_128", ++ null, null); ++ ++ ps("SecretKeyFactory", "PBEWithHmacSHA256AndAES_128", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithHmacSHA256AndAES_128", ++ null, null); ++ ++ ps("SecretKeyFactory", "PBEWithHmacSHA384AndAES_128", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithHmacSHA384AndAES_128", ++ null, null); ++ ++ ps("SecretKeyFactory", "PBEWithHmacSHA512AndAES_128", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithHmacSHA512AndAES_128", ++ null, null); ++ ++ ps("SecretKeyFactory", "PBEWithHmacSHA1AndAES_256", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithHmacSHA1AndAES_256", ++ null, null); ++ ++ ps("SecretKeyFactory", "PBEWithHmacSHA224AndAES_256", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithHmacSHA224AndAES_256", ++ null, null); ++ ++ ps("SecretKeyFactory", "PBEWithHmacSHA256AndAES_256", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithHmacSHA256AndAES_256", ++ null, null); ++ ++ ps("SecretKeyFactory", "PBEWithHmacSHA384AndAES_256", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithHmacSHA384AndAES_256", ++ null, null); ++ ++ ps("SecretKeyFactory", "PBEWithHmacSHA512AndAES_256", ++ "com.sun.crypto.provider.PBEKeyFactory$PBEWithHmacSHA512AndAES_256", ++ null, null); ++ ++ // PBKDF2 ++ ps("SecretKeyFactory", "PBKDF2WithHmacSHA1", ++ "com.sun.crypto.provider.PBKDF2Core$HmacSHA1", ++ pkcs5PBKDF2Aliases, null); ++ ps("SecretKeyFactory", "PBKDF2WithHmacSHA224", ++ "com.sun.crypto.provider.PBKDF2Core$HmacSHA224", ++ null, null); ++ ps("SecretKeyFactory", "PBKDF2WithHmacSHA256", ++ "com.sun.crypto.provider.PBKDF2Core$HmacSHA256", ++ null, null); ++ ps("SecretKeyFactory", "PBKDF2WithHmacSHA384", ++ "com.sun.crypto.provider.PBKDF2Core$HmacSHA384", ++ null, null); ++ ps("SecretKeyFactory", "PBKDF2WithHmacSHA512", ++ "com.sun.crypto.provider.PBKDF2Core$HmacSHA512", ++ null, null); ++ ++ /* ++ * MAC ++ */ ++ attrs.clear(); ++ attrs.put("SupportedKeyFormats", "RAW"); ++ ps("Mac", "HmacMD5", "com.sun.crypto.provider.HmacMD5", null, attrs); ++ ps("Mac", "HmacSHA1", "com.sun.crypto.provider.HmacSHA1", ++ macSHA1Aliases, attrs); ++ ps("Mac", "HmacSHA224", "com.sun.crypto.provider.HmacCore$HmacSHA224", ++ macSHA224Aliases, attrs); ++ ps("Mac", "HmacSHA256", "com.sun.crypto.provider.HmacCore$HmacSHA256", ++ macSHA256Aliases, attrs); ++ ps("Mac", "HmacSHA384", "com.sun.crypto.provider.HmacCore$HmacSHA384", ++ macSHA384Aliases, attrs); ++ ps("Mac", "HmacSHA512", "com.sun.crypto.provider.HmacCore$HmacSHA512", ++ macSHA512Aliases, attrs); ++ // TODO: aliases with OIDs ++ ps("Mac", "HmacPBESHA1", "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA1", ++ null, attrs); ++ ps("Mac", "HmacPBESHA224", "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA224", ++ null, attrs); ++ ps("Mac", "HmacPBESHA256", "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA256", ++ null, attrs); ++ ps("Mac", "HmacPBESHA384", "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA384", ++ null, attrs); ++ ps("Mac", "HmacPBESHA512", "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA512", ++ null, attrs); ++ ps("Mac", "HmacPBESHA512/224", "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA512_224", ++ null, attrs); ++ ps("Mac", "HmacPBESHA512/256", "com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA512_256", ++ null, attrs); ++ ++ // PBMAC1 ++ ps("Mac", "PBEWithHmacSHA1", ++ "com.sun.crypto.provider.PBMAC1Core$HmacSHA1", null, attrs); ++ ps("Mac", "PBEWithHmacSHA224", ++ "com.sun.crypto.provider.PBMAC1Core$HmacSHA224", null, attrs); ++ ps("Mac", "PBEWithHmacSHA256", ++ "com.sun.crypto.provider.PBMAC1Core$HmacSHA256", null, attrs); ++ ps("Mac", "PBEWithHmacSHA384", ++ "com.sun.crypto.provider.PBMAC1Core$HmacSHA384", null, attrs); ++ ps("Mac", "PBEWithHmacSHA512", ++ "com.sun.crypto.provider.PBMAC1Core$HmacSHA512", null, attrs); ++ ps("Mac", "SslMacMD5", ++ "com.sun.crypto.provider.SslMacCore$SslMacMD5", null, attrs); ++ ps("Mac", "SslMacSHA1", ++ "com.sun.crypto.provider.SslMacCore$SslMacSHA1", null, attrs); ++ ++ /* ++ * KeyStore ++ */ ++ ps("KeyStore", "JCEKS", ++ "com.sun.crypto.provider.JceKeyStore", ++ null, null); ++ ++ /* ++ * SSL/TLS mechanisms ++ * ++ * These are strictly internal implementations and may ++ * be changed at any time. These names were chosen ++ * because PKCS11/SunPKCS11 does not yet have TLS1.2 ++ * mechanisms, and it will cause calls to come here. ++ */ ++ ps("KeyGenerator", "SunTlsPrf", ++ "com.sun.crypto.provider.TlsPrfGenerator$V10", ++ null, null); ++ ps("KeyGenerator", "SunTls12Prf", ++ "com.sun.crypto.provider.TlsPrfGenerator$V12", ++ null, null); ++ ++ ps("KeyGenerator", "SunTlsMasterSecret", ++ "com.sun.crypto.provider.TlsMasterSecretGenerator", ++ createAliases("SunTls12MasterSecret", ++ "SunTlsExtendedMasterSecret"), null); ++ ps("KeyGenerator", "SunTlsKeyMaterial", ++ "com.sun.crypto.provider.TlsKeyMaterialGenerator", ++ createAliases("SunTls12KeyMaterial"), null); ++ ++ ps("KeyGenerator", "SunTlsRsaPremasterSecret", ++ "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator", ++ createAliases("SunTls12RsaPremasterSecret"), null); + } + + // Return the instance of this class or create one if needed. +diff --git a/jdk/src/share/classes/java/security/AlgorithmParameterGenerator.java b/jdk/src/share/classes/java/security/AlgorithmParameterGenerator.java +index 7f9c7cbf4..b8cb61a56 100644 +--- a/jdk/src/share/classes/java/security/AlgorithmParameterGenerator.java ++++ b/jdk/src/share/classes/java/security/AlgorithmParameterGenerator.java +@@ -26,6 +26,7 @@ + package java.security; + + import java.security.spec.AlgorithmParameterSpec; ++import sun.security.jca.JCAUtil; + + /** + * The {@code AlgorithmParameterGenerator} class is used to generate a +@@ -282,7 +283,7 @@ public class AlgorithmParameterGenerator { + * @param size the size (number of bits). + */ + public final void init(int size) { +- paramGenSpi.engineInit(size, new SecureRandom()); ++ paramGenSpi.engineInit(size, JCAUtil.getSecureRandom()); + } + + /** +@@ -313,7 +314,7 @@ public class AlgorithmParameterGenerator { + */ + public final void init(AlgorithmParameterSpec genParamSpec) + throws InvalidAlgorithmParameterException { +- paramGenSpi.engineInit(genParamSpec, new SecureRandom()); ++ paramGenSpi.engineInit(genParamSpec, JCAUtil.getSecureRandom()); + } + + /** +diff --git a/jdk/src/share/classes/java/security/Provider.java b/jdk/src/share/classes/java/security/Provider.java +index 1eadb0e62..34f5ab22b 100644 +--- a/jdk/src/share/classes/java/security/Provider.java ++++ b/jdk/src/share/classes/java/security/Provider.java +@@ -30,6 +30,7 @@ import java.util.*; + import static java.util.Locale.ENGLISH; + import java.lang.ref.*; + import java.lang.reflect.*; ++import java.util.concurrent.ConcurrentHashMap; + import java.util.function.BiConsumer; + import java.util.function.BiFunction; + import java.util.function.Function; +@@ -135,6 +136,7 @@ public abstract class Provider extends Properties { + this.name = name; + this.version = version; + this.info = info; ++ this.serviceMap = new ConcurrentHashMap<>(); + putId(); + initialized = true; + } +@@ -662,15 +664,20 @@ public abstract class Provider extends Properties { + // legacy properties changed since last call to any services method? + private transient boolean legacyChanged; + // serviceMap changed since last call to getServices() +- private transient boolean servicesChanged; ++ private volatile transient boolean servicesChanged; + +- // Map ++ // Map used to keep track of legacy registration + private transient Map legacyStrings; + + // Map + // used for services added via putService(), initialized on demand + private transient Map serviceMap; + ++ // For backward compatibility, the registration ordering of ++ // SecureRandom (RNG) algorithms needs to be preserved for ++ // "new SecureRandom()" calls when this provider is used ++ private transient Set prngAlgos; ++ + // Map + // used for services added via legacy methods, init on demand + private transient Map legacyMap; +@@ -698,11 +705,13 @@ public abstract class Provider extends Properties { + } + defaults = null; + in.defaultReadObject(); ++ this.serviceMap = new ConcurrentHashMap<>(); + implClear(); + initialized = true; + putAll(copy); + } + ++ // check whether to update 'legacyString' with the specified key + private boolean checkLegacy(Object key) { + String keyString = (String)key; + if (keyString.startsWith("Provider.")) { +@@ -711,7 +720,7 @@ public abstract class Provider extends Properties { + + legacyChanged = true; + if (legacyStrings == null) { +- legacyStrings = new LinkedHashMap(); ++ legacyStrings = new LinkedHashMap<>(); + } + return true; + } +@@ -742,7 +751,7 @@ public abstract class Provider extends Properties { + if (!checkLegacy(key)) { + return false; + } +- legacyStrings.remove((String)key, value); ++ legacyStrings.remove((String)key, (String)value); + } + return super.remove(key, value); + } +@@ -772,7 +781,7 @@ public abstract class Provider extends Properties { + private void implReplaceAll(BiFunction function) { + legacyChanged = true; + if (legacyStrings == null) { +- legacyStrings = new LinkedHashMap(); ++ legacyStrings = new LinkedHashMap<>(); + } else { + legacyStrings.replaceAll((BiFunction) function); + } +@@ -796,8 +805,8 @@ public abstract class Provider extends Properties { + if (!checkLegacy(key)) { + return null; + } +- legacyStrings.computeIfAbsent((String) key, +- (Function) remappingFunction); ++ legacyStrings.compute((String) key, ++ (BiFunction) remappingFunction); + } + return super.compute(key, remappingFunction); + } +@@ -851,12 +860,11 @@ public abstract class Provider extends Properties { + if (legacyMap != null) { + legacyMap.clear(); + } +- if (serviceMap != null) { +- serviceMap.clear(); +- } ++ serviceMap.clear(); + legacyChanged = false; + servicesChanged = false; + serviceSet = null; ++ prngAlgos = null; + super.clear(); + putId(); + } +@@ -873,13 +881,13 @@ public abstract class Provider extends Properties { + this.algorithm = intern ? algorithm.intern() : algorithm; + } + public int hashCode() { +- return type.hashCode() + algorithm.hashCode(); ++ return Objects.hash(type, algorithm); + } + public boolean equals(Object obj) { + if (this == obj) { + return true; + } +- if (obj instanceof ServiceKey == false) { ++ if (!(obj instanceof ServiceKey)) { + return false; + } + ServiceKey other = (ServiceKey)obj; +@@ -901,7 +909,7 @@ public abstract class Provider extends Properties { + } + serviceSet = null; + if (legacyMap == null) { +- legacyMap = new LinkedHashMap(); ++ legacyMap = new ConcurrentHashMap<>(); + } else { + legacyMap.clear(); + } +@@ -957,7 +965,10 @@ public abstract class Provider extends Properties { + String type = getEngineName(typeAndAlg[0]); + String aliasAlg = typeAndAlg[1].intern(); + ServiceKey key = new ServiceKey(type, stdAlg, true); +- Service s = legacyMap.get(key); ++ Service s = serviceMap.get(key); ++ if (s == null) { ++ s = legacyMap.get(key); ++ } + if (s == null) { + s = new Service(this); + s.type = type; +@@ -986,6 +997,10 @@ public abstract class Provider extends Properties { + legacyMap.put(key, s); + } + s.className = className; ++ ++ if (type.equals("SecureRandom")) { ++ updateSecureRandomEntries(true, s.algorithm); ++ } + } else { // attribute + // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software"); + String attributeValue = value; +@@ -1031,7 +1046,7 @@ public abstract class Provider extends Properties { + * + * @since 1.5 + */ +- public synchronized Service getService(String type, String algorithm) { ++ public Service getService(String type, String algorithm) { + checkInitialized(); + // avoid allocating a new key object if possible + ServiceKey key = previousKey; +@@ -1039,14 +1054,19 @@ public abstract class Provider extends Properties { + key = new ServiceKey(type, algorithm, false); + previousKey = key; + } +- if (serviceMap != null) { +- Service service = serviceMap.get(key); +- if (service != null) { +- return service; ++ if (!serviceMap.isEmpty()) { ++ Service s = serviceMap.get(key); ++ if (s != null) { ++ return s; ++ } ++ } ++ synchronized (this){ ++ ensureLegacyParsed(); ++ if (legacyMap != null && !legacyMap.isEmpty()) { ++ return legacyMap.get(key); + } + } +- ensureLegacyParsed(); +- return (legacyMap != null) ? legacyMap.get(key) : null; ++ return null; + } + + // ServiceKey from previous getService() call +@@ -1075,10 +1095,10 @@ public abstract class Provider extends Properties { + if (serviceSet == null) { + ensureLegacyParsed(); + Set set = new LinkedHashSet<>(); +- if (serviceMap != null) { ++ if (!serviceMap.isEmpty()) { + set.addAll(serviceMap.values()); + } +- if (legacyMap != null) { ++ if (legacyMap != null && !legacyMap.isEmpty()) { + set.addAll(legacyMap.values()); + } + serviceSet = Collections.unmodifiableSet(set); +@@ -1116,7 +1136,7 @@ public abstract class Provider extends Properties { + * + * @since 1.5 + */ +- protected synchronized void putService(Service s) { ++ protected void putService(Service s) { + check("putProviderProperty." + name); + if (debug != null) { + debug.println(name + ".putService(): " + s); +@@ -1128,20 +1148,58 @@ public abstract class Provider extends Properties { + throw new IllegalArgumentException + ("service.getProvider() must match this Provider object"); + } +- if (serviceMap == null) { +- serviceMap = new LinkedHashMap(); +- } +- servicesChanged = true; + String type = s.getType(); + String algorithm = s.getAlgorithm(); + ServiceKey key = new ServiceKey(type, algorithm, true); +- // remove existing service + implRemoveService(serviceMap.get(key)); + serviceMap.put(key, s); + for (String alias : s.getAliases()) { + serviceMap.put(new ServiceKey(type, alias, true), s); + } +- putPropertyStrings(s); ++ servicesChanged = true; ++ synchronized (this) { ++ putPropertyStrings(s); ++ if (type.equals("SecureRandom")) { ++ updateSecureRandomEntries(true, s.algorithm); ++ } ++ } ++ } ++ ++ // keep tracks of the registered secure random algos and store them in order ++ private void updateSecureRandomEntries(boolean doAdd, String s) { ++ Objects.requireNonNull(s); ++ if (doAdd) { ++ if (prngAlgos == null) { ++ prngAlgos = new LinkedHashSet(); ++ } ++ prngAlgos.add(s); ++ } else { ++ prngAlgos.remove(s); ++ } ++ ++ if (debug != null) { ++ debug.println((doAdd? "Add":"Remove") + " SecureRandom algo " + s); ++ } ++ } ++ ++ // used by new SecureRandom() to find out the default SecureRandom ++ // service for this provider ++ synchronized Service getDefaultSecureRandomService() { ++ checkInitialized(); ++ ++ if (legacyChanged) { ++ prngAlgos = null; ++ ensureLegacyParsed(); ++ } ++ ++ if (prngAlgos != null && !prngAlgos.isEmpty()) { ++ // IMPORTANT: use the Service obj returned by getService(...) call ++ // as providers may override putService(...)/getService(...) and ++ // return their own Service objects ++ return getService("SecureRandom", prngAlgos.iterator().next()); ++ } ++ ++ return null; + } + + /** +@@ -1208,7 +1266,7 @@ public abstract class Provider extends Properties { + * + * @since 1.5 + */ +- protected synchronized void removeService(Service s) { ++ protected void removeService(Service s) { + check("removeProviderProperty." + name); + if (debug != null) { + debug.println(name + ".removeService(): " + s); +@@ -1220,7 +1278,7 @@ public abstract class Provider extends Properties { + } + + private void implRemoveService(Service s) { +- if ((s == null) || (serviceMap == null)) { ++ if ((s == null) || serviceMap.isEmpty()) { + return; + } + String type = s.getType(); +@@ -1235,7 +1293,12 @@ public abstract class Provider extends Properties { + for (String alias : s.getAliases()) { + serviceMap.remove(new ServiceKey(type, alias, false)); + } +- removePropertyStrings(s); ++ synchronized (this) { ++ removePropertyStrings(s); ++ if (type.equals("SecureRandom")) { ++ updateSecureRandomEntries(false, s.algorithm); ++ } ++ } + } + + // Wrapped String that behaves in a case insensitive way for equals/hashCode +diff --git a/jdk/src/share/classes/java/security/SecureRandom.java b/jdk/src/share/classes/java/security/SecureRandom.java +index 6848be5a2..05ff79191 100644 +--- a/jdk/src/share/classes/java/security/SecureRandom.java ++++ b/jdk/src/share/classes/java/security/SecureRandom.java +@@ -32,6 +32,7 @@ import java.security.Provider.Service; + + import sun.security.jca.*; + import sun.security.jca.GetInstance.Instance; ++import sun.security.provider.SunEntries; + import sun.security.util.Debug; + + /** +@@ -191,35 +192,50 @@ public class SecureRandom extends java.util.Random { + } + + private void getDefaultPRNG(boolean setSeed, byte[] seed) { +- String prng = getPrngAlgorithm(); +- if (prng == null) { +- // bummer, get the SUN implementation +- prng = "SHA1PRNG"; ++ Service prngService = null; ++ String prngAlgorithm = null; ++ for (Provider p : Providers.getProviderList().providers()) { ++ // SUN provider uses the SunEntries.DEF_SECURE_RANDOM_ALGO ++ // as the default SecureRandom algorithm; for other providers, ++ // Provider.getDefaultSecureRandom() will use the 1st ++ // registered SecureRandom algorithm ++ if (p.getName().equals("SUN")) { ++ prngAlgorithm = SunEntries.DEF_SECURE_RANDOM_ALGO; ++ prngService = p.getService("SecureRandom", prngAlgorithm); ++ break; ++ } else { ++ prngService = p.getDefaultSecureRandomService(); ++ if (prngService != null) { ++ prngAlgorithm = prngService.getAlgorithm(); ++ break; ++ } ++ } ++ } ++ // per javadoc, if none of the Providers support a RNG algorithm, ++ // then an implementation-specific default is returned. ++ if (prngService == null) { ++ prngAlgorithm = "SHA1PRNG"; + this.secureRandomSpi = new sun.security.provider.SecureRandom(); + this.provider = Providers.getSunProvider(); +- if (setSeed) { +- this.secureRandomSpi.engineSetSeed(seed); +- } + } else { + try { +- SecureRandom random = SecureRandom.getInstance(prng); +- this.secureRandomSpi = random.getSecureRandomSpi(); +- this.provider = random.getProvider(); +- if (setSeed) { +- this.secureRandomSpi.engineSetSeed(seed); +- } ++ this.secureRandomSpi = (SecureRandomSpi) prngService.newInstance(null); ++ this.provider = prngService.getProvider(); + } catch (NoSuchAlgorithmException nsae) { +- // never happens, because we made sure the algorithm exists ++ // should not happen + throw new RuntimeException(nsae); + } + } ++ if (setSeed) { ++ this.secureRandomSpi.engineSetSeed(seed); ++ } + // JDK 1.1 based implementations subclass SecureRandom instead of + // SecureRandomSpi. They will also go through this code path because + // they must call a SecureRandom constructor as it is their superclass. + // If we are dealing with such an implementation, do not set the + // algorithm value as it would be inaccurate. + if (getClass() == SecureRandom.class) { +- this.algorithm = prng; ++ this.algorithm = prngAlgorithm; + } + } + +@@ -386,13 +402,6 @@ public class SecureRandom extends java.util.Random { + instance.provider, algorithm); + } + +- /** +- * Returns the SecureRandomSpi of this SecureRandom object. +- */ +- SecureRandomSpi getSecureRandomSpi() { +- return secureRandomSpi; +- } +- + /** + * Returns the provider of this SecureRandom object. + * +@@ -548,23 +557,6 @@ public class SecureRandom extends java.util.Random { + return retVal; + } + +- /** +- * Gets a default PRNG algorithm by looking through all registered +- * providers. Returns the first PRNG algorithm of the first provider that +- * has registered a SecureRandom implementation, or null if none of the +- * registered providers supplies a SecureRandom implementation. +- */ +- private static String getPrngAlgorithm() { +- for (Provider p : Providers.getProviderList().providers()) { +- for (Service s : p.getServices()) { +- if (s.getType().equals("SecureRandom")) { +- return s.getAlgorithm(); +- } +- } +- } +- return null; +- } +- + /* + * Lazily initialize since Pattern.compile() is heavy. + * Effective Java (2nd Edition), Item 71. +diff --git a/jdk/src/share/classes/javax/crypto/Cipher.java b/jdk/src/share/classes/javax/crypto/Cipher.java +index d3d09d7e2..93c177e77 100644 +--- a/jdk/src/share/classes/javax/crypto/Cipher.java ++++ b/jdk/src/share/classes/javax/crypto/Cipher.java +@@ -1186,7 +1186,7 @@ public class Cipher { + * by the underlying {@code CipherSpi}. + */ + public final void init(int opmode, Key key) throws InvalidKeyException { +- init(opmode, key, JceSecurity.RANDOM); ++ init(opmode, key, JCAUtil.getSecureRandom()); + } + + /** +@@ -1327,7 +1327,7 @@ public class Cipher { + public final void init(int opmode, Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { +- init(opmode, key, params, JceSecurity.RANDOM); ++ init(opmode, key, params, JCAUtil.getSecureRandom()); + } + + /** +@@ -1470,7 +1470,7 @@ public class Cipher { + public final void init(int opmode, Key key, AlgorithmParameters params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { +- init(opmode, key, params, JceSecurity.RANDOM); ++ init(opmode, key, params, JCAUtil.getSecureRandom()); + } + + /** +@@ -1618,7 +1618,7 @@ public class Cipher { + public final void init(int opmode, Certificate certificate) + throws InvalidKeyException + { +- init(opmode, certificate, JceSecurity.RANDOM); ++ init(opmode, certificate, JCAUtil.getSecureRandom()); + } + + /** +diff --git a/jdk/src/share/classes/javax/crypto/JceSecurity.java b/jdk/src/share/classes/javax/crypto/JceSecurity.java +index e7e3a99f5..1186dc351 100644 +--- a/jdk/src/share/classes/javax/crypto/JceSecurity.java ++++ b/jdk/src/share/classes/javax/crypto/JceSecurity.java +@@ -49,8 +49,6 @@ import sun.security.util.Debug; + + final class JceSecurity { + +- static final SecureRandom RANDOM = new SecureRandom(); +- + // The defaultPolicy and exemptPolicy will be set up + // in the static initializer. + private static CryptoPermissions defaultPolicy = null; +diff --git a/jdk/src/share/classes/javax/crypto/KeyAgreement.java b/jdk/src/share/classes/javax/crypto/KeyAgreement.java +index 513fc501e..4e16bcacb 100644 +--- a/jdk/src/share/classes/javax/crypto/KeyAgreement.java ++++ b/jdk/src/share/classes/javax/crypto/KeyAgreement.java +@@ -438,7 +438,7 @@ public class KeyAgreement { + * has an incompatible algorithm type. + */ + public final void init(Key key) throws InvalidKeyException { +- init(key, JceSecurity.RANDOM); ++ init(key, JCAUtil.getSecureRandom()); + } + + /** +@@ -506,7 +506,7 @@ public class KeyAgreement { + public final void init(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { +- init(key, params, JceSecurity.RANDOM); ++ init(key, params, JCAUtil.getSecureRandom()); + } + + /** +diff --git a/jdk/src/share/classes/javax/crypto/KeyGenerator.java b/jdk/src/share/classes/javax/crypto/KeyGenerator.java +index 2a26da5e5..71fa64715 100644 +--- a/jdk/src/share/classes/javax/crypto/KeyGenerator.java ++++ b/jdk/src/share/classes/javax/crypto/KeyGenerator.java +@@ -427,7 +427,7 @@ public class KeyGenerator { + public final void init(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException + { +- init(params, JceSecurity.RANDOM); ++ init(params, JCAUtil.getSecureRandom()); + } + + /** +@@ -491,7 +491,7 @@ public class KeyGenerator { + * supported. + */ + public final void init(int keysize) { +- init(keysize, JceSecurity.RANDOM); ++ init(keysize, JCAUtil.getSecureRandom()); + } + + /** +diff --git a/jdk/src/share/classes/sun/security/provider/Sun.java b/jdk/src/share/classes/sun/security/provider/Sun.java +index 07ef2ff4a..75b411605 100644 +--- a/jdk/src/share/classes/sun/security/provider/Sun.java ++++ b/jdk/src/share/classes/sun/security/provider/Sun.java +@@ -28,7 +28,6 @@ package sun.security.provider; + import java.util.*; + import java.security.*; + +-import sun.security.action.PutAllAction; + + /** + * The SUN Security Provider. +@@ -49,17 +48,27 @@ public final class Sun extends Provider { + /* We are the SUN provider */ + super("SUN", 1.8d, INFO); + ++ Provider p = this; ++ Iterator serviceIter = new SunEntries(p).iterator(); ++ + // if there is no security manager installed, put directly into +- // the provider. Otherwise, create a temporary map and use a +- // doPrivileged() call at the end to transfer the contents ++ // the provider. + if (System.getSecurityManager() == null) { +- SunEntries.putEntries(this); ++ putEntries(serviceIter); + } else { +- // use LinkedHashMap to preserve the order of the PRNGs +- Map map = new LinkedHashMap<>(); +- SunEntries.putEntries(map); +- AccessController.doPrivileged(new PutAllAction(this, map)); ++ AccessController.doPrivileged(new PrivilegedAction() { ++ @Override ++ public Void run() { ++ putEntries(serviceIter); ++ return null; ++ } ++ }); + } + } + ++ void putEntries(Iterator i) { ++ while (i.hasNext()) { ++ putService(i.next()); ++ } ++ } + } +diff --git a/jdk/src/share/classes/sun/security/provider/SunEntries.java b/jdk/src/share/classes/sun/security/provider/SunEntries.java +index d85697841..fb61d40b0 100644 +--- a/jdk/src/share/classes/sun/security/provider/SunEntries.java ++++ b/jdk/src/share/classes/sun/security/provider/SunEntries.java +@@ -27,7 +27,7 @@ package sun.security.provider; + + import java.io.*; + import java.net.*; +-import java.util.Map; ++import java.util.*; + import java.security.*; + import sun.security.action.GetPropertyAction; + +@@ -77,255 +77,222 @@ import sun.security.action.GetPropertyAction; + * - JavaLoginConfig is the default file-based LoginModule Configuration type. + */ + +-final class SunEntries { ++public final class SunEntries { + +- private static final boolean useLegacyDSA = +- Boolean.parseBoolean(GetPropertyAction.privilegedGetProperty +- ("jdk.security.legacyDSAKeyPairGenerator")); ++ // the default algo used by SecureRandom class for new SecureRandom() calls ++ public static final String DEF_SECURE_RANDOM_ALGO; ++ ++ // create an aliases List from the specified aliases ++ public static List createAliases(String ... aliases) { ++ return Arrays.asList(aliases); ++ } + +- private SunEntries() { +- // empty ++ // create an aliases List from the specified oid followed by other aliases ++ public static List createAliasesWithOid(String ... oids) { ++ String[] result = Arrays.copyOf(oids, oids.length + 1); ++ result[result.length - 1] = "OID." + oids[0]; ++ return Arrays.asList(result); + } + +- static void putEntries(Map map) { ++ SunEntries(Provider p) { ++ services = new LinkedHashSet<>(50, 0.9f); ++ ++ // start populating content using the specified provider ++ ++ // common attribute map ++ HashMap attrs = new HashMap<>(3); + + /* +- * SecureRandom +- * +- * Register these first to speed up "new SecureRandom()", +- * which iterates through the list of algorithms ++ * SecureRandom engines + */ +- // register the native PRNG, if available +- // if user selected /dev/urandom, we put it before SHA1PRNG, +- // otherwise after it +- boolean nativeAvailable = NativePRNG.isAvailable(); +- boolean useNativePRNG = seedSource.equals(URL_DEV_URANDOM) || +- seedSource.equals(URL_DEV_RANDOM); +- +- if (nativeAvailable && useNativePRNG) { +- map.put("SecureRandom.NativePRNG", +- "sun.security.provider.NativePRNG"); +- } + +- map.put("SecureRandom.SHA1PRNG", +- "sun.security.provider.SecureRandom"); +- if (nativeAvailable && !useNativePRNG) { +- map.put("SecureRandom.NativePRNG", +- "sun.security.provider.NativePRNG"); ++ if (NativePRNG.isAvailable()) { ++ add(p, "SecureRandom", "NativePRNG", ++ "sun.security.provider.NativePRNG", ++ null, attrs); + } + + if (NativePRNG.Blocking.isAvailable()) { +- map.put("SecureRandom.NativePRNGBlocking", +- "sun.security.provider.NativePRNG$Blocking"); ++ add(p, "SecureRandom", "NativePRNGBlocking", ++ "sun.security.provider.NativePRNG$Blocking", null, attrs); + } + + if (NativePRNG.NonBlocking.isAvailable()) { +- map.put("SecureRandom.NativePRNGNonBlocking", +- "sun.security.provider.NativePRNG$NonBlocking"); ++ add(p, "SecureRandom", "NativePRNGNonBlocking", ++ "sun.security.provider.NativePRNG$NonBlocking", null, attrs); + } + ++ attrs.put("ImplementedIn", "Software"); ++ add(p, "SecureRandom", "SHA1PRNG", ++ "sun.security.provider.SecureRandom", null, attrs); ++ + /* + * Signature engines + */ +- map.put("Signature.SHA1withDSA", +- "sun.security.provider.DSA$SHA1withDSA"); +- map.put("Signature.NONEwithDSA", "sun.security.provider.DSA$RawDSA"); +- map.put("Alg.Alias.Signature.RawDSA", "NONEwithDSA"); +- map.put("Signature.SHA224withDSA", +- "sun.security.provider.DSA$SHA224withDSA"); +- map.put("Signature.SHA256withDSA", +- "sun.security.provider.DSA$SHA256withDSA"); +- ++ attrs.clear(); + String dsaKeyClasses = "java.security.interfaces.DSAPublicKey" + + "|java.security.interfaces.DSAPrivateKey"; +- map.put("Signature.SHA1withDSA SupportedKeyClasses", dsaKeyClasses); +- map.put("Signature.NONEwithDSA SupportedKeyClasses", dsaKeyClasses); +- map.put("Signature.SHA224withDSA SupportedKeyClasses", dsaKeyClasses); +- map.put("Signature.SHA256withDSA SupportedKeyClasses", dsaKeyClasses); +- +- map.put("Alg.Alias.Signature.DSA", "SHA1withDSA"); +- map.put("Alg.Alias.Signature.DSS", "SHA1withDSA"); +- map.put("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA"); +- map.put("Alg.Alias.Signature.SHA-1/DSA", "SHA1withDSA"); +- map.put("Alg.Alias.Signature.SHA1/DSA", "SHA1withDSA"); +- map.put("Alg.Alias.Signature.SHAwithDSA", "SHA1withDSA"); +- map.put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA"); +- map.put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", +- "SHA1withDSA"); +- map.put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA"); +- map.put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA1withDSA"); +- map.put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA1withDSA"); +- map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.1", +- "SHA224withDSA"); +- map.put("Alg.Alias.Signature.2.16.840.1.101.3.4.3.1", "SHA224withDSA"); +- map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.2", +- "SHA256withDSA"); +- map.put("Alg.Alias.Signature.2.16.840.1.101.3.4.3.2", "SHA256withDSA"); ++ attrs.put("SupportedKeyClasses", dsaKeyClasses); ++ attrs.put("ImplementedIn", "Software"); ++ ++ attrs.put("KeySize", "1024"); // for NONE and SHA1 DSA signatures ++ ++ add(p, "Signature", "SHA1withDSA", ++ "sun.security.provider.DSA$SHA1withDSA", ++ createAliasesWithOid("1.2.840.10040.4.3", "DSA", "DSS", ++ "SHA/DSA", "SHA-1/DSA", "SHA1/DSA", "SHAwithDSA", ++ "DSAWithSHA1", "1.3.14.3.2.13", "1.3.14.3.2.27"), attrs); ++ add(p, "Signature", "NONEwithDSA", "sun.security.provider.DSA$RawDSA", ++ createAliases("RawDSA"), attrs); ++ ++ attrs.put("KeySize", "2048"); // for SHA224 and SHA256 DSA signatures ++ ++ add(p, "Signature", "SHA224withDSA", ++ "sun.security.provider.DSA$SHA224withDSA", ++ createAliasesWithOid("2.16.840.1.101.3.4.3.1"), attrs); ++ add(p, "Signature", "SHA256withDSA", ++ "sun.security.provider.DSA$SHA256withDSA", ++ createAliasesWithOid("2.16.840.1.101.3.4.3.2"), attrs); ++ ++ attrs.remove("KeySize"); + + /* + * Key Pair Generator engines + */ ++ attrs.clear(); ++ attrs.put("ImplementedIn", "Software"); ++ attrs.put("KeySize", "2048"); // for DSA KPG and APG only ++ ++ String dsaOid = "1.2.840.10040.4.1"; ++ List dsaAliases = createAliasesWithOid(dsaOid, "1.3.14.3.2.12"); + String dsaKPGImplClass = "sun.security.provider.DSAKeyPairGenerator$"; + dsaKPGImplClass += (useLegacyDSA? "Legacy" : "Current"); +- map.put("KeyPairGenerator.DSA", dsaKPGImplClass); +- map.put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA"); +- map.put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA"); +- map.put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA"); +- +- /* +- * Digest engines +- */ +- map.put("MessageDigest.MD2", "sun.security.provider.MD2"); +- map.put("MessageDigest.MD5", "sun.security.provider.MD5"); +- map.put("MessageDigest.SHA", "sun.security.provider.SHA"); +- +- map.put("Alg.Alias.MessageDigest.SHA-1", "SHA"); +- map.put("Alg.Alias.MessageDigest.SHA1", "SHA"); +- map.put("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA"); +- map.put("Alg.Alias.MessageDigest.OID.1.3.14.3.2.26", "SHA"); +- +- map.put("MessageDigest.SHA-224", "sun.security.provider.SHA2$SHA224"); +- map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.4", "SHA-224"); +- map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.4", +- "SHA-224"); +- +- map.put("MessageDigest.SHA-256", "sun.security.provider.SHA2$SHA256"); +- map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256"); +- map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.1", +- "SHA-256"); +- map.put("MessageDigest.SHA-384", "sun.security.provider.SHA5$SHA384"); +- map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384"); +- map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.2", +- "SHA-384"); +- map.put("MessageDigest.SHA-512", "sun.security.provider.SHA5$SHA512"); +- map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512"); +- map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3", +- "SHA-512"); +- map.put("MessageDigest.SHA-512/224", "sun.security.provider.SHA5$SHA512_224"); +- map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.5", "SHA-512/224"); +- map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.5", +- "SHA-512/224"); +- map.put("MessageDigest.SHA-512/256", "sun.security.provider.SHA5$SHA512_256"); +- map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.6", "SHA-512/256"); +- map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.6", +- "SHA-512/256"); ++ add(p, "KeyPairGenerator", "DSA", dsaKPGImplClass, dsaAliases, attrs); + + /* + * Algorithm Parameter Generator engines + */ +- map.put("AlgorithmParameterGenerator.DSA", +- "sun.security.provider.DSAParameterGenerator"); ++ add(p, "AlgorithmParameterGenerator", "DSA", ++ "sun.security.provider.DSAParameterGenerator", dsaAliases, ++ attrs); ++ attrs.remove("KeySize"); + + /* + * Algorithm Parameter engines + */ +- map.put("AlgorithmParameters.DSA", +- "sun.security.provider.DSAParameters"); +- map.put("Alg.Alias.AlgorithmParameters.OID.1.2.840.10040.4.1", "DSA"); +- map.put("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.1", "DSA"); +- map.put("Alg.Alias.AlgorithmParameters.1.3.14.3.2.12", "DSA"); ++ add(p, "AlgorithmParameters", "DSA", ++ "sun.security.provider.DSAParameters", dsaAliases, attrs); + + /* + * Key factories + */ +- map.put("KeyFactory.DSA", "sun.security.provider.DSAKeyFactory"); +- map.put("Alg.Alias.KeyFactory.OID.1.2.840.10040.4.1", "DSA"); +- map.put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA"); +- map.put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSA"); ++ add(p, "KeyFactory", "DSA", "sun.security.provider.DSAKeyFactory", ++ dsaAliases, attrs); + + /* +- * Certificates ++ * Digest engines + */ +- map.put("CertificateFactory.X.509", +- "sun.security.provider.X509Factory"); +- map.put("Alg.Alias.CertificateFactory.X509", "X.509"); ++ add(p, "MessageDigest", "MD2", "sun.security.provider.MD2", null, attrs); ++ add(p, "MessageDigest", "MD5", "sun.security.provider.MD5", null, attrs); ++ add(p, "MessageDigest", "SHA", "sun.security.provider.SHA", ++ createAliasesWithOid("1.3.14.3.2.26", "SHA-1", "SHA1"), attrs); ++ ++ String sha2BaseOid = "2.16.840.1.101.3.4.2"; ++ add(p, "MessageDigest", "SHA-224", "sun.security.provider.SHA2$SHA224", ++ createAliasesWithOid(sha2BaseOid + ".4"), attrs); ++ add(p, "MessageDigest", "SHA-256", "sun.security.provider.SHA2$SHA256", ++ createAliasesWithOid(sha2BaseOid + ".1"), attrs); ++ add(p, "MessageDigest", "SHA-384", "sun.security.provider.SHA5$SHA384", ++ createAliasesWithOid(sha2BaseOid + ".2"), attrs); ++ add(p, "MessageDigest", "SHA-512", "sun.security.provider.SHA5$SHA512", ++ createAliasesWithOid(sha2BaseOid + ".3"), attrs); ++ add(p, "MessageDigest", "SHA-512/224", ++ "sun.security.provider.SHA5$SHA512_224", ++ createAliasesWithOid(sha2BaseOid + ".5"), attrs); ++ add(p, "MessageDigest", "SHA-512/256", ++ "sun.security.provider.SHA5$SHA512_256", ++ createAliasesWithOid(sha2BaseOid + ".6"), attrs); + +- /* +- * KeyStore +- */ +- map.put("KeyStore.JKS", +- "sun.security.provider.JavaKeyStore$DualFormatJKS"); +- map.put("KeyStore.CaseExactJKS", +- "sun.security.provider.JavaKeyStore$CaseExactJKS"); +- map.put("KeyStore.DKS", "sun.security.provider.DomainKeyStore$DKS"); + + /* +- * Policy ++ * Certificates + */ +- map.put("Policy.JavaPolicy", "sun.security.provider.PolicySpiFile"); ++ add(p, "CertificateFactory", "X.509", ++ "sun.security.provider.X509Factory", ++ createAliases("X509"), attrs); + + /* +- * Configuration ++ * KeyStore + */ +- map.put("Configuration.JavaLoginConfig", +- "sun.security.provider.ConfigFile$Spi"); ++ add(p, "KeyStore", "JKS", ++ "sun.security.provider.JavaKeyStore$DualFormatJKS", ++ null, attrs); ++ add(p, "KeyStore", "CaseExactJKS", ++ "sun.security.provider.JavaKeyStore$CaseExactJKS", ++ null, attrs); ++ add(p, "KeyStore", "DKS", "sun.security.provider.DomainKeyStore$DKS", ++ null, attrs); + + /* +- * CertPathBuilder ++ * CertStores + */ +- map.put("CertPathBuilder.PKIX", +- "sun.security.provider.certpath.SunCertPathBuilder"); +- map.put("CertPathBuilder.PKIX ValidationAlgorithm", +- "RFC5280"); ++ attrs.put("LDAPSchema", "RFC2587"); ++ add(p, "CertStore", "LDAP", ++ "sun.security.provider.certpath.ldap.LDAPCertStore", null, attrs); ++ attrs.remove("LDAPSchema"); ++ add(p, "CertStore", "Collection", ++ "sun.security.provider.certpath.CollectionCertStore", ++ null, attrs); ++ add(p, "CertStore", "com.sun.security.IndexedCollection", ++ "sun.security.provider.certpath.IndexedCollectionCertStore", ++ null, attrs); + + /* +- * CertPathValidator ++ * Policy + */ +- map.put("CertPathValidator.PKIX", +- "sun.security.provider.certpath.PKIXCertPathValidator"); +- map.put("CertPathValidator.PKIX ValidationAlgorithm", +- "RFC5280"); ++ add(p, "Policy", "JavaPolicy", "sun.security.provider.PolicySpiFile", ++ null, null); + + /* +- * CertStores ++ * Configuration + */ +- map.put("CertStore.LDAP", +- "sun.security.provider.certpath.ldap.LDAPCertStore"); +- map.put("CertStore.LDAP LDAPSchema", "RFC2587"); +- map.put("CertStore.Collection", +- "sun.security.provider.certpath.CollectionCertStore"); +- map.put("CertStore.com.sun.security.IndexedCollection", +- "sun.security.provider.certpath.IndexedCollectionCertStore"); ++ add(p, "Configuration", "JavaLoginConfig", ++ "sun.security.provider.ConfigFile$Spi", null, null); + + /* +- * KeySize ++ * CertPathBuilder and CertPathValidator + */ +- map.put("Signature.NONEwithDSA KeySize", "1024"); +- map.put("Signature.SHA1withDSA KeySize", "1024"); +- map.put("Signature.SHA224withDSA KeySize", "2048"); +- map.put("Signature.SHA256withDSA KeySize", "2048"); +- +- map.put("KeyPairGenerator.DSA KeySize", "2048"); +- map.put("AlgorithmParameterGenerator.DSA KeySize", "2048"); ++ attrs.clear(); ++ attrs.put("ValidationAlgorithm", "RFC5280"); ++ attrs.put("ImplementedIn", "Software"); ++ add(p, "CertPathBuilder", "PKIX", ++ "sun.security.provider.certpath.SunCertPathBuilder", ++ null, attrs); ++ add(p, "CertPathValidator", "PKIX", ++ "sun.security.provider.certpath.PKIXCertPathValidator", ++ null, attrs); ++ } + +- /* +- * Implementation type: software or hardware +- */ +- map.put("Signature.SHA1withDSA ImplementedIn", "Software"); +- map.put("KeyPairGenerator.DSA ImplementedIn", "Software"); +- map.put("MessageDigest.MD5 ImplementedIn", "Software"); +- map.put("MessageDigest.SHA ImplementedIn", "Software"); +- map.put("AlgorithmParameterGenerator.DSA ImplementedIn", +- "Software"); +- map.put("AlgorithmParameters.DSA ImplementedIn", "Software"); +- map.put("KeyFactory.DSA ImplementedIn", "Software"); +- map.put("SecureRandom.SHA1PRNG ImplementedIn", "Software"); +- map.put("CertificateFactory.X.509 ImplementedIn", "Software"); +- map.put("KeyStore.JKS ImplementedIn", "Software"); +- map.put("CertPathValidator.PKIX ImplementedIn", "Software"); +- map.put("CertPathBuilder.PKIX ImplementedIn", "Software"); +- map.put("CertStore.LDAP ImplementedIn", "Software"); +- map.put("CertStore.Collection ImplementedIn", "Software"); +- map.put("CertStore.com.sun.security.IndexedCollection ImplementedIn", +- "Software"); ++ Iterator iterator() { ++ return services.iterator(); ++ } + ++ private void add(Provider p, String type, String algo, String cn, ++ List aliases, HashMap attrs) { ++ services.add(new Provider.Service(p, type, algo, cn, aliases, attrs)); + } + ++ private LinkedHashSet services; ++ + // name of the *System* property, takes precedence over PROP_RNDSOURCE + private final static String PROP_EGD = "java.security.egd"; + // name of the *Security* property + private final static String PROP_RNDSOURCE = "securerandom.source"; + ++ private static final boolean useLegacyDSA = ++ Boolean.parseBoolean(GetPropertyAction.privilegedGetProperty ++ ("jdk.security.legacyDSAKeyPairGenerator")); ++ + final static String URL_DEV_RANDOM = "file:/dev/random"; + final static String URL_DEV_URANDOM = "file:/dev/urandom"; + +@@ -348,6 +315,12 @@ final class SunEntries { + return egdSource; + } + }); ++ ++ DEF_SECURE_RANDOM_ALGO = (NativePRNG.isAvailable() && ++ (seedSource.equals(URL_DEV_URANDOM) || ++ seedSource.equals(URL_DEV_RANDOM)) ? ++ "NativePRNG" : "SHA1PRNG"); ++ + } + + static String getSeedSource() { +diff --git a/jdk/src/share/classes/sun/security/provider/VerificationProvider.java b/jdk/src/share/classes/sun/security/provider/VerificationProvider.java +index 296b03437..d76d81999 100644 +--- a/jdk/src/share/classes/sun/security/provider/VerificationProvider.java ++++ b/jdk/src/share/classes/sun/security/provider/VerificationProvider.java +@@ -28,8 +28,6 @@ package sun.security.provider; + import java.util.*; + import java.security.*; + +-import sun.security.action.PutAllAction; +- + import sun.security.rsa.SunRsaSignEntries; + + /** +@@ -68,19 +66,29 @@ public final class VerificationProvider extends Provider { + return; + } + ++ Provider p = this; ++ Iterator sunIter = new SunEntries(p).iterator(); ++ Iterator rsaIter = new SunRsaSignEntries(p).iterator(); + // if there is no security manager installed, put directly into +- // the provider. Otherwise, create a temporary map and use a +- // doPrivileged() call at the end to transfer the contents ++ // the provider. + if (System.getSecurityManager() == null) { +- SunEntries.putEntries(this); +- SunRsaSignEntries.putEntries(this); ++ putEntries(sunIter); ++ putEntries(rsaIter); + } else { + // use LinkedHashMap to preserve the order of the PRNGs +- Map map = new LinkedHashMap<>(); +- SunEntries.putEntries(map); +- SunRsaSignEntries.putEntries(map); +- AccessController.doPrivileged(new PutAllAction(this, map)); ++ AccessController.doPrivileged(new PrivilegedAction() { ++ public Void run() { ++ putEntries(sunIter); ++ putEntries(rsaIter); ++ return null; ++ } ++ }); + } + } + ++ void putEntries(Iterator i) { ++ while (i.hasNext()) { ++ putService(i.next()); ++ } ++ } + } +diff --git a/jdk/src/share/classes/sun/security/rsa/SunRsaSign.java b/jdk/src/share/classes/sun/security/rsa/SunRsaSign.java +index 65ae02a08..3c3d0f693 100644 +--- a/jdk/src/share/classes/sun/security/rsa/SunRsaSign.java ++++ b/jdk/src/share/classes/sun/security/rsa/SunRsaSign.java +@@ -29,7 +29,6 @@ import java.util.*; + + import java.security.*; + +-import sun.security.action.PutAllAction; + + /** + * Provider class for the RSA signature provider. Supports RSA keyfactory, +@@ -45,17 +44,25 @@ public final class SunRsaSign extends Provider { + public SunRsaSign() { + super("SunRsaSign", 1.8d, "Sun RSA signature provider"); + +- // if there is no security manager installed, put directly into +- // the provider. Otherwise, create a temporary map and use a +- // doPrivileged() call at the end to transfer the contents ++ Provider p = this; ++ Iterator serviceIter = new SunRsaSignEntries(p).iterator(); ++ + if (System.getSecurityManager() == null) { +- SunRsaSignEntries.putEntries(this); ++ putEntries(serviceIter); + } else { +- // use LinkedHashMap to preserve the order of the PRNGs +- Map map = new HashMap<>(); +- SunRsaSignEntries.putEntries(map); +- AccessController.doPrivileged(new PutAllAction(this, map)); ++ AccessController.doPrivileged(new PrivilegedAction() { ++ @Override ++ public Void run() { ++ putEntries(serviceIter); ++ return null; ++ } ++ }); + } + } + ++ void putEntries(Iterator i) { ++ while (i.hasNext()) { ++ putService(i.next()); ++ } ++ } + } +diff --git a/jdk/src/share/classes/sun/security/rsa/SunRsaSignEntries.java b/jdk/src/share/classes/sun/security/rsa/SunRsaSignEntries.java +index 6af5fdf85..f8de9eccc 100644 +--- a/jdk/src/share/classes/sun/security/rsa/SunRsaSignEntries.java ++++ b/jdk/src/share/classes/sun/security/rsa/SunRsaSignEntries.java +@@ -25,7 +25,9 @@ + + package sun.security.rsa; + +-import java.util.Map; ++import java.util.*; ++import java.security.Provider; ++import static sun.security.provider.SunEntries.createAliasesWithOid; + + /** + * Defines the entries of the SunRsaSign provider. +@@ -34,102 +36,81 @@ import java.util.Map; + */ + public final class SunRsaSignEntries { + +- private SunRsaSignEntries() { +- // empty ++ private void add(Provider p, String type, String algo, String cn, ++ List aliases, HashMap attrs) { ++ services.add(new Provider.Service(p, type, algo, cn, aliases, attrs)); + } + +- public static void putEntries(Map map) { +- +- // main algorithms +- map.put("KeyFactory.RSA", +- "sun.security.rsa.RSAKeyFactory$Legacy"); +- map.put("KeyPairGenerator.RSA", +- "sun.security.rsa.RSAKeyPairGenerator$Legacy"); +- map.put("Signature.MD2withRSA", +- "sun.security.rsa.RSASignature$MD2withRSA"); +- map.put("Signature.MD5withRSA", +- "sun.security.rsa.RSASignature$MD5withRSA"); +- map.put("Signature.SHA1withRSA", +- "sun.security.rsa.RSASignature$SHA1withRSA"); +- map.put("Signature.SHA224withRSA", +- "sun.security.rsa.RSASignature$SHA224withRSA"); +- map.put("Signature.SHA256withRSA", +- "sun.security.rsa.RSASignature$SHA256withRSA"); +- map.put("Signature.SHA384withRSA", +- "sun.security.rsa.RSASignature$SHA384withRSA"); +- map.put("Signature.SHA512withRSA", +- "sun.security.rsa.RSASignature$SHA512withRSA"); +- map.put("Signature.SHA512/224withRSA", +- "sun.security.rsa.RSASignature$SHA512_224withRSA"); +- map.put("Signature.SHA512/256withRSA", +- "sun.security.rsa.RSASignature$SHA512_256withRSA"); +- +- map.put("KeyFactory.RSASSA-PSS", +- "sun.security.rsa.RSAKeyFactory$PSS"); +- map.put("KeyPairGenerator.RSASSA-PSS", +- "sun.security.rsa.RSAKeyPairGenerator$PSS"); +- map.put("Signature.RSASSA-PSS", +- "sun.security.rsa.RSAPSSSignature"); +- map.put("AlgorithmParameters.RSASSA-PSS", +- "sun.security.rsa.PSSParameters"); +- +- // attributes for supported key classes +- String rsaKeyClasses = "java.security.interfaces.RSAPublicKey" + +- "|java.security.interfaces.RSAPrivateKey"; +- map.put("Signature.MD2withRSA SupportedKeyClasses", rsaKeyClasses); +- map.put("Signature.MD5withRSA SupportedKeyClasses", rsaKeyClasses); +- map.put("Signature.SHA1withRSA SupportedKeyClasses", rsaKeyClasses); +- map.put("Signature.SHA224withRSA SupportedKeyClasses", rsaKeyClasses); +- map.put("Signature.SHA256withRSA SupportedKeyClasses", rsaKeyClasses); +- map.put("Signature.SHA384withRSA SupportedKeyClasses", rsaKeyClasses); +- map.put("Signature.SHA512withRSA SupportedKeyClasses", rsaKeyClasses); +- map.put("Signature.SHA512/224withRSA SupportedKeyClasses", rsaKeyClasses); +- map.put("Signature.SHA512/256withRSA SupportedKeyClasses", rsaKeyClasses); +- map.put("Signature.RSASSA-PSS SupportedKeyClasses", rsaKeyClasses); +- +- // aliases +- map.put("Alg.Alias.KeyFactory.1.2.840.113549.1.1", "RSA"); +- map.put("Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1", "RSA"); +- +- map.put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1", "RSA"); +- map.put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1", "RSA"); +- +- map.put("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA"); +- map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2", "MD2withRSA"); +- +- map.put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); +- map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA"); +- +- map.put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); +- map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA"); +- map.put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA"); +- +- map.put("Alg.Alias.Signature.1.2.840.113549.1.1.14", "SHA224withRSA"); +- map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.14", "SHA224withRSA"); +- +- map.put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA"); +- map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA"); +- +- map.put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA"); +- map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA"); +- +- map.put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA"); +- map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA"); +- map.put("Alg.Alias.Signature.1.2.840.113549.1.1.15", "SHA512/224withRSA"); +- map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.15", "SHA512/224withRSA"); +- map.put("Alg.Alias.Signature.1.2.840.113549.1.1.16", "SHA512/256withRSA"); +- map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.16", "SHA512/256withRSA"); +- +- map.put("Alg.Alias.KeyFactory.1.2.840.113549.1.1.10", "RSASSA-PSS"); +- map.put("Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); +- +- map.put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.10", "RSASSA-PSS"); +- map.put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); +- +- map.put("Alg.Alias.Signature.1.2.840.113549.1.1.10", "RSASSA-PSS"); +- map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ // extend LinkedHashSet for consistency with SunEntries ++ // used by sun.security.provider.VerificationProvider ++ public SunRsaSignEntries(Provider p) { ++ services = new LinkedHashSet<>(20, 0.9f); ++ ++ // start populating content using the specified provider ++ ++ // common oids ++ String rsaOid = "1.2.840.113549.1.1"; ++ List rsaAliases = createAliasesWithOid(rsaOid); ++ List rsapssAliases = createAliasesWithOid(rsaOid + ".10"); ++ String sha1withRSAOid2 = "1.3.14.3.2.29"; ++ ++ // common attribute map ++ HashMap attrs = new HashMap<>(3); ++ attrs.put("SupportedKeyClasses", ++ "java.security.interfaces.RSAPublicKey" + ++ "|java.security.interfaces.RSAPrivateKey"); ++ ++ add(p, "KeyFactory", "RSA", ++ "sun.security.rsa.RSAKeyFactory$Legacy", ++ rsaAliases, null); ++ add(p, "KeyPairGenerator", "RSA", ++ "sun.security.rsa.RSAKeyPairGenerator$Legacy", ++ rsaAliases, null); ++ add(p, "Signature", "MD2withRSA", ++ "sun.security.rsa.RSASignature$MD2withRSA", ++ createAliasesWithOid(rsaOid + ".2"), attrs); ++ add(p, "Signature", "MD5withRSA", ++ "sun.security.rsa.RSASignature$MD5withRSA", ++ createAliasesWithOid(rsaOid + ".4"), attrs); ++ add(p, "Signature", "SHA1withRSA", ++ "sun.security.rsa.RSASignature$SHA1withRSA", ++ createAliasesWithOid(rsaOid + ".5", sha1withRSAOid2), attrs); ++ add(p, "Signature", "SHA224withRSA", ++ "sun.security.rsa.RSASignature$SHA224withRSA", ++ createAliasesWithOid(rsaOid + ".14"), attrs); ++ add(p, "Signature", "SHA256withRSA", ++ "sun.security.rsa.RSASignature$SHA256withRSA", ++ createAliasesWithOid(rsaOid + ".11"), attrs); ++ add(p, "Signature", "SHA384withRSA", ++ "sun.security.rsa.RSASignature$SHA384withRSA", ++ createAliasesWithOid(rsaOid + ".12"), attrs); ++ add(p, "Signature", "SHA512withRSA", ++ "sun.security.rsa.RSASignature$SHA512withRSA", ++ createAliasesWithOid(rsaOid + ".13"), attrs); ++ add(p, "Signature", "SHA512/224withRSA", ++ "sun.security.rsa.RSASignature$SHA512_224withRSA", ++ createAliasesWithOid(rsaOid + ".15"), attrs); ++ add(p, "Signature", "SHA512/256withRSA", ++ "sun.security.rsa.RSASignature$SHA512_256withRSA", ++ createAliasesWithOid(rsaOid + ".16"), attrs); ++ ++ add(p, "KeyFactory", "RSASSA-PSS", ++ "sun.security.rsa.RSAKeyFactory$PSS", ++ rsapssAliases, null); ++ add(p, "KeyPairGenerator", "RSASSA-PSS", ++ "sun.security.rsa.RSAKeyPairGenerator$PSS", ++ rsapssAliases, null); ++ add(p, "Signature", "RSASSA-PSS", ++ "sun.security.rsa.RSAPSSSignature", ++ rsapssAliases, attrs); ++ add(p, "AlgorithmParameters", "RSASSA-PSS", ++ "sun.security.rsa.PSSParameters", ++ rsapssAliases, null); ++ } + +- map.put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.1.10", "RSASSA-PSS"); +- map.put("Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ public Iterator iterator() { ++ return services.iterator(); + } ++ ++ private LinkedHashSet services; + } +diff --git a/jdk/src/share/classes/sun/security/ssl/SunJSSE.java b/jdk/src/share/classes/sun/security/ssl/SunJSSE.java +index 2845dc379..58b791c99 100644 +--- a/jdk/src/share/classes/sun/security/ssl/SunJSSE.java ++++ b/jdk/src/share/classes/sun/security/ssl/SunJSSE.java +@@ -26,9 +26,12 @@ + + package sun.security.ssl; + +-import static sun.security.util.SecurityConstants.PROVIDER_VER; +- + import java.security.*; ++import java.util.*; ++ ++import static sun.security.provider.SunEntries.createAliasesWithOid; ++import static sun.security.util.SecurityConstants.PROVIDER_VER; ++import static sun.security.provider.SunEntries.createAliases; + + /** + * The JSSE provider. +@@ -159,79 +162,78 @@ public abstract class SunJSSE extends java.security.Provider { + }); + } + ++ private void ps(String type, String algo, String cn, ++ List aliases, HashMap attrs) { ++ putService(new Provider.Service(this, type, algo, cn, aliases, attrs)); ++ } ++ ++ + private void doRegister(boolean isfips) { + if (isfips == false) { +- put("KeyFactory.RSA", +- "sun.security.rsa.RSAKeyFactory$Legacy"); +- put("Alg.Alias.KeyFactory.1.2.840.113549.1.1", "RSA"); +- put("Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1", "RSA"); +- +- put("KeyPairGenerator.RSA", +- "sun.security.rsa.RSAKeyPairGenerator$Legacy"); +- put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1", "RSA"); +- put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1", "RSA"); +- +- put("Signature.MD2withRSA", +- "sun.security.rsa.RSASignature$MD2withRSA"); +- put("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA"); +- put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2", +- "MD2withRSA"); +- +- put("Signature.MD5withRSA", +- "sun.security.rsa.RSASignature$MD5withRSA"); +- put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); +- put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", +- "MD5withRSA"); +- +- put("Signature.SHA1withRSA", +- "sun.security.rsa.RSASignature$SHA1withRSA"); +- put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); +- put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", +- "SHA1withRSA"); +- put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA"); +- put("Alg.Alias.Signature.OID.1.3.14.3.2.29", "SHA1withRSA"); ++ // common oids ++ String rsaOid = "1.2.840.113549.1.1"; ++ List rsaAliases = createAliasesWithOid(rsaOid); ++ String sha1withRSAOid2 = "1.3.14.3.2.29"; ++ ++ // common attribute map ++ HashMap attrs = new HashMap<>(3); ++ attrs.put("SupportedKeyClasses", ++ "java.security.interfaces.RSAPublicKey" + ++ "|java.security.interfaces.RSAPrivateKey"); ++ ++ ps("KeyFactory", "RSA", ++ "sun.security.rsa.RSAKeyFactory$Legacy", ++ rsaAliases, null); ++ ps("KeyPairGenerator", "RSA", ++ "sun.security.rsa.RSAKeyPairGenerator$Legacy", ++ rsaAliases, null); ++ ps("Signature", "MD2withRSA", ++ "sun.security.rsa.RSASignature$MD2withRSA", ++ createAliasesWithOid(rsaOid + ".2"), attrs); ++ ps("Signature", "MD5withRSA", ++ "sun.security.rsa.RSASignature$MD5withRSA", ++ createAliasesWithOid(rsaOid + ".4"), attrs); ++ ps("Signature", "SHA1withRSA", ++ "sun.security.rsa.RSASignature$SHA1withRSA", ++ createAliasesWithOid(rsaOid + ".5", sha1withRSAOid2, "OID." + sha1withRSAOid2), attrs); + + } +- put("Signature.MD5andSHA1withRSA", +- "sun.security.ssl.RSASignature"); +- +- put("KeyManagerFactory.SunX509", +- "sun.security.ssl.KeyManagerFactoryImpl$SunX509"); +- put("KeyManagerFactory.NewSunX509", +- "sun.security.ssl.KeyManagerFactoryImpl$X509"); +- put("Alg.Alias.KeyManagerFactory.PKIX", "NewSunX509"); +- +- put("TrustManagerFactory.SunX509", +- "sun.security.ssl.TrustManagerFactoryImpl$SimpleFactory"); +- put("TrustManagerFactory.PKIX", +- "sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory"); +- put("Alg.Alias.TrustManagerFactory.SunPKIX", "PKIX"); +- put("Alg.Alias.TrustManagerFactory.X509", "PKIX"); +- put("Alg.Alias.TrustManagerFactory.X.509", "PKIX"); +- +- put("SSLContext.TLSv1", +- "sun.security.ssl.SSLContextImpl$TLS10Context"); +- put("SSLContext.TLSv1.1", +- "sun.security.ssl.SSLContextImpl$TLS11Context"); +- put("SSLContext.TLSv1.2", +- "sun.security.ssl.SSLContextImpl$TLS12Context"); +- put("SSLContext.TLSv1.3", +- "sun.security.ssl.SSLContextImpl$TLS13Context"); +- put("SSLContext.TLS", +- "sun.security.ssl.SSLContextImpl$TLSContext"); +- if (isfips == false) { +- put("Alg.Alias.SSLContext.SSL", "TLS"); +- put("Alg.Alias.SSLContext.SSLv3", "TLSv1"); +- } +- +- put("SSLContext.Default", +- "sun.security.ssl.SSLContextImpl$DefaultSSLContext"); ++ ps("Signature", "MD5andSHA1withRSA", ++ "sun.security.ssl.RSASignature", null, null); ++ ++ ps("KeyManagerFactory", "SunX509", ++ "sun.security.ssl.KeyManagerFactoryImpl$SunX509", null, null); ++ ps("KeyManagerFactory", "NewSunX509", ++ "sun.security.ssl.KeyManagerFactoryImpl$X509", ++ createAliases("PKIX"), null); ++ ++ ps("TrustManagerFactory", "SunX509", ++ "sun.security.ssl.TrustManagerFactoryImpl$SimpleFactory", null, null); ++ ps("TrustManagerFactory", "PKIX", ++ "sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory", ++ createAliases("SunPKIX", "X509", "X.509"), null); ++ ++ ps("SSLContext", "TLSv1", ++ "sun.security.ssl.SSLContextImpl$TLS10Context", ++ (isfips? null : createAliases("SSLv3")), null); ++ ps("SSLContext", "TLSv1.1", ++ "sun.security.ssl.SSLContextImpl$TLS11Context", null, null); ++ ps("SSLContext", "TLSv1.2", ++ "sun.security.ssl.SSLContextImpl$TLS12Context", null, null); ++ ps("SSLContext", "TLSv1.3", ++ "sun.security.ssl.SSLContextImpl$TLS13Context", null, null); ++ ps("SSLContext", "TLS", ++ "sun.security.ssl.SSLContextImpl$TLSContext", ++ (isfips? null : createAliases("SSL")), null); ++ ++ ps("SSLContext", "Default", ++ "sun.security.ssl.SSLContextImpl$DefaultSSLContext", null, null); + + /* + * KeyStore + */ +- put("KeyStore.PKCS12", +- "sun.security.pkcs12.PKCS12KeyStore"); ++ ps("KeyStore", "PKCS12", ++ "sun.security.pkcs12.PKCS12KeyStore", null, null); + } + + private void subclassCheck() { +diff --git a/jdk/test/java/security/Provider/BaseProviderValidator.java b/jdk/test/java/security/Provider/BaseProviderValidator.java +new file mode 100644 +index 000000000..510529baa +--- /dev/null ++++ b/jdk/test/java/security/Provider/BaseProviderValidator.java +@@ -0,0 +1,76 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++/* ++ * @test ++ * @bug 7092821 ++ * @library ../testlibrary ++ * @summary make sure that Sun providers do not miss any algorithms after ++ * modifying the frameworks underneath ++ * @author Henry Yang ++ */ ++ ++import java.security.Provider; ++import java.security.Provider.Service; ++ ++/** ++ * Base class for a provider validator ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++public abstract class BaseProviderValidator { ++ String providerName; ++ Provider provider; ++ ++ public BaseProviderValidator() { ++ provider = getDefaultProvider(); ++ providerName = provider.getName(); ++ } ++ ++ abstract Provider getDefaultProvider(); ++ ++ abstract boolean validate() throws Exception; ++ ++ Service getService(String type, String algo) { ++ return ProviderValidationUtil.getService(provider, type, algo); ++ } ++ ++ boolean checkService(String serviceName) { ++ String[] typeAndAlg = ProviderValidationUtil.getTypeAndAlgorithm(serviceName); ++ if(typeAndAlg == null || typeAndAlg.length < 2){ ++ throw new RuntimeException("service name is not in a right formation"); ++ } ++ return ProviderValidationUtil.checkService(provider, typeAndAlg[0], typeAndAlg[1]); ++ } ++ ++ boolean checkAlias(String aliasFullName, String serviceShortName) { ++ return ProviderValidationUtil.checkAlias(provider, aliasFullName, serviceShortName); ++ } ++ ++ boolean checkAttribute(String attrName, String attrValue) { ++ String[] nameAndAttr = attrName.split("\\s+"); ++ return ProviderValidationUtil.checkAttribute(provider, nameAndAttr[0], nameAndAttr[1], attrValue); ++ } ++} +diff --git a/jdk/test/java/security/Provider/GetServiceRace.java b/jdk/test/java/security/Provider/GetServiceRace.java +new file mode 100644 +index 000000000..b5b47b5d9 +--- /dev/null ++++ b/jdk/test/java/security/Provider/GetServiceRace.java +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++/* ++ * @test ++ * @bug 8231387 ++ * @library ../testlibrary ++ * @summary make sure getService() avoids a race ++ * @author Tianmin Shi ++ */ ++ ++import java.security.Provider; ++ ++public class GetServiceRace { ++ ++ private static final Provider testProvider; ++ static { ++ testProvider = new Provider("MyProvider", 1.0, "test") { ++ }; ++ testProvider.put("CertificateFactory.Fixed", "MyCertificateFactory"); ++ } ++ ++ private static final int NUMBER_OF_RETRIEVERS = 3; ++ private static final int TEST_TIME_MS = 1000; ++ ++ public static boolean testFailed = false; ++ ++ public static void main(String[] args) throws Exception { ++ Updater updater = new Updater(); ++ updater.start(); ++ Retriever [] retrievers = new Retriever[NUMBER_OF_RETRIEVERS]; ++ for (int i=0; i Test Passed"); ++ } ++ ++ private static void validate(Provider p, String algo, String alias) { ++ Provider.Service s = p.getService("SecureRandom", alias); ++ if (s == null) { ++ throw new RuntimeException("Failed alias " + alias + " check, " + ++ "exp: " + algo + ", got null"); ++ } ++ if (!algo.equals(s.getAlgorithm())) { ++ throw new RuntimeException("Failed alias " + alias + " check, " + ++ "exp: " + algo + ", got " + s.getAlgorithm()); ++ } ++ } ++ ++ ++ private static final String SR_IMPLCLASS = ++ "sun.security.provider.SecureRandom"; ++ private static class CustomProvider extends Provider { ++ private static class CustomService extends Provider.Service { ++ CustomService(Provider p, String type, String algo, String cName) { ++ super(p, type, algo, cName, null, null); ++ } ++ } ++ ++ CustomProvider() { ++ super("CP", 1.0, "test provider that registers two services, " + ++ "one with put and one with putService"); ++ ++ putService(new CustomService(this, "SecureRandom", ++ MODERN_ALGO, SR_IMPLCLASS)); ++ put("SecureRandom." + LEGACY_ALGO, SR_IMPLCLASS); ++ } ++ } ++} +diff --git a/jdk/test/java/security/Provider/ProviderValidationUtil.java b/jdk/test/java/security/Provider/ProviderValidationUtil.java +new file mode 100644 +index 000000000..8c4ef89c7 +--- /dev/null ++++ b/jdk/test/java/security/Provider/ProviderValidationUtil.java +@@ -0,0 +1,270 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++/* ++ * @test ++ * @bug 7092821 ++ * @library ../testlibrary ++ * @summary make sure that Sun providers do not miss any algorithms after ++ * modifying the frameworks underneath ++ * @author Henry Yang ++ */ ++ ++import static java.util.Locale.ENGLISH; ++ ++import java.lang.reflect.InvocationTargetException; ++import java.lang.reflect.Method; ++import java.security.Provider; ++import java.security.Provider.Service; ++import java.util.Collections; ++import java.util.HashSet; ++import java.util.List; ++import java.util.Set; ++ ++/** ++ * utils for provider validator ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++public class ProviderValidationUtil { ++ private static final String ALIAS_PREFIX_LOWER = "alg.alias."; ++ private static final int ALIAS_LENGTH = ALIAS_PREFIX_LOWER.length(); ++ ++ /** ++ * get a service from a provider for a specific algorithm ++ * ++ * @param provider the provider to get a service ++ * @param type algorithm type ++ * @param algo algorithm name ++ * @return the service of the specific algorithm ++ */ ++ public static Service getService(Provider provider, String type, String algo) { ++ Service service = provider.getService(type, algo); ++ if (service == null) { ++ throw new ServiceNotFoundException(provider.getName(), getServiceName(type, algo)); ++ } ++ return service; ++ } ++ ++ /** ++ * checks if the provider offers services for a specific algorithm ++ * ++ * @param provider the provider to check ++ * @param type algorithm type ++ * @param algo algorithm name ++ * @return true if passed this check ++ */ ++ public static boolean checkService(Provider provider, String type, String algo) { ++ Service service = getService(provider, type, algo); ++ String className = service.getClassName(); ++ if (className == null) { ++ throw new ServiceNotFoundException(provider.getName(), getServiceName(type, algo)); ++ } ++ try { ++ Class.forName(className); ++ } catch (ClassNotFoundException e) { ++ throw new ServiceNotFoundException(provider.getName(), getServiceName(type, algo)); ++ } ++ return true; ++ } ++ ++ private static List getAlias(Service service) { ++ try { ++ Method method = Service.class.getDeclaredMethod("getAliases"); ++ method.setAccessible(true); ++ List aliases = (List) method.invoke(service, null); ++ return aliases; ++ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { ++ e.printStackTrace(); ++ } ++ return Collections.emptyList(); ++ } ++ ++ /** ++ * check if the provider associates the alias name to the service ++ * ++ * @param provider the provider to check ++ * @param aliasFullName alias ++ * @param serviceShortName service name for short ++ * @return true if passed this check ++ */ ++ public static boolean checkAlias(Provider provider, String aliasFullName, String serviceShortName) { ++ if (aliasFullName.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) { ++ // for example, in provider defination put("Alg.Alias.MessageDigest.SHA", "SHA-1"); ++ // Alg.Alias.MessageDigest.SHA for the aliasFullNanme and SHA-1 for serviceShortName ++ // the aliasKey is MessageDigest.SHA ++ String aliasKey = aliasFullName.substring(ALIAS_LENGTH); ++ String[] typeAndAlg = getTypeAndAlgorithm(aliasKey); ++ if (typeAndAlg == null || typeAndAlg.length < 2) { ++ throw new NameMalFormatException("alias name and type cannot be null"); ++ } ++ String type = typeAndAlg[0]; ++ String aliasAlg = typeAndAlg[1].intern(); ++ Service aliasService = provider.getService(type, aliasAlg); ++ if (aliasService == null) { ++ throw new ServiceNotFoundException(provider.getName(), getServiceName(type, aliasAlg)); ++ } ++ Service service = provider.getService(type, serviceShortName); ++ if (service == null) { ++ throw new ServiceNotFoundException(provider.getName(), getServiceName(type, serviceShortName)); ++ } ++ if (service != aliasService || !checkAliasInService(service, aliasAlg)) { ++ throw new AliasNotMatchedException( ++ getServiceName(type, aliasAlg), getServiceName(type, serviceShortName)); ++ } ++ } else { ++ throw new NameMalFormatException("Alias name is not in a proper format"); ++ } ++ return true; ++ } ++ ++ private static boolean checkAliasInService(Service service, String... aliasArray) { ++ List aliases = getAlias(service); ++ Set aliasesSet = new HashSet<>(); ++ aliasesSet.addAll(aliases); ++ for (String aliasName : aliasArray) { ++ if (!aliasesSet.contains(aliasName)) { ++ return false; ++ } ++ } ++ return true; ++ } ++ ++ /** ++ * check if the service has a specific attribute with the correct value in the provider ++ * ++ * @param provider the provider to check ++ * @param serviceName service name ++ * @param attrName attribute name ++ * @param attrValue attribute value ++ * @return true if passed this check ++ */ ++ public static boolean checkAttribute(Provider provider, String serviceName, String attrName, String attrValue) { ++ String[] typeAndAlg = getTypeAndAlgorithm(serviceName); ++ if (typeAndAlg == null || typeAndAlg.length < 2) { ++ throw new NameMalFormatException("service name is not in a right formation"); ++ } ++ Service service = getService(provider, typeAndAlg[0], typeAndAlg[1]); ++ return checkAttribute(service, attrName, attrValue); ++ } ++ ++ private static boolean checkAttribute(Service service, String attrName, String attrValue) { ++ if (!attrValue.equals(service.getAttribute(attrName))) { ++ throw new AttributeNotFoundException(service.getType(), service.getAlgorithm(), attrName, attrValue); ++ } ++ return true; ++ } ++ ++ private static String getServiceName(String type, String algo) { ++ return type + "." + algo; ++ } ++ ++ /** ++ * seperate algorithm key with type and name ++ * ++ * @param key algorithm full name ++ * @return string array with algorithm type and name ++ */ ++ public static String[] getTypeAndAlgorithm(String key) { ++ int index = key.indexOf('.'); ++ if (index < 1) { ++ return new String[0]; ++ } ++ String type = key.substring(0, index); ++ String alg = key.substring(index + 1); ++ return new String[] {type, alg}; ++ } ++ ++ /** ++ * throws this exception if we cannot find the service in the provider ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++ public static class ServiceNotFoundException extends RuntimeException { ++ public ServiceNotFoundException(String provider, String serviceName) { ++ this("faild to find " + serviceName + " in " + provider + " provider"); ++ } ++ ++ public ServiceNotFoundException(String message) { ++ super(message); ++ } ++ } ++ ++ /** ++ * throws this exception if we cannot find the attribute in the service ++ * or the attribute value is not correct ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++ public static class AttributeNotFoundException extends RuntimeException { ++ public AttributeNotFoundException(String type, String algo, String attrName, String attrValue) { ++ this( ++ "faild " ++ + type ++ + "." ++ + algo ++ + " '" ++ + attrName ++ + "' attribute check, " ++ + "the correct value should be '" ++ + attrValue ++ + "'"); ++ } ++ ++ public AttributeNotFoundException(String message) { ++ super(message); ++ } ++ } ++ ++ /** ++ * throws this exception if we cannot find the alias name in the provider ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++ public static class AliasNotMatchedException extends RuntimeException { ++ public AliasNotMatchedException(String aliasName, String serviceName) { ++ this("faild to find alias name " + aliasName + " in " + serviceName); ++ } ++ ++ public AliasNotMatchedException(String message) { ++ super(message); ++ } ++ } ++ ++ /** ++ * throws this exception if the name is in a malformation ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++ public static class NameMalFormatException extends RuntimeException { ++ public NameMalFormatException(String message) { ++ super(message); ++ } ++ } ++} +diff --git a/jdk/test/java/security/Provider/SunJCEValidator.java b/jdk/test/java/security/Provider/SunJCEValidator.java +new file mode 100644 +index 000000000..314abb380 +--- /dev/null ++++ b/jdk/test/java/security/Provider/SunJCEValidator.java +@@ -0,0 +1,574 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++/* ++ * @test ++ * @bug 7092821 ++ * @library ../testlibrary ++ * @summary make sure that Sun providers do not miss any algorithms after ++ * modifying the frameworks underneath ++ * @author Henry Yang ++ */ ++ ++/* ++ *- @TestCaseID:Provider/SunJCEValidator.java ++ *- @TestCaseName:Provider/SunJCEValidator.java ++ *- @TestCaseType:Function test ++ *- @RequirementID:AR.SR.IREQ02758058.001.001 ++ *- @RequirementName: java.security.Provider.getService() is synchronized and became scalability bottleneck ++ *- @Condition:JDK8u302及以后 ++ *- @Brief:测试相应provider更改底层架构以后所提供的service是否与原先有差异(以openJDK8u302为准) ++ * -#step:比较openJDK8u302 SunJceProvider与此特性修改后的SunJceProvider所提供的service是否一致 ++ *- @Expect:正常运行 ++ *- @Priority:Level 1 ++ */ ++ ++import com.sun.crypto.provider.SunJCE; ++ ++import java.security.Provider; ++ ++/** ++ * validator for SunJCE provider, make sure we do not miss any algorithm ++ * after the modification. ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++public class SunJCEValidator extends BaseProviderValidator { ++ private static final String OID_PKCS12_RC4_128 = "1.2.840.113549.1.12.1.1"; ++ private static final String OID_PKCS12_RC4_40 = "1.2.840.113549.1.12.1.2"; ++ private static final String OID_PKCS12_DESede = "1.2.840.113549.1.12.1.3"; ++ private static final String OID_PKCS12_RC2_128 = "1.2.840.113549.1.12.1.5"; ++ private static final String OID_PKCS12_RC2_40 = "1.2.840.113549.1.12.1.6"; ++ private static final String OID_PKCS5_MD5_DES = "1.2.840.113549.1.5.3"; ++ private static final String OID_PKCS5_PBKDF2 = "1.2.840.113549.1.5.12"; ++ private static final String OID_PKCS5_PBES2 = "1.2.840.113549.1.5.13"; ++ private static final String OID_PKCS3 = "1.2.840.113549.1.3.1"; ++ ++ public static void main(String[] args) throws Exception { ++ SunJCEValidator validator = new SunJCEValidator(); ++ validator.validate(); ++ } ++ ++ @Override ++ Provider getDefaultProvider() { ++ return new SunJCE(); ++ } ++ ++ @Override ++ boolean validate() throws Exception { ++ final String BLOCK_MODES = ++ "ECB|CBC|PCBC|CTR|CTS|CFB|OFB" ++ + "|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64" ++ + "|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64"; ++ final String BLOCK_MODES128 = ++ BLOCK_MODES ++ + "|GCM|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128" ++ + "|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128"; ++ final String BLOCK_PADS = "NOPADDING|PKCS5PADDING|ISO10126PADDING"; ++ ++ /* ++ * Cipher engines ++ */ ++ checkService("Cipher.RSA"); ++ checkAttribute("Cipher.RSA SupportedModes", "ECB"); ++ checkAttribute( ++ "Cipher.RSA SupportedPaddings", ++ "NOPADDING|PKCS1PADDING|OAEPPADDING" ++ + "|OAEPWITHMD5ANDMGF1PADDING" ++ + "|OAEPWITHSHA1ANDMGF1PADDING" ++ + "|OAEPWITHSHA-1ANDMGF1PADDING" ++ + "|OAEPWITHSHA-224ANDMGF1PADDING" ++ + "|OAEPWITHSHA-256ANDMGF1PADDING" ++ + "|OAEPWITHSHA-384ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512/224ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512/256ANDMGF1PADDING"); ++ checkAttribute( ++ "Cipher.RSA SupportedKeyClasses", ++ "java.security.interfaces.RSAPublicKey" + "|java.security.interfaces.RSAPrivateKey"); ++ ++ checkService("Cipher.DES"); ++ checkAttribute("Cipher.DES SupportedModes", BLOCK_MODES); ++ checkAttribute("Cipher.DES SupportedPaddings", BLOCK_PADS); ++ checkAttribute("Cipher.DES SupportedKeyFormats", "RAW"); ++ ++ checkService("Cipher.DESede"); ++ checkAlias("Alg.Alias.Cipher.TripleDES", "DESede"); ++ checkAttribute("Cipher.DESede SupportedModes", BLOCK_MODES); ++ checkAttribute("Cipher.DESede SupportedPaddings", BLOCK_PADS); ++ checkAttribute("Cipher.DESede SupportedKeyFormats", "RAW"); ++ ++ checkService("Cipher.DESedeWrap"); ++ checkAttribute("Cipher.DESedeWrap SupportedModes", "CBC"); ++ checkAttribute("Cipher.DESedeWrap SupportedPaddings", "NOPADDING"); ++ checkAttribute("Cipher.DESedeWrap SupportedKeyFormats", "RAW"); ++ System.out.println("Cipher engines check passed"); ++ ++ // PBES1 ++ checkService("Cipher.PBEWithMD5AndDES"); ++ checkAlias("Alg.Alias.Cipher.OID." + OID_PKCS5_MD5_DES, "PBEWithMD5AndDES"); ++ checkAlias("Alg.Alias.Cipher." + OID_PKCS5_MD5_DES, "PBEWithMD5AndDES"); ++ ++ checkService("Cipher.PBEWithMD5AndTripleDES"); ++ ++ checkService("Cipher.PBEWithSHA1AndDESede"); ++ checkAlias("Alg.Alias.Cipher.OID." + OID_PKCS12_DESede, "PBEWithSHA1AndDESede"); ++ checkAlias("Alg.Alias.Cipher." + OID_PKCS12_DESede, "PBEWithSHA1AndDESede"); ++ ++ checkService("Cipher.PBEWithSHA1AndRC2_40"); ++ checkAlias("Alg.Alias.Cipher.OID." + OID_PKCS12_RC2_40, "PBEWithSHA1AndRC2_40"); ++ checkAlias("Alg.Alias.Cipher." + OID_PKCS12_RC2_40, "PBEWithSHA1AndRC2_40"); ++ ++ checkService("Cipher.PBEWithSHA1AndRC2_128"); ++ checkAlias("Alg.Alias.Cipher.OID." + OID_PKCS12_RC2_128, "PBEWithSHA1AndRC2_128"); ++ checkAlias("Alg.Alias.Cipher." + OID_PKCS12_RC2_128, "PBEWithSHA1AndRC2_128"); ++ ++ checkService("Cipher.PBEWithSHA1AndRC4_40"); ++ checkAlias("Alg.Alias.Cipher.OID." + OID_PKCS12_RC4_40, "PBEWithSHA1AndRC4_40"); ++ checkAlias("Alg.Alias.Cipher." + OID_PKCS12_RC4_40, "PBEWithSHA1AndRC4_40"); ++ ++ checkService("Cipher.PBEWithSHA1AndRC4_128"); ++ checkAlias("Alg.Alias.Cipher.OID." + OID_PKCS12_RC4_128, "PBEWithSHA1AndRC4_128"); ++ checkAlias("Alg.Alias.Cipher." + OID_PKCS12_RC4_128, "PBEWithSHA1AndRC4_128"); ++ System.out.println("PBES1 check passed"); ++ ++ // PBES2 ++ ++ checkService("Cipher.PBEWithHmacSHA1AndAES_128"); ++ ++ checkService("Cipher.PBEWithHmacSHA224AndAES_128"); ++ ++ checkService("Cipher.PBEWithHmacSHA256AndAES_128"); ++ ++ checkService("Cipher.PBEWithHmacSHA384AndAES_128"); ++ ++ checkService("Cipher.PBEWithHmacSHA512AndAES_128"); ++ ++ checkService("Cipher.PBEWithHmacSHA1AndAES_256"); ++ ++ checkService("Cipher.PBEWithHmacSHA224AndAES_256"); ++ ++ checkService("Cipher.PBEWithHmacSHA256AndAES_256"); ++ ++ checkService("Cipher.PBEWithHmacSHA384AndAES_256"); ++ ++ checkService("Cipher.PBEWithHmacSHA512AndAES_256"); ++ ++ checkService("Cipher.Blowfish"); ++ checkAttribute("Cipher.Blowfish SupportedModes", BLOCK_MODES); ++ checkAttribute("Cipher.Blowfish SupportedPaddings", BLOCK_PADS); ++ checkAttribute("Cipher.Blowfish SupportedKeyFormats", "RAW"); ++ ++ checkService("Cipher.AES"); ++ checkAlias("Alg.Alias.Cipher.Rijndael", "AES"); ++ checkAttribute("Cipher.AES SupportedModes", BLOCK_MODES128); ++ checkAttribute("Cipher.AES SupportedPaddings", BLOCK_PADS); ++ checkAttribute("Cipher.AES SupportedKeyFormats", "RAW"); ++ ++ checkService("Cipher.AES_128/ECB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.1", "AES_128/ECB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.1", "AES_128/ECB/NoPadding"); ++ checkService("Cipher.AES_128/CBC/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.2", "AES_128/CBC/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.2", "AES_128/CBC/NoPadding"); ++ checkService("Cipher.AES_128/OFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.3", "AES_128/OFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.3", "AES_128/OFB/NoPadding"); ++ checkService("Cipher.AES_128/CFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.4", "AES_128/CFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.4", "AES_128/CFB/NoPadding"); ++ checkService("Cipher.AES_128/GCM/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.6", "AES_128/GCM/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.6", "AES_128/GCM/NoPadding"); ++ ++ checkService("Cipher.AES_192/ECB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.21", "AES_192/ECB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.21", "AES_192/ECB/NoPadding"); ++ checkService("Cipher.AES_192/CBC/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.22", "AES_192/CBC/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.22", "AES_192/CBC/NoPadding"); ++ checkService("Cipher.AES_192/OFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.23", "AES_192/OFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.23", "AES_192/OFB/NoPadding"); ++ checkService("Cipher.AES_192/CFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.24", "AES_192/CFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.24", "AES_192/CFB/NoPadding"); ++ checkService("Cipher.AES_192/GCM/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.26", "AES_192/GCM/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.26", "AES_192/GCM/NoPadding"); ++ ++ checkService("Cipher.AES_256/ECB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.41", "AES_256/ECB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.41", "AES_256/ECB/NoPadding"); ++ checkService("Cipher.AES_256/CBC/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.42", "AES_256/CBC/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.42", "AES_256/CBC/NoPadding"); ++ checkService("Cipher.AES_256/OFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.43", "AES_256/OFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.43", "AES_256/OFB/NoPadding"); ++ checkService("Cipher.AES_256/CFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.44", "AES_256/CFB/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.44", "AES_256/CFB/NoPadding"); ++ checkService("Cipher.AES_256/GCM/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.46", "AES_256/GCM/NoPadding"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.46", "AES_256/GCM/NoPadding"); ++ ++ checkService("Cipher.AESWrap"); ++ checkAttribute("Cipher.AESWrap SupportedModes", "ECB"); ++ checkAttribute("Cipher.AESWrap SupportedPaddings", "NOPADDING"); ++ checkAttribute("Cipher.AESWrap SupportedKeyFormats", "RAW"); ++ ++ checkService("Cipher.AESWrap_128"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.5", "AESWrap_128"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.5", "AESWrap_128"); ++ checkService("Cipher.AESWrap_192"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.25", "AESWrap_192"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.25", "AESWrap_192"); ++ checkService("Cipher.AESWrap_256"); ++ checkAlias("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.45", "AESWrap_256"); ++ checkAlias("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.45", "AESWrap_256"); ++ ++ checkService("Cipher.RC2"); ++ checkAttribute("Cipher.RC2 SupportedModes", BLOCK_MODES); ++ checkAttribute("Cipher.RC2 SupportedPaddings", BLOCK_PADS); ++ checkAttribute("Cipher.RC2 SupportedKeyFormats", "RAW"); ++ ++ checkService("Cipher.ARCFOUR"); ++ checkAlias("Alg.Alias.Cipher.RC4", "ARCFOUR"); ++ checkAttribute("Cipher.ARCFOUR SupportedModes", "ECB"); ++ checkAttribute("Cipher.ARCFOUR SupportedPaddings", "NOPADDING"); ++ checkAttribute("Cipher.ARCFOUR SupportedKeyFormats", "RAW"); ++ System.out.println("PBES2 check passed"); ++ ++ /* ++ * Key(pair) Generator engines ++ */ ++ checkService("KeyGenerator.DES"); ++ ++ checkService("KeyGenerator.DESede"); ++ checkAlias("Alg.Alias.KeyGenerator.TripleDES", "DESede"); ++ ++ checkService("KeyGenerator.Blowfish"); ++ ++ checkService("KeyGenerator.AES"); ++ checkAlias("Alg.Alias.KeyGenerator.Rijndael", "AES"); ++ ++ checkService("KeyGenerator.RC2"); ++ checkService("KeyGenerator.ARCFOUR"); ++ checkAlias("Alg.Alias.KeyGenerator.RC4", "ARCFOUR"); ++ ++ checkService("KeyGenerator.HmacMD5"); ++ ++ checkService("KeyGenerator.HmacSHA1"); ++ checkAlias("Alg.Alias.KeyGenerator.OID.1.2.840.113549.2.7", "HmacSHA1"); ++ checkAlias("Alg.Alias.KeyGenerator.1.2.840.113549.2.7", "HmacSHA1"); ++ ++ checkService("KeyGenerator.HmacSHA224"); ++ checkAlias("Alg.Alias.KeyGenerator.OID.1.2.840.113549.2.8", "HmacSHA224"); ++ checkAlias("Alg.Alias.KeyGenerator.1.2.840.113549.2.8", "HmacSHA224"); ++ ++ checkService("KeyGenerator.HmacSHA256"); ++ checkAlias("Alg.Alias.KeyGenerator.OID.1.2.840.113549.2.9", "HmacSHA256"); ++ checkAlias("Alg.Alias.KeyGenerator.1.2.840.113549.2.9", "HmacSHA256"); ++ ++ checkService("KeyGenerator.HmacSHA384"); ++ checkAlias("Alg.Alias.KeyGenerator.OID.1.2.840.113549.2.10", "HmacSHA384"); ++ checkAlias("Alg.Alias.KeyGenerator.1.2.840.113549.2.10", "HmacSHA384"); ++ ++ checkService("KeyGenerator.HmacSHA512"); ++ checkAlias("Alg.Alias.KeyGenerator.OID.1.2.840.113549.2.11", "HmacSHA512"); ++ checkAlias("Alg.Alias.KeyGenerator.1.2.840.113549.2.11", "HmacSHA512"); ++ ++ checkService("KeyPairGenerator.DiffieHellman"); ++ checkAlias("Alg.Alias.KeyPairGenerator.DH", "DiffieHellman"); ++ checkAlias("Alg.Alias.KeyPairGenerator.OID." + OID_PKCS3, "DiffieHellman"); ++ checkAlias("Alg.Alias.KeyPairGenerator." + OID_PKCS3, "DiffieHellman"); ++ System.out.println("Key(pair) Generator engines check passed"); ++ ++ /* ++ * Algorithm parameter generation engines ++ */ ++ checkService("AlgorithmParameterGenerator.DiffieHellman"); ++ checkAlias("Alg.Alias.AlgorithmParameterGenerator.DH", "DiffieHellman"); ++ checkAlias("Alg.Alias.AlgorithmParameterGenerator.OID." + OID_PKCS3, "DiffieHellman"); ++ checkAlias("Alg.Alias.AlgorithmParameterGenerator." + OID_PKCS3, "DiffieHellman"); ++ System.out.println("Algorithm parameter generation engines check passed"); ++ ++ /* ++ * Key Agreement engines ++ */ ++ checkService("KeyAgreement.DiffieHellman"); ++ checkAlias("Alg.Alias.KeyAgreement.DH", "DiffieHellman"); ++ checkAlias("Alg.Alias.KeyAgreement.OID." + OID_PKCS3, "DiffieHellman"); ++ checkAlias("Alg.Alias.KeyAgreement." + OID_PKCS3, "DiffieHellman"); ++ ++ checkAttribute( ++ "KeyAgreement.DiffieHellman SupportedKeyClasses", ++ "javax.crypto.interfaces.DHPublicKey" + "|javax.crypto.interfaces.DHPrivateKey"); ++ System.out.println("Key Agreement engines check passed"); ++ ++ /* ++ * Algorithm Parameter engines ++ */ ++ checkService("AlgorithmParameters.DiffieHellman"); ++ checkAlias("Alg.Alias.AlgorithmParameters.DH", "DiffieHellman"); ++ checkAlias("Alg.Alias.AlgorithmParameters.OID." + OID_PKCS3, "DiffieHellman"); ++ checkAlias("Alg.Alias.AlgorithmParameters." + OID_PKCS3, "DiffieHellman"); ++ ++ checkService("AlgorithmParameters.DES"); ++ ++ checkService("AlgorithmParameters.DESede"); ++ checkAlias("Alg.Alias.AlgorithmParameters.TripleDES", "DESede"); ++ ++ checkService("AlgorithmParameters.PBE"); ++ ++ checkService("AlgorithmParameters.PBEWithMD5AndDES"); ++ checkAlias("Alg.Alias.AlgorithmParameters.OID." + OID_PKCS5_MD5_DES, "PBEWithMD5AndDES"); ++ checkAlias("Alg.Alias.AlgorithmParameters." + OID_PKCS5_MD5_DES, "PBEWithMD5AndDES"); ++ ++ checkService("AlgorithmParameters.PBEWithMD5AndTripleDES"); ++ ++ checkService("AlgorithmParameters.PBEWithSHA1AndDESede"); ++ checkAlias("Alg.Alias.AlgorithmParameters.OID." + OID_PKCS12_DESede, "PBEWithSHA1AndDESede"); ++ checkAlias("Alg.Alias.AlgorithmParameters." + OID_PKCS12_DESede, "PBEWithSHA1AndDESede"); ++ ++ checkService("AlgorithmParameters.PBEWithSHA1AndRC2_40"); ++ checkAlias("Alg.Alias.AlgorithmParameters.OID." + OID_PKCS12_RC2_40, "PBEWithSHA1AndRC2_40"); ++ checkAlias("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC2_40, "PBEWithSHA1AndRC2_40"); ++ ++ checkService("AlgorithmParameters.PBEWithSHA1AndRC2_128"); ++ checkAlias("Alg.Alias.AlgorithmParameters.OID." + OID_PKCS12_RC2_128, "PBEWithSHA1AndRC2_128"); ++ checkAlias("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC2_128, "PBEWithSHA1AndRC2_128"); ++ ++ checkService("AlgorithmParameters.PBEWithSHA1AndRC4_40"); ++ checkAlias("Alg.Alias.AlgorithmParameters.OID." + OID_PKCS12_RC4_40, "PBEWithSHA1AndRC4_40"); ++ checkAlias("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC4_40, "PBEWithSHA1AndRC4_40"); ++ ++ checkService("AlgorithmParameters.PBEWithSHA1AndRC4_128"); ++ checkAlias("Alg.Alias.AlgorithmParameters.OID." + OID_PKCS12_RC4_128, "PBEWithSHA1AndRC4_128"); ++ checkAlias("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC4_128, "PBEWithSHA1AndRC4_128"); ++ ++ checkService("AlgorithmParameters.PBES2"); ++ checkAlias("Alg.Alias.AlgorithmParameters.OID." + OID_PKCS5_PBES2, "PBES2"); ++ checkAlias("Alg.Alias.AlgorithmParameters." + OID_PKCS5_PBES2, "PBES2"); ++ ++ checkService("AlgorithmParameters.PBEWithHmacSHA1AndAES_128"); ++ ++ checkService("AlgorithmParameters.PBEWithHmacSHA224AndAES_128"); ++ ++ checkService("AlgorithmParameters.PBEWithHmacSHA256AndAES_128"); ++ ++ checkService("AlgorithmParameters.PBEWithHmacSHA384AndAES_128"); ++ ++ checkService("AlgorithmParameters.PBEWithHmacSHA512AndAES_128"); ++ ++ checkService("AlgorithmParameters.PBEWithHmacSHA1AndAES_256"); ++ ++ checkService("AlgorithmParameters.PBEWithHmacSHA224AndAES_256"); ++ ++ checkService("AlgorithmParameters.PBEWithHmacSHA256AndAES_256"); ++ ++ checkService("AlgorithmParameters.PBEWithHmacSHA384AndAES_256"); ++ ++ checkService("AlgorithmParameters.PBEWithHmacSHA512AndAES_256"); ++ ++ checkService("AlgorithmParameters.Blowfish"); ++ ++ checkService("AlgorithmParameters.AES"); ++ checkAlias("Alg.Alias.AlgorithmParameters.Rijndael", "AES"); ++ checkService("AlgorithmParameters.GCM"); ++ ++ checkService("AlgorithmParameters.RC2"); ++ ++ checkService("AlgorithmParameters.OAEP"); ++ System.out.println("Algorithm Parameter engines check passed"); ++ ++ /* ++ * Key factories ++ */ ++ checkService("KeyFactory.DiffieHellman"); ++ checkAlias("Alg.Alias.KeyFactory.DH", "DiffieHellman"); ++ checkAlias("Alg.Alias.KeyFactory.OID." + OID_PKCS3, "DiffieHellman"); ++ checkAlias("Alg.Alias.KeyFactory." + OID_PKCS3, "DiffieHellman"); ++ System.out.println("Key factories check passed"); ++ ++ /* ++ * Secret-key factories ++ */ ++ checkService("SecretKeyFactory.DES"); ++ ++ checkService("SecretKeyFactory.DESede"); ++ checkAlias("Alg.Alias.SecretKeyFactory.TripleDES", "DESede"); ++ ++ checkService("SecretKeyFactory.PBEWithMD5AndDES"); ++ checkAlias("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS5_MD5_DES, "PBEWithMD5AndDES"); ++ checkAlias("Alg.Alias.SecretKeyFactory." + OID_PKCS5_MD5_DES, "PBEWithMD5AndDES"); ++ ++ checkAlias("Alg.Alias.SecretKeyFactory.PBE", "PBEWithMD5AndDES"); ++ ++ /* ++ * Internal in-house crypto algorithm used for ++ * the JCEKS keystore type. Since this was developed ++ * internally, there isn't an OID corresponding to this ++ * algorithm. ++ */ ++ checkService("SecretKeyFactory.PBEWithMD5AndTripleDES"); ++ ++ checkService("SecretKeyFactory.PBEWithSHA1AndDESede"); ++ checkAlias("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_DESede, "PBEWithSHA1AndDESede"); ++ checkAlias("Alg.Alias.SecretKeyFactory." + OID_PKCS12_DESede, "PBEWithSHA1AndDESede"); ++ ++ checkService("SecretKeyFactory.PBEWithSHA1AndRC2_40"); ++ checkAlias("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC2_40, "PBEWithSHA1AndRC2_40"); ++ checkAlias("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC2_40, "PBEWithSHA1AndRC2_40"); ++ ++ checkService("SecretKeyFactory.PBEWithSHA1AndRC2_128"); ++ checkAlias("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC2_128, "PBEWithSHA1AndRC2_128"); ++ checkAlias("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC2_128, "PBEWithSHA1AndRC2_128"); ++ ++ checkService("SecretKeyFactory.PBEWithSHA1AndRC4_40"); ++ ++ checkAlias("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC4_40, "PBEWithSHA1AndRC4_40"); ++ checkAlias("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC4_40, "PBEWithSHA1AndRC4_40"); ++ ++ checkService("SecretKeyFactory.PBEWithSHA1AndRC4_128"); ++ ++ checkAlias("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC4_128, "PBEWithSHA1AndRC4_128"); ++ checkAlias("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC4_128, "PBEWithSHA1AndRC4_128"); ++ ++ checkService("SecretKeyFactory.PBEWithHmacSHA1AndAES_128"); ++ ++ checkService("SecretKeyFactory.PBEWithHmacSHA224AndAES_128"); ++ ++ checkService("SecretKeyFactory.PBEWithHmacSHA256AndAES_128"); ++ ++ checkService("SecretKeyFactory.PBEWithHmacSHA384AndAES_128"); ++ ++ checkService("SecretKeyFactory.PBEWithHmacSHA512AndAES_128"); ++ ++ checkService("SecretKeyFactory.PBEWithHmacSHA1AndAES_256"); ++ ++ checkService("SecretKeyFactory.PBEWithHmacSHA224AndAES_256"); ++ ++ checkService("SecretKeyFactory.PBEWithHmacSHA256AndAES_256"); ++ ++ checkService("SecretKeyFactory.PBEWithHmacSHA384AndAES_256"); ++ ++ checkService("SecretKeyFactory.PBEWithHmacSHA512AndAES_256"); ++ System.out.println("crypto algorithm for JCEKS keystore check passed "); ++ ++ // PBKDF2 ++ ++ checkService("SecretKeyFactory.PBKDF2WithHmacSHA1"); ++ checkAlias("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS5_PBKDF2, "PBKDF2WithHmacSHA1"); ++ checkAlias("Alg.Alias.SecretKeyFactory." + OID_PKCS5_PBKDF2, "PBKDF2WithHmacSHA1"); ++ ++ checkService("SecretKeyFactory.PBKDF2WithHmacSHA224"); ++ checkService("SecretKeyFactory.PBKDF2WithHmacSHA256"); ++ checkService("SecretKeyFactory.PBKDF2WithHmacSHA384"); ++ checkService("SecretKeyFactory.PBKDF2WithHmacSHA512"); ++ ++ System.out.println("PBKDF2 check passed"); ++ ++ /* ++ * MAC ++ */ ++ checkService("Mac.HmacMD5"); ++ checkService("Mac.HmacSHA1"); ++ checkAlias("Alg.Alias.Mac.OID.1.2.840.113549.2.7", "HmacSHA1"); ++ checkAlias("Alg.Alias.Mac.1.2.840.113549.2.7", "HmacSHA1"); ++ checkService("Mac.HmacSHA224"); ++ checkAlias("Alg.Alias.Mac.OID.1.2.840.113549.2.8", "HmacSHA224"); ++ checkAlias("Alg.Alias.Mac.1.2.840.113549.2.8", "HmacSHA224"); ++ checkService("Mac.HmacSHA256"); ++ checkAlias("Alg.Alias.Mac.OID.1.2.840.113549.2.9", "HmacSHA256"); ++ checkAlias("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA256"); ++ checkService("Mac.HmacSHA384"); ++ checkAlias("Alg.Alias.Mac.OID.1.2.840.113549.2.10", "HmacSHA384"); ++ checkAlias("Alg.Alias.Mac.1.2.840.113549.2.10", "HmacSHA384"); ++ checkService("Mac.HmacSHA512"); ++ checkAlias("Alg.Alias.Mac.OID.1.2.840.113549.2.11", "HmacSHA512"); ++ checkAlias("Alg.Alias.Mac.1.2.840.113549.2.11", "HmacSHA512"); ++ checkService("Mac.HmacPBESHA1"); ++ ++ System.out.println("MAC check passed"); ++ ++ // PBMAC1 ++ ++ checkService("Mac.PBEWithHmacSHA1"); ++ checkService("Mac.PBEWithHmacSHA224"); ++ checkService("Mac.PBEWithHmacSHA256"); ++ checkService("Mac.PBEWithHmacSHA384"); ++ checkService("Mac.PBEWithHmacSHA512"); ++ ++ checkService("Mac.SslMacMD5"); ++ checkService("Mac.SslMacSHA1"); ++ ++ checkAttribute("Mac.HmacMD5 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.HmacSHA1 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.HmacSHA224 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.HmacSHA256 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.HmacSHA384 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.HmacSHA512 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.HmacPBESHA1 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.PBEWithHmacSHA1 SupportedKeyFormatS", "RAW"); ++ checkAttribute("Mac.PBEWithHmacSHA224 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.PBEWithHmacSHA256 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.PBEWithHmacSHA384 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.PBEWithHmacSHA512 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.SslMacMD5 SupportedKeyFormats", "RAW"); ++ checkAttribute("Mac.SslMacSHA1 SupportedKeyFormats", "RAW"); ++ System.out.println("PBMAC1 check passed"); ++ ++ /* ++ * KeyStore ++ */ ++ checkService("KeyStore.JCEKS"); ++ System.out.println("KeyStore check passed"); ++ ++ /* ++ * SSL/TLS mechanisms ++ * ++ * These are strictly internal implementations and may ++ * be changed at any time. These names were chosen ++ * because PKCS11/SunPKCS11 does not yet have TLS1.2 ++ * mechanisms, and it will cause calls to come here. ++ */ ++ checkService("KeyGenerator.SunTlsPrf"); ++ checkService("KeyGenerator.SunTls12Prf"); ++ ++ checkService("KeyGenerator.SunTlsMasterSecret"); ++ checkAlias("Alg.Alias.KeyGenerator.SunTls12MasterSecret", "SunTlsMasterSecret"); ++ checkAlias("Alg.Alias.KeyGenerator.SunTlsExtendedMasterSecret", "SunTlsMasterSecret"); ++ ++ checkService("KeyGenerator.SunTlsKeyMaterial"); ++ checkAlias("Alg.Alias.KeyGenerator.SunTls12KeyMaterial", "SunTlsKeyMaterial"); ++ ++ checkService("KeyGenerator.SunTlsRsaPremasterSecret"); ++ checkAlias("Alg.Alias.KeyGenerator.SunTls12RsaPremasterSecret", "SunTlsRsaPremasterSecret"); ++ System.out.println("SSL/TLS mechanisms check passed"); ++ return true; ++ } ++} +diff --git a/jdk/test/java/security/Provider/SunJSSEValidator.java b/jdk/test/java/security/Provider/SunJSSEValidator.java +new file mode 100644 +index 000000000..5817c3b7f +--- /dev/null ++++ b/jdk/test/java/security/Provider/SunJSSEValidator.java +@@ -0,0 +1,137 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++/* ++ * @test ++ * @bug 7092821 ++ * @library ../testlibrary ++ * @summary make sure that Sun providers do not miss any algorithms after ++ * modifying the frameworks underneath ++ * @author Henry Yang ++ */ ++ ++/* ++ *- @TestCaseID:Provider/SunJSSEValidator.java ++ *- @TestCaseName:Provider/SunJSSEValidator.java ++ *- @TestCaseType:Function test ++ *- @RequirementID:AR.SR.IREQ02758058.001.001 ++ *- @RequirementName: java.security.Provider.getService() is synchronized and became scalability bottleneck ++ *- @Condition:JDK8u302及以后 ++ *- @Brief:测试相应provider更改底层架构以后所提供的service是否与原先有差异(以openJDK8u302为准) ++ * -#step:比较openJDK8u302 SunJSSEProvider与此特性修改后的SunJSSEProvider所提供的service是否一致 ++ *- @Expect:正常运行 ++ *- @Priority:Level 1 ++ */ ++ ++import java.security.Provider; ++import java.util.Locale; ++ ++/** ++ * validator for SunJSSE provider, make sure we do not miss any algorithm ++ * after the modification. ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++public class SunJSSEValidator extends BaseProviderValidator { ++ private boolean fips = false; ++ ++ public static void main(String[] args) throws Exception { ++ SunJSSEValidator validator = new SunJSSEValidator(); ++ if (args != null && args.length > 0) { ++ String fipsStr = args[0].toLowerCase(Locale.ENGLISH); ++ if (!"true".equals(fipsStr) && !"false".equals(fipsStr)) { ++ throw new RuntimeException("Fips mode argument should be a boolean value"); ++ } ++ validator.setFips(Boolean.parseBoolean(fipsStr)); ++ } ++ validator.validate(); ++ } ++ ++ public void setFips(boolean isFips) { ++ this.fips = isFips; ++ } ++ ++ @Override ++ Provider getDefaultProvider() { ++ return new com.sun.net.ssl.internal.ssl.Provider(); ++ } ++ ++ @Override ++ boolean validate() throws Exception { ++ if (fips == false) { ++ checkService("KeyFactory.RSA"); ++ checkAlias("Alg.Alias.KeyFactory.1.2.840.113549.1.1", "RSA"); ++ checkAlias("Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1", "RSA"); ++ ++ checkService("KeyPairGenerator.RSA"); ++ checkAlias("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1", "RSA"); ++ checkAlias("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1", "RSA"); ++ ++ checkService("Signature.MD2withRSA"); ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2", "MD2withRSA"); ++ ++ checkService("Signature.MD5withRSA"); ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA"); ++ ++ checkService("Signature.SHA1withRSA"); ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA"); ++ checkAlias("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.3.14.3.2.29", "SHA1withRSA"); ++ } ++ checkService("Signature.MD5andSHA1withRSA"); ++ ++ checkService("KeyManagerFactory.SunX509"); ++ checkService("KeyManagerFactory.NewSunX509"); ++ checkAlias("Alg.Alias.KeyManagerFactory.PKIX", "NewSunX509"); ++ ++ checkService("TrustManagerFactory.SunX509"); ++ checkService("TrustManagerFactory.PKIX"); ++ checkAlias("Alg.Alias.TrustManagerFactory.SunPKIX", "PKIX"); ++ checkAlias("Alg.Alias.TrustManagerFactory.X509", "PKIX"); ++ checkAlias("Alg.Alias.TrustManagerFactory.X.509", "PKIX"); ++ ++ checkService("SSLContext.TLSv1"); ++ checkService("SSLContext.TLSv1.1"); ++ checkService("SSLContext.TLSv1.2"); ++ checkService("SSLContext.TLSv1.3"); ++ checkService("SSLContext.TLS"); ++ if (fips == false) { ++ checkAlias("Alg.Alias.SSLContext.SSL", "TLS"); ++ checkAlias("Alg.Alias.SSLContext.SSLv3", "TLSv1"); ++ } ++ ++ checkService("SSLContext.Default"); ++ ++ /* ++ * KeyStore ++ */ ++ checkService("KeyStore.PKCS12"); ++ System.out.println("SunJSSE check passed"); ++ return true; ++ } ++} +diff --git a/jdk/test/java/security/Provider/SunRsaSignValidator.java b/jdk/test/java/security/Provider/SunRsaSignValidator.java +new file mode 100644 +index 000000000..66fb33a44 +--- /dev/null ++++ b/jdk/test/java/security/Provider/SunRsaSignValidator.java +@@ -0,0 +1,154 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++/* ++ * @test ++ * @bug 7092821 ++ * @library ../testlibrary ++ * @summary make sure that Sun providers do not miss any algorithms after ++ * modifying the frameworks underneath ++ * @author Henry Yang ++ */ ++ ++/* ++ *- @TestCaseID:Provider/SunRsaSignValidator.java ++ *- @TestCaseName:Provider/SunRsaSignValidator.java ++ *- @TestCaseType:Function test ++ *- @RequirementID:AR.SR.IREQ02758058.001.001 ++ *- @RequirementName: java.security.Provider.getService() is synchronized and became scalability bottleneck ++ *- @Condition:JDK8u302及以后 ++ *- @Brief:测试相应provider更改底层架构以后所提供的service是否与原先有差异(以openJDK8u302为准) ++ * -#step:比较openJDK8u302 SunRsaSignProvider与此特性修改后的SunRsaSignProvider所提供的service是否一致 ++ *- @Expect:正常运行 ++ *- @Priority:Level 1 ++ */ ++ ++import sun.security.rsa.SunRsaSign; ++ ++import java.security.Provider; ++ ++/** ++ * validator for SunRsaSign provider, make sure we do not miss any algorithm ++ * after the modification. ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++public class SunRsaSignValidator extends BaseProviderValidator { ++ public static void main(String[] args) throws Exception { ++ SunRsaSignValidator validator = new SunRsaSignValidator(); ++ validator.validate(); ++ } ++ ++ @Override ++ Provider getDefaultProvider() { ++ return new SunRsaSign(); ++ } ++ ++ @Override ++ boolean validate() throws Exception { ++ // main algorithms ++ checkService("KeyFactory.RSA"); ++ checkService("KeyPairGenerator.RSA"); ++ checkService("Signature.MD2withRSA"); ++ checkService("Signature.MD5withRSA"); ++ checkService("Signature.SHA1withRSA"); ++ checkService("Signature.SHA224withRSA"); ++ checkService("Signature.SHA256withRSA"); ++ checkService("Signature.SHA384withRSA"); ++ checkService("Signature.SHA512withRSA"); ++ checkService("Signature.SHA512/224withRSA"); ++ checkService("Signature.SHA512/256withRSA"); ++ ++ checkService("KeyFactory.RSASSA-PSS"); ++ checkService("KeyPairGenerator.RSASSA-PSS"); ++ checkService("Signature.RSASSA-PSS"); ++ checkService("AlgorithmParameters.RSASSA-PSS"); ++ ++ System.out.println("service check passed"); ++ ++ // attributes for supported key classes ++ String rsaKeyClasses = "java.security.interfaces.RSAPublicKey" + "|java.security.interfaces.RSAPrivateKey"; ++ checkAttribute("Signature.MD2withRSA SupportedKeyClasses", rsaKeyClasses); ++ checkAttribute("Signature.MD5withRSA SupportedKeyClasses", rsaKeyClasses); ++ checkAttribute("Signature.SHA1withRSA SupportedKeyClasses", rsaKeyClasses); ++ checkAttribute("Signature.SHA224withRSA SupportedKeyClasses", rsaKeyClasses); ++ checkAttribute("Signature.SHA256withRSA SupportedKeyClasses", rsaKeyClasses); ++ checkAttribute("Signature.SHA384withRSA SupportedKeyClasses", rsaKeyClasses); ++ checkAttribute("Signature.SHA512withRSA SupportedKeyClasses", rsaKeyClasses); ++ checkAttribute("Signature.SHA512/224withRSA SupportedKeyClasses", rsaKeyClasses); ++ checkAttribute("Signature.SHA512/256withRSA SupportedKeyClasses", rsaKeyClasses); ++ checkAttribute("Signature.RSASSA-PSS SupportedKeyClasses", rsaKeyClasses); ++ ++ System.out.println("attribute check passed"); ++ ++ // aliases ++ checkAlias("Alg.Alias.KeyFactory.1.2.840.113549.1.1", "RSA"); ++ checkAlias("Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1", "RSA"); ++ ++ checkAlias("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1", "RSA"); ++ checkAlias("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1", "RSA"); ++ ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2", "MD2withRSA"); ++ ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA"); ++ ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA"); ++ checkAlias("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA"); ++ ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.14", "SHA224withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.14", "SHA224withRSA"); ++ ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA"); ++ ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA"); ++ ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA"); ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.15", "SHA512/224withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.15", "SHA512/224withRSA"); ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.16", "SHA512/256withRSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.16", "SHA512/256withRSA"); ++ ++ checkAlias("Alg.Alias.KeyFactory.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ checkAlias("Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ ++ checkAlias("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ checkAlias("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ ++ checkAlias("Alg.Alias.Signature.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ ++ checkAlias("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ checkAlias("Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ ++ System.out.println("check alias passed"); ++ return true; ++ } ++} +diff --git a/jdk/test/java/security/Provider/SunValidator.java b/jdk/test/java/security/Provider/SunValidator.java +new file mode 100644 +index 000000000..3f4b81222 +--- /dev/null ++++ b/jdk/test/java/security/Provider/SunValidator.java +@@ -0,0 +1,263 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++/* ++ * @test ++ * @bug 7092821 ++ * @library ../testlibrary ++ * @summary make sure that Sun providers do not miss any algorithms after ++ * modifying the frameworks underneath ++ * @author Henry Yang ++ */ ++ ++/* ++ *- @TestCaseID:Provider/SunValidator.java ++ *- @TestCaseName:Provider/SunValidator.java ++ *- @TestCaseType:Function test ++ *- @RequirementID:AR.SR.IREQ02758058.001.001 ++ *- @RequirementName: java.security.Provider.getService() is synchronized and became scalability bottleneck ++ *- @Condition:JDK8u302及以后 ++ *- @Brief:测试相应provider更改底层架构以后所提供的service是否与原先有差异(以openJDK8u302为准) ++ * -#step:比较openJDK8u302 SunProvider与此特性修改后的SunProvider所提供的service是否一致 ++ *- @Expect:正常运行 ++ *- @Priority:Level 1 ++ */ ++ ++import sun.security.provider.NativePRNG; ++import sun.security.provider.Sun; ++ ++import java.lang.reflect.Method; ++import java.security.Provider; ++ ++/** ++ * validator for Sun provider, make sure we do not miss any algorithm ++ * after the modification. ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++public class SunValidator extends BaseProviderValidator { ++ public static void main(String[] args) throws Exception { ++ SunValidator validator = new SunValidator(); ++ validator.validate(); ++ } ++ ++ @Override ++ Provider getDefaultProvider() { ++ return new Sun(); ++ } ++ ++ @Override ++ public boolean validate() throws Exception { ++ Method nativeAvailableMethod = NativePRNG.class.getDeclaredMethod("isAvailable"); ++ nativeAvailableMethod.setAccessible(true); ++ boolean nativeAvailable = (Boolean) nativeAvailableMethod.invoke(null); ++ if (nativeAvailable) { ++ checkService("SecureRandom.NativePRNG"); ++ } ++ ++ checkService("SecureRandom.SHA1PRNG"); ++ ++ /* ++ * Signature engines ++ */ ++ checkService("Signature.SHA1withDSA"); ++ checkService("Signature.NONEwithDSA"); ++ checkAlias("Alg.Alias.Signature.RawDSA", "NONEwithDSA"); ++ checkService("Signature.SHA224withDSA"); ++ checkService("Signature.SHA256withDSA"); ++ ++ String dsaKeyClasses = "java.security.interfaces.DSAPublicKey" + "|java.security.interfaces.DSAPrivateKey"; ++ checkAttribute("Signature.SHA1withDSA SupportedKeyClasses", dsaKeyClasses); ++ checkAttribute("Signature.NONEwithDSA SupportedKeyClasses", dsaKeyClasses); ++ checkAttribute("Signature.SHA224withDSA SupportedKeyClasses", dsaKeyClasses); ++ checkAttribute("Signature.SHA256withDSA SupportedKeyClasses", dsaKeyClasses); ++ ++ checkAlias("Alg.Alias.Signature.DSA", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.DSS", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.SHA-1/DSA", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.SHA1/DSA", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.SHAwithDSA", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.OID.1.2.840.10040.4.3", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.1.3.14.3.2.13", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.1.3.14.3.2.27", "SHA1withDSA"); ++ checkAlias("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.1", "SHA224withDSA"); ++ checkAlias("Alg.Alias.Signature.2.16.840.1.101.3.4.3.1", "SHA224withDSA"); ++ checkAlias("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.2", "SHA256withDSA"); ++ checkAlias("Alg.Alias.Signature.2.16.840.1.101.3.4.3.2", "SHA256withDSA"); ++ System.out.println("Signature engines check passed"); ++ ++ /* ++ * Key Pair Generator engines ++ */ ++ checkService("KeyPairGenerator.DSA"); ++ checkAlias("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA"); ++ checkAlias("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA"); ++ checkAlias("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA"); ++ System.out.println("Key Pair Generator engines check passed"); ++ ++ /* ++ * Digest engines ++ */ ++ checkService("MessageDigest.MD2"); ++ checkService("MessageDigest.MD5"); ++ checkService("MessageDigest.SHA"); ++ ++ checkAlias("Alg.Alias.MessageDigest.SHA-1", "SHA"); ++ checkAlias("Alg.Alias.MessageDigest.SHA1", "SHA"); ++ checkAlias("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA"); ++ checkAlias("Alg.Alias.MessageDigest.OID.1.3.14.3.2.26", "SHA"); ++ ++ checkService("MessageDigest.SHA-224"); ++ checkAlias("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.4", "SHA-224"); ++ checkAlias("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.4", "SHA-224"); ++ ++ checkService("MessageDigest.SHA-256"); ++ checkAlias("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256"); ++ checkAlias("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.1", "SHA-256"); ++ checkService("MessageDigest.SHA-384"); ++ checkAlias("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384"); ++ checkAlias("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.2", "SHA-384"); ++ checkService("MessageDigest.SHA-512"); ++ checkAlias("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512"); ++ checkAlias("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3", "SHA-512"); ++ checkService("MessageDigest.SHA-512/224"); ++ checkAlias("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.5", "SHA-512/224"); ++ checkAlias("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.5", "SHA-512/224"); ++ checkService("MessageDigest.SHA-512/256"); ++ checkAlias("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.6", "SHA-512/256"); ++ checkAlias("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.6", "SHA-512/256"); ++ System.out.println("Digest engines check passed"); ++ ++ /* ++ * Algorithm Parameter Generator engines ++ */ ++ checkService("AlgorithmParameterGenerator.DSA"); ++ System.out.println("Algorithm Parameter Generator engines check passed"); ++ ++ /* ++ * Algorithm Parameter engines ++ */ ++ checkService("AlgorithmParameters.DSA"); ++ checkAlias("Alg.Alias.AlgorithmParameters.OID.1.2.840.10040.4.1", "DSA"); ++ checkAlias("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.1", "DSA"); ++ checkAlias("Alg.Alias.AlgorithmParameters.1.3.14.3.2.12", "DSA"); ++ System.out.println("Algorithm Parameter engines check passed"); ++ ++ /* ++ * Key factories ++ */ ++ checkService("KeyFactory.DSA"); ++ checkAlias("Alg.Alias.KeyFactory.OID.1.2.840.10040.4.1", "DSA"); ++ checkAlias("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA"); ++ checkAlias("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSA"); ++ System.out.println("Key factories check passed"); ++ ++ /* ++ * Certificates ++ */ ++ checkService("CertificateFactory.X.509"); ++ checkAlias("Alg.Alias.CertificateFactory.X509", "X.509"); ++ System.out.println("Certificates check passed"); ++ ++ /* ++ * KeyStore ++ */ ++ checkService("KeyStore.JKS"); ++ checkService("KeyStore.CaseExactJKS"); ++ checkService("KeyStore.DKS"); ++ System.out.println("KeyStore check passed"); ++ ++ /* ++ * Policy ++ */ ++ checkService("Policy.JavaPolicy"); ++ System.out.println("Policy check passed"); ++ ++ /* ++ * Configuration ++ */ ++ checkService("Configuration.JavaLoginConfig"); ++ System.out.println("Configuration check passed"); ++ ++ /* ++ * CertPathBuilder ++ */ ++ checkService("CertPathBuilder.PKIX"); ++ checkAttribute("CertPathBuilder.PKIX ValidationAlgorithm", "RFC5280"); ++ System.out.println("CertPathBuilder check passed"); ++ ++ /* ++ * CertPathValidator ++ */ ++ checkService("CertPathValidator.PKIX"); ++ checkAttribute("CertPathValidator.PKIX ValidationAlgorithm", "RFC5280"); ++ System.out.println("CertPathValidator check passed"); ++ ++ /* ++ * CertStores ++ */ ++ checkService("CertStore.LDAP"); ++ checkAttribute("CertStore.LDAP LDAPSchema", "RFC2587"); ++ checkService("CertStore.Collection"); ++ checkService("CertStore.com.sun.security.IndexedCollection"); ++ System.out.println("CertStores check passed"); ++ ++ /* ++ * KeySize ++ */ ++ checkAttribute("Signature.NONEwithDSA KeySize", "1024"); ++ checkAttribute("Signature.SHA1withDSA KeySize", "1024"); ++ checkAttribute("Signature.SHA224withDSA KeySize", "2048"); ++ checkAttribute("Signature.SHA256withDSA KeySize", "2048"); ++ ++ checkAttribute("KeyPairGenerator.DSA KeySize", "2048"); ++ checkAttribute("AlgorithmParameterGenerator.DSA KeySize", "2048"); ++ System.out.println("KeySize attribute check passed"); ++ ++ /* ++ * Implementation type: software or hardware ++ */ ++ checkAttribute("Signature.SHA1withDSA ImplementedIn", "Software"); ++ checkAttribute("KeyPairGenerator.DSA ImplementedIn", "Software"); ++ checkAttribute("MessageDigest.MD5 ImplementedIn", "Software"); ++ checkAttribute("MessageDigest.SHA ImplementedIn", "Software"); ++ checkAttribute("AlgorithmParameterGenerator.DSA ImplementedIn", "Software"); ++ checkAttribute("AlgorithmParameters.DSA ImplementedIn", "Software"); ++ checkAttribute("KeyFactory.DSA ImplementedIn", "Software"); ++ checkAttribute("SecureRandom.SHA1PRNG ImplementedIn", "Software"); ++ checkAttribute("CertificateFactory.X.509 ImplementedIn", "Software"); ++ checkAttribute("KeyStore.JKS ImplementedIn", "Software"); ++ checkAttribute("CertPathValidator.PKIX ImplementedIn", "Software"); ++ checkAttribute("CertPathBuilder.PKIX ImplementedIn", "Software"); ++ checkAttribute("CertStore.LDAP ImplementedIn", "Software"); ++ checkAttribute("CertStore.Collection ImplementedIn", "Software"); ++ checkAttribute("CertStore.com.sun.security.IndexedCollection ImplementedIn", "Software"); ++ System.out.println("Implementation type attribute check passed"); ++ return true; ++ } ++} +diff --git a/jdk/test/java/security/SecureRandom/DefaultAlgo.java b/jdk/test/java/security/SecureRandom/DefaultAlgo.java +new file mode 100644 +index 000000000..ce786f7a2 +--- /dev/null ++++ b/jdk/test/java/security/SecureRandom/DefaultAlgo.java +@@ -0,0 +1,117 @@ ++/* ++ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import static java.lang.System.out; ++import java.security.Provider; ++import java.security.Security; ++import java.security.SecureRandom; ++import java.security.Provider.Service; ++import java.util.Objects; ++import java.util.Arrays; ++import sun.security.provider.SunEntries; ++ ++/** ++ * @test ++ * @bug 8228613 ++ * @summary Ensure that the default SecureRandom algo used is based ++ * on the registration ordering, and falls to next provider ++ * if none are found ++ * @modules java.base/sun.security.provider ++ */ ++public class DefaultAlgo { ++ ++ public static void main(String[] args) throws Exception { ++ String[] algos = { "A", "B", "C" }; ++ test3rdParty(algos); ++ // reverse the order and re-check ++ String[] algosReversed = { "C", "B", "A" }; ++ test3rdParty(algosReversed); ++ } ++ ++ private static void test3rdParty(String[] algos) { ++ Provider[] provs = { ++ new SampleLegacyProvider(algos), ++ new SampleServiceProvider(algos) ++ }; ++ for (Provider p : provs) { ++ checkDefault(p, algos); ++ } ++ } ++ ++ // validate the specified SecureRandom obj to be from the specified ++ // provider and matches the specified algorithm ++ private static void validate(SecureRandom sr, String pName, String algo) { ++ if (!sr.getProvider().getName().equals(pName)) { ++ throw new RuntimeException("Failed provider check, exp: " + ++ pName + ", got " + sr.getProvider().getName()); ++ } ++ if (!sr.getAlgorithm().equals(algo)) { ++ throw new RuntimeException("Failed algo check, exp: " + ++ algo + ", got " + sr.getAlgorithm()); ++ } ++ } ++ ++ private static void checkDefault(Provider p, String ... algos) { ++ out.println(p.getName() + " with " + Arrays.toString(algos)); ++ int pos = Security.insertProviderAt(p, 1); ++ String pName = p.getName(); ++ boolean isLegacy = pName.equals("SampleLegacy"); ++ try { ++ if (isLegacy) { ++ for (String s : algos) { ++ validate(new SecureRandom(), pName, s); ++ p.remove("SecureRandom." + s); ++ out.println("removed " + s); ++ } ++ validate(new SecureRandom(), "SUN", ++ SunEntries.DEF_SECURE_RANDOM_ALGO); ++ } else { ++ validate(new SecureRandom(), pName, algos[0]); ++ } ++ out.println("=> Test Passed"); ++ } finally { ++ if (pos != -1) { ++ Security.removeProvider(p.getName()); ++ } ++ } ++ } ++ ++ private static class SampleLegacyProvider extends Provider { ++ SampleLegacyProvider(String[] listOfSupportedRNGs) { ++ super("SampleLegacy", 1.0, "test provider using legacy put"); ++ for (String s : listOfSupportedRNGs) { ++ put("SecureRandom." + s, "sun.security.provider.SecureRandom"); ++ } ++ } ++ } ++ ++ private static class SampleServiceProvider extends Provider { ++ SampleServiceProvider(String[] listOfSupportedRNGs) { ++ super("SampleService", 1.0, "test provider using putService"); ++ for (String s : listOfSupportedRNGs) { ++ putService(new Provider.Service(this, "SecureRandom", s, ++ "sun.security.provider.SecureRandom", null, null)); ++ } ++ } ++ } ++} +\ No newline at end of file +diff --git a/jdk/test/micro/org/openeuler/bench/security/provider/GetServiceBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/provider/GetServiceBenchmark.java +new file mode 100644 +index 000000000..93cd887d6 +--- /dev/null ++++ b/jdk/test/micro/org/openeuler/bench/security/provider/GetServiceBenchmark.java +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional ++ * information or have any questions. ++ */ ++ ++/* ++ * - @TestCaseID:provider/GetServiceBenchmark.java ++ * - @TestCaseName:provider/GetServiceBenchmark.java ++ * - @TestCaseType:Performance test ++ * - @RequirementID:AR.SR.IREQ02758058.001.001 ++ * - @RequirementName:java.security.Provider.getService() is synchronized and became scalability bottleneck ++ * - @Condition:JDK8u302及以后 ++ * - @Brief:测试provider.getService的性能 ++ * -#step:创建jmh的maven项目mvn archetype:generate -DinteractiveMode=false -DarchetypeGroupId=org.openjdk.jmh -DarchetypeArtifactId=jmh-java-benchmark-archetype -DgroupId=org.openeuler.bench.security.provider -DartifactId=provider-benchmark -Dversion=1.0 ++ * -#step2:删除项目中的多余文件rm -rf provider-benchmark/src/main/java/org/openeuler/bench/security/provider/MyBenchmark.java ++ * -#step3:将本文件拷贝进项目目录cp GetServiceBenchmark.java provider-benchmark/src/main/java/org/openeuler/bench/security/provider/ ++ * -#step4:构建项目mvn install ++ * -#step5:运行测试java -jar target/benchmarks.jar GetServiceBenchmark ++ * - @Expect:正常运行 ++ * - @Priority:Level 1 ++ */ ++ ++package org.openeuler.bench.security.provider; ++ ++import com.sun.crypto.provider.SunJCE; ++ ++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.Scope; ++import org.openjdk.jmh.annotations.State; ++import org.openjdk.jmh.annotations.Threads; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import java.security.Provider; ++import java.util.concurrent.TimeUnit; ++ ++/** ++ * Benchmark to test the performance of provider.getService in ++ * high concurrency scenarios. ++ * ++ * @author Henry Yang ++ * @since 2022-05-05 ++ */ ++@BenchmarkMode(Mode.Throughput) ++@Fork(1) ++@Threads(2000) ++@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS) ++@Measurement(iterations = 5, time = 3, timeUnit = TimeUnit.SECONDS) ++@State(Scope.Benchmark) ++public class GetServiceBenchmark { ++ private Provider provider = new SunJCE(); ++ ++ @Benchmark ++ public void getService() { ++ try { ++ provider.getService("Cipher", "RSA"); ++ } catch (Exception e) { ++ e.printStackTrace(); ++ } ++ } ++} +-- +2.22.0 + diff --git a/8065895-Synchronous-signals-during-error-reporting-may-terminate-or-hang-vm-process.patch b/8065895-Synchronous-signals-during-error-reporting-may-terminate-or-hang-vm-process.patch new file mode 100644 index 0000000000000000000000000000000000000000..2e5bc2595a55796498e848c8f53be00871148ae3 --- /dev/null +++ b/8065895-Synchronous-signals-during-error-reporting-may-terminate-or-hang-vm-process.patch @@ -0,0 +1,485 @@ +From 69371858fda3c1793faf8bbf116ec4fe554605ac Mon Sep 17 00:00:00 2001 +From: hedongbo +Date: Fri, 21 Oct 2022 15:16:04 +0800 +Subject: 8065895: Synchronous signals during error reporting may + terminate or hang VM process + +Bug url: https://bugs.openjdk.java.net/browse/JDK-8065895 +--- + hotspot/src/os/aix/vm/vmError_aix.cpp | 11 +++-- + hotspot/src/os/bsd/vm/vmError_bsd.cpp | 47 +++++++++++------- + hotspot/src/os/linux/vm/vmError_linux.cpp | 48 ++++++++++++------- + hotspot/src/os/solaris/vm/vmError_solaris.cpp | 48 ++++++++++++------- + hotspot/src/share/vm/runtime/globals.hpp | 4 ++ + hotspot/src/share/vm/utilities/debug.cpp | 48 ++++++++++++++++--- + hotspot/src/share/vm/utilities/debug.hpp | 18 +++++++ + hotspot/src/share/vm/utilities/vmError.cpp | 29 +++++++++++ + 8 files changed, 196 insertions(+), 57 deletions(-) + +diff --git a/hotspot/src/os/aix/vm/vmError_aix.cpp b/hotspot/src/os/aix/vm/vmError_aix.cpp +index d99436ebc..34709134a 100644 +--- a/hotspot/src/os/aix/vm/vmError_aix.cpp ++++ b/hotspot/src/os/aix/vm/vmError_aix.cpp +@@ -80,7 +80,6 @@ static void save_signal(int idx, int sig) { + } + + int VMError::get_resetted_sigflags(int sig) { +- // Handle all program errors. + for (int i = 0; i < NUM_SIGNALS; i++) { + if (SIGNALS[i] == sig) { + return resettedSigflags[i]; +@@ -90,7 +89,6 @@ int VMError::get_resetted_sigflags(int sig) { + } + + address VMError::get_resetted_sighandler(int sig) { +- // Handle all program errors. + for (int i = 0; i < NUM_SIGNALS; i++) { + if (SIGNALS[i] == sig) { + return resettedSighandler[i]; +@@ -100,12 +98,19 @@ address VMError::get_resetted_sighandler(int sig) { + } + + static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { ++ + // Unmask current signal. + sigset_t newset; + sigemptyset(&newset); + sigaddset(&newset, sig); ++ // and all other synchronous signals too. ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ sigaddset(&newset, SIGNALS[i]); ++ } ++ sigthreadmask(SIG_UNBLOCK, &newset, NULL); + +- Unimplemented(); ++ VMError err(NULL, sig, NULL, info, ucVoid); ++ err.report_and_die(); + } + + void VMError::reset_signal_handlers() { +diff --git a/hotspot/src/os/bsd/vm/vmError_bsd.cpp b/hotspot/src/os/bsd/vm/vmError_bsd.cpp +index 8ec6ca04c..f09e1163f 100644 +--- a/hotspot/src/os/bsd/vm/vmError_bsd.cpp ++++ b/hotspot/src/os/bsd/vm/vmError_bsd.cpp +@@ -63,9 +63,15 @@ void VMError::show_message_box(char *buf, int buflen) { + } while (yes); + } + ++// handle all synchronous program error signals which may happen during error ++// reporting. They must be unblocked, caught, handled. ++ ++static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed ++static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int); ++ + // Space for our "saved" signal flags and handlers +-static int resettedSigflags[2]; +-static address resettedSighandler[2]; ++static int resettedSigflags[NUM_SIGNALS]; ++static address resettedSighandler[NUM_SIGNALS]; + + static void save_signal(int idx, int sig) + { +@@ -78,19 +84,19 @@ static void save_signal(int idx, int sig) + } + + int VMError::get_resetted_sigflags(int sig) { +- if(SIGSEGV == sig) { +- return resettedSigflags[0]; +- } else if(SIGBUS == sig) { +- return resettedSigflags[1]; ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ if (SIGNALS[i] == sig) { ++ return resettedSigflags[i]; ++ } + } + return -1; + } + + address VMError::get_resetted_sighandler(int sig) { +- if(SIGSEGV == sig) { +- return resettedSighandler[0]; +- } else if(SIGBUS == sig) { +- return resettedSighandler[1]; ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ if (SIGNALS[i] == sig) { ++ return resettedSighandler[i]; ++ } + } + return NULL; + } +@@ -100,16 +106,25 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { + sigset_t newset; + sigemptyset(&newset); + sigaddset(&newset, sig); +- sigprocmask(SIG_UNBLOCK, &newset, NULL); ++ // also unmask other synchronous signals ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ sigaddset(&newset, SIGNALS[i]); ++ } ++ pthread_sigmask(SIG_UNBLOCK, &newset, NULL); + + VMError err(NULL, sig, NULL, info, ucVoid); + err.report_and_die(); + } + + void VMError::reset_signal_handlers() { +- // Save sigflags for resetted signals +- save_signal(0, SIGSEGV); +- save_signal(1, SIGBUS); +- os::signal(SIGSEGV, CAST_FROM_FN_PTR(void *, crash_handler)); +- os::signal(SIGBUS, CAST_FROM_FN_PTR(void *, crash_handler)); ++ // install signal handlers for all synchronous program error signals ++ sigset_t newset; ++ sigemptyset(&newset); ++ ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ save_signal(i, SIGNALS[i]); ++ os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); ++ sigaddset(&newset, SIGNALS[i]); ++ } ++ pthread_sigmask(SIG_UNBLOCK, &newset, NULL); + } +diff --git a/hotspot/src/os/linux/vm/vmError_linux.cpp b/hotspot/src/os/linux/vm/vmError_linux.cpp +index 378c9a6ab..fca239c7e 100644 +--- a/hotspot/src/os/linux/vm/vmError_linux.cpp ++++ b/hotspot/src/os/linux/vm/vmError_linux.cpp +@@ -63,9 +63,15 @@ void VMError::show_message_box(char *buf, int buflen) { + } while (yes); + } + ++// handle all synchronous program error signals which may happen during error ++// reporting. They must be unblocked, caught, handled. ++ ++static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed ++static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int); ++ + // Space for our "saved" signal flags and handlers +-static int resettedSigflags[2]; +-static address resettedSighandler[2]; ++static int resettedSigflags[NUM_SIGNALS]; ++static address resettedSighandler[NUM_SIGNALS]; + + static void save_signal(int idx, int sig) + { +@@ -78,19 +84,19 @@ static void save_signal(int idx, int sig) + } + + int VMError::get_resetted_sigflags(int sig) { +- if(SIGSEGV == sig) { +- return resettedSigflags[0]; +- } else if(SIGBUS == sig) { +- return resettedSigflags[1]; ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ if (SIGNALS[i] == sig) { ++ return resettedSigflags[i]; ++ } + } + return -1; + } + + address VMError::get_resetted_sighandler(int sig) { +- if(SIGSEGV == sig) { +- return resettedSighandler[0]; +- } else if(SIGBUS == sig) { +- return resettedSighandler[1]; ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ if (SIGNALS[i] == sig) { ++ return resettedSighandler[i]; ++ } + } + return NULL; + } +@@ -100,16 +106,26 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { + sigset_t newset; + sigemptyset(&newset); + sigaddset(&newset, sig); +- sigprocmask(SIG_UNBLOCK, &newset, NULL); ++ // also unmask other synchronous signals ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ sigaddset(&newset, SIGNALS[i]); ++ } ++ pthread_sigmask(SIG_UNBLOCK, &newset, NULL); + + VMError err(NULL, sig, NULL, info, ucVoid); + err.report_and_die(); + } + + void VMError::reset_signal_handlers() { +- // Save sigflags for resetted signals +- save_signal(0, SIGSEGV); +- save_signal(1, SIGBUS); +- os::signal(SIGSEGV, CAST_FROM_FN_PTR(void *, crash_handler)); +- os::signal(SIGBUS, CAST_FROM_FN_PTR(void *, crash_handler)); ++ // install signal handlers for all synchronous program error signals ++ sigset_t newset; ++ sigemptyset(&newset); ++ ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ save_signal(i, SIGNALS[i]); ++ os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); ++ sigaddset(&newset, SIGNALS[i]); ++ } ++ pthread_sigmask(SIG_UNBLOCK, &newset, NULL); ++ + } +diff --git a/hotspot/src/os/solaris/vm/vmError_solaris.cpp b/hotspot/src/os/solaris/vm/vmError_solaris.cpp +index 6f3f5b06f..e24e5f6bf 100644 +--- a/hotspot/src/os/solaris/vm/vmError_solaris.cpp ++++ b/hotspot/src/os/solaris/vm/vmError_solaris.cpp +@@ -30,6 +30,7 @@ + + #include + #include ++#include + #include + + void VMError::show_message_box(char *buf, int buflen) { +@@ -59,9 +60,15 @@ void VMError::show_message_box(char *buf, int buflen) { + } while (yes); + } + ++// handle all synchronous program error signals which may happen during error ++// reporting. They must be unblocked, caught, handled. ++ ++static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed ++static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int); ++ + // Space for our "saved" signal flags and handlers +-static int resettedSigflags[2]; +-static address resettedSighandler[2]; ++static int resettedSigflags[NUM_SIGNALS]; ++static address resettedSighandler[NUM_SIGNALS]; + + static void save_signal(int idx, int sig) + { +@@ -74,19 +81,19 @@ static void save_signal(int idx, int sig) + } + + int VMError::get_resetted_sigflags(int sig) { +- if(SIGSEGV == sig) { +- return resettedSigflags[0]; +- } else if(SIGBUS == sig) { +- return resettedSigflags[1]; ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ if (SIGNALS[i] == sig) { ++ return resettedSigflags[i]; ++ } + } + return -1; + } + + address VMError::get_resetted_sighandler(int sig) { +- if(SIGSEGV == sig) { +- return resettedSighandler[0]; +- } else if(SIGBUS == sig) { +- return resettedSighandler[1]; ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ if (SIGNALS[i] == sig) { ++ return resettedSighandler[i]; ++ } + } + return NULL; + } +@@ -96,16 +103,25 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { + sigset_t newset; + sigemptyset(&newset); + sigaddset(&newset, sig); +- sigprocmask(SIG_UNBLOCK, &newset, NULL); ++ // also unmask other synchronous signals ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ sigaddset(&newset, SIGNALS[i]); ++ } ++ thr_sigsetmask(SIG_UNBLOCK, &newset, NULL); + + VMError err(NULL, sig, NULL, info, ucVoid); + err.report_and_die(); + } + + void VMError::reset_signal_handlers() { +- // Save sigflags for resetted signals +- save_signal(0, SIGSEGV); +- save_signal(1, SIGBUS); +- os::signal(SIGSEGV, CAST_FROM_FN_PTR(void *, crash_handler)); +- os::signal(SIGBUS, CAST_FROM_FN_PTR(void *, crash_handler)); ++ // install signal handlers for all synchronous program error signals ++ sigset_t newset; ++ sigemptyset(&newset); ++ ++ for (int i = 0; i < NUM_SIGNALS; i++) { ++ save_signal(i, SIGNALS[i]); ++ os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); ++ sigaddset(&newset, SIGNALS[i]); ++ } ++ thr_sigsetmask(SIG_UNBLOCK, &newset, NULL); + } +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index eb13ee0d7..0dab18e1a 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -916,6 +916,10 @@ class CommandLineFlags { + "determines which error to provoke. See test_error_handler() " \ + "in debug.cpp.") \ + \ ++ notproduct(uintx, TestCrashInErrorHandler, 0, \ ++ "If > 0, provokes an error inside VM error handler (a secondary " \ ++ "crash). see test_error_handler() in debug.cpp.") \ ++ \ + develop(bool, Verbose, false, \ + "Print additional debugging information from other modes") \ + \ +diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp +index 58a32a2b8..8cea16d32 100644 +--- a/hotspot/src/share/vm/utilities/debug.cpp ++++ b/hotspot/src/share/vm/utilities/debug.cpp +@@ -337,13 +337,47 @@ bool is_error_reported() { + #ifndef PRODUCT + #include + ++typedef void (*voidfun_t)(); ++// Crash with an authentic sigfpe ++static void crash_with_sigfpe() { ++ // generate a native synchronous SIGFPE where possible; ++ // if that did not cause a signal (e.g. on ppc), just ++ // raise the signal. ++ volatile int x = 0; ++ volatile int y = 1/x; ++#ifndef _WIN32 ++ raise(SIGFPE); ++#endif ++} // end: crash_with_sigfpe ++ ++// crash with sigsegv at non-null address. ++static void crash_with_segfault() { ++ ++ char* const crash_addr = (char*) get_segfault_address(); ++ *crash_addr = 'X'; ++ ++} // end: crash_with_segfault ++ ++// returns an address which is guaranteed to generate a SIGSEGV on read, ++// for test purposes, which is not NULL and contains bits in every word ++void* get_segfault_address() { ++ return (void*) ++#ifdef _LP64 ++ 0xABC0000000000ABCULL; ++#else ++ 0x00000ABC; ++#endif ++} ++ + void test_error_handler() { +- uintx test_num = ErrorHandlerTest; +- if (test_num == 0) return; ++ controlled_crash(ErrorHandlerTest); ++} ++ ++void controlled_crash(int how) { ++ if (how == 0) return; + + // If asserts are disabled, use the corresponding guarantee instead. +- size_t n = test_num; +- NOT_DEBUG(if (n <= 2) n += 2); ++ NOT_DEBUG(if (how <= 2) how += 2); + + const char* const str = "hello"; + const size_t num = (size_t)os::vm_page_size(); +@@ -354,7 +388,7 @@ void test_error_handler() { + const void (*funcPtr)(void) = (const void(*)()) 0xF; // bad function pointer + + // Keep this in sync with test/runtime/6888954/vmerrors.sh. +- switch (n) { ++ switch (how) { + case 1: assert(str == NULL, "expected null"); + case 2: assert(num == 1023 && *str == 'X', + err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); +@@ -379,8 +413,10 @@ void test_error_handler() { + // There's no guarantee the bad function pointer will crash us + // so "break" out to the ShouldNotReachHere(). + case 13: (*funcPtr)(); break; ++ case 14: crash_with_segfault(); break; ++ case 15: crash_with_sigfpe(); break; + +- default: tty->print_cr("ERROR: %d: unexpected test_num value.", n); ++ default: tty->print_cr("ERROR: %d: unexpected test_num value.", how); + } + ShouldNotReachHere(); + } +diff --git a/hotspot/src/share/vm/utilities/debug.hpp b/hotspot/src/share/vm/utilities/debug.hpp +index 3c3f8afe2..7a5e1523b 100644 +--- a/hotspot/src/share/vm/utilities/debug.hpp ++++ b/hotspot/src/share/vm/utilities/debug.hpp +@@ -266,6 +266,24 @@ void set_error_reported(); + /* Test assert(), fatal(), guarantee(), etc. */ + NOT_PRODUCT(void test_error_handler();) + ++// crash in a controlled way: ++// how can be one of: ++// 1,2 - asserts ++// 3,4 - guarantee ++// 5-7 - fatal ++// 8 - vm_exit_out_of_memory ++// 9 - ShouldNotCallThis ++// 10 - ShouldNotReachHere ++// 11 - Unimplemented ++// 12,13 - (not guaranteed) crashes ++// 14 - SIGSEGV ++// 15 - SIGFPE ++NOT_PRODUCT(void controlled_crash(int how);) ++ ++// returns an address which is guaranteed to generate a SIGSEGV on read, ++// for test purposes, which is not NULL and contains bits in every word ++NOT_PRODUCT(void* get_segfault_address();) ++ + void pd_ps(frame f); + void pd_obfuscate_location(char *buf, size_t buflen); + +diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp +index aa0b63a80..9b40a3468 100644 +--- a/hotspot/src/share/vm/utilities/vmError.cpp ++++ b/hotspot/src/share/vm/utilities/vmError.cpp +@@ -397,6 +397,26 @@ void VMError::report(outputStream* st) { + "Runtime Environment to continue."); + } + ++#ifndef PRODUCT ++ // Error handler self tests ++ ++ // test secondary error handling. Test it twice, to test that resetting ++ // error handler after a secondary crash works. ++ STEP(13, "(test secondary crash 1)") ++ if (_verbose && TestCrashInErrorHandler != 0) { ++ st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", ++ TestCrashInErrorHandler); ++ controlled_crash(TestCrashInErrorHandler); ++ } ++ ++ STEP(14, "(test secondary crash 2)") ++ if (_verbose && TestCrashInErrorHandler != 0) { ++ st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", ++ TestCrashInErrorHandler); ++ controlled_crash(TestCrashInErrorHandler); ++ } ++#endif // PRODUCT ++ + STEP(15, "(printing type of error)") + + switch(static_cast(_id)) { +@@ -829,6 +849,15 @@ void VMError::report(outputStream* st) { + st->cr(); + } + ++#ifndef PRODUCT ++ // print a defined marker to show that error handling finished correctly. ++ STEP(290, "(printing end marker)" ) ++ ++ if (_verbose) { ++ st->print_cr("END."); ++ } ++#endif ++ + END + + # undef BEGIN +-- +2.22.0 + diff --git a/8067941-TESTBUG-Fix-tests-for-OS-with-64K-page-size.patch b/8067941-TESTBUG-Fix-tests-for-OS-with-64K-page-size.patch new file mode 100644 index 0000000000000000000000000000000000000000..3f428476463513b57725151b82347dda7ed036e3 --- /dev/null +++ b/8067941-TESTBUG-Fix-tests-for-OS-with-64K-page-size.patch @@ -0,0 +1,170 @@ +From c97998519552b7d8287125e46a3db2f29293784f Mon Sep 17 00:00:00 2001 +From: xiezhaokun +Date: Wed, 8 Jun 2022 10:32:52 +0800 +Subject: [PATCH 08/10] 8067941: [TESTBUG] Fix tests for OS with 64K page size + +--- + hotspot/src/share/vm/memory/metaspace.cpp | 8 +++++--- + hotspot/test/compiler/6865265/StackOverflowBug.java | 2 +- + hotspot/test/compiler/8009761/Test8009761.java | 2 +- + .../exceptions/TestRecursiveReplacedException.java | 2 +- + .../compiler/uncommontrap/StackOverflowGuardPagesOff.java | 2 +- + .../compiler/uncommontrap/TestStackBangMonitorOwned.java | 2 +- + hotspot/test/compiler/uncommontrap/TestStackBangRbp.java | 2 +- + hotspot/test/gc/arguments/TestMaxHeapSizeTools.java | 2 +- + hotspot/test/gc/g1/TestHumongousAllocInitialMark.java | 4 +++- + 9 files changed, 15 insertions(+), 11 deletions(-) + +diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp +index 600bcfd1..2912f41b 100644 +--- a/hotspot/src/share/vm/memory/metaspace.cpp ++++ b/hotspot/src/share/vm/memory/metaspace.cpp +@@ -3937,11 +3937,13 @@ class TestVirtualSpaceNodeTest { + assert(cm.sum_free_chunks() == 2*MediumChunk, "sizes should add up"); + } + +- { // 4 pages of VSN is committed, some is used by chunks ++ const size_t page_chunks = 4 * (size_t)os::vm_page_size() / BytesPerWord; ++ // This doesn't work for systems with vm_page_size >= 16K. ++ if (page_chunks < MediumChunk) { ++ // 4 pages of VSN is committed, some is used by chunks + ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); + VirtualSpaceNode vsn(vsn_test_size_bytes); +- const size_t page_chunks = 4 * (size_t)os::vm_page_size() / BytesPerWord; +- assert(page_chunks < MediumChunk, "Test expects medium chunks to be at least 4*page_size"); ++ + vsn.initialize(); + vsn.expand_by(page_chunks, page_chunks); + vsn.get_chunk_vs(SmallChunk); +diff --git a/hotspot/test/compiler/6865265/StackOverflowBug.java b/hotspot/test/compiler/6865265/StackOverflowBug.java +index 295a6b41..c5d0f3b6 100644 +--- a/hotspot/test/compiler/6865265/StackOverflowBug.java ++++ b/hotspot/test/compiler/6865265/StackOverflowBug.java +@@ -28,7 +28,7 @@ + * @summary JVM crashes with "missing exception handler" error + * @author volker.simonis@sap.com + * +- * @run main/othervm -XX:CompileThreshold=100 -Xbatch -Xss248k StackOverflowBug ++ * @run main/othervm -XX:CompileThreshold=100 -Xbatch -Xss512k StackOverflowBug + */ + + +diff --git a/hotspot/test/compiler/8009761/Test8009761.java b/hotspot/test/compiler/8009761/Test8009761.java +index 401458b6..b41f49fd 100644 +--- a/hotspot/test/compiler/8009761/Test8009761.java ++++ b/hotspot/test/compiler/8009761/Test8009761.java +@@ -25,7 +25,7 @@ + * @test + * @bug 8009761 + * @summary Deoptimization on sparc doesn't set Llast_SP correctly in the interpreter frames it creates +- * @run main/othervm -XX:CompileCommand=exclude,Test8009761::m2 -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -Xss256K Test8009761 ++ * @run main/othervm -XX:CompileCommand=exclude,Test8009761::m2 -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -Xss512K Test8009761 + * + */ + +diff --git a/hotspot/test/compiler/exceptions/TestRecursiveReplacedException.java b/hotspot/test/compiler/exceptions/TestRecursiveReplacedException.java +index 996d82a0..950ed18c 100644 +--- a/hotspot/test/compiler/exceptions/TestRecursiveReplacedException.java ++++ b/hotspot/test/compiler/exceptions/TestRecursiveReplacedException.java +@@ -25,7 +25,7 @@ + * @test + * @bug 8054224 + * @summary Recursive method compiled by C1 is unable to catch StackOverflowError +- * @run main/othervm -Xcomp -XX:CompileOnly=Test.run -XX:+TieredCompilation -XX:TieredStopAtLevel=2 -Xss256K TestRecursiveReplacedException ++ * @run main/othervm -Xcomp -XX:CompileOnly=Test.run -XX:+TieredCompilation -XX:TieredStopAtLevel=2 -Xss512K TestRecursiveReplacedException + * + */ + +diff --git a/hotspot/test/compiler/uncommontrap/StackOverflowGuardPagesOff.java b/hotspot/test/compiler/uncommontrap/StackOverflowGuardPagesOff.java +index 4ad409bb..835283c0 100644 +--- a/hotspot/test/compiler/uncommontrap/StackOverflowGuardPagesOff.java ++++ b/hotspot/test/compiler/uncommontrap/StackOverflowGuardPagesOff.java +@@ -25,7 +25,7 @@ + * @test + * @bug 8029383 + * @summary stack overflow if callee is marked for deoptimization causes crash +- * @run main/othervm -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,StackOverflowGuardPagesOff::m1 -XX:CompileCommand=exclude,StackOverflowGuardPagesOff::m2 -Xss256K -XX:-UseOnStackReplacement StackOverflowGuardPagesOff ++ * @run main/othervm -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,StackOverflowGuardPagesOff::m1 -XX:CompileCommand=exclude,StackOverflowGuardPagesOff::m2 -Xss512K -XX:-UseOnStackReplacement StackOverflowGuardPagesOff + * + */ + +diff --git a/hotspot/test/compiler/uncommontrap/TestStackBangMonitorOwned.java b/hotspot/test/compiler/uncommontrap/TestStackBangMonitorOwned.java +index 3d93d7d5..c07a995d 100644 +--- a/hotspot/test/compiler/uncommontrap/TestStackBangMonitorOwned.java ++++ b/hotspot/test/compiler/uncommontrap/TestStackBangMonitorOwned.java +@@ -25,7 +25,7 @@ + * @test + * @bug 8032410 + * @summary Stack overflow at deoptimization doesn't release owned monitors +- * @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestStackBangMonitorOwned::m1 -XX:CompileCommand=exclude,TestStackBangMonitorOwned::m2 -Xss256K -XX:-UseOnStackReplacement TestStackBangMonitorOwned ++ * @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestStackBangMonitorOwned::m1 -XX:CompileCommand=exclude,TestStackBangMonitorOwned::m2 -Xss512K -XX:-UseOnStackReplacement TestStackBangMonitorOwned + * + */ + public class TestStackBangMonitorOwned { +diff --git a/hotspot/test/compiler/uncommontrap/TestStackBangRbp.java b/hotspot/test/compiler/uncommontrap/TestStackBangRbp.java +index 38d4e206..9b96951a 100644 +--- a/hotspot/test/compiler/uncommontrap/TestStackBangRbp.java ++++ b/hotspot/test/compiler/uncommontrap/TestStackBangRbp.java +@@ -25,7 +25,7 @@ + * @test + * @bug 8028308 + * @summary rbp not restored when stack overflow is thrown from deopt/uncommon trap blobs +- * @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestStackBangRbp::m1 -XX:CompileCommand=exclude,TestStackBangRbp::m2 -Xss256K -XX:-UseOnStackReplacement TestStackBangRbp ++ * @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestStackBangRbp::m1 -XX:CompileCommand=exclude,TestStackBangRbp::m2 -Xss512K -XX:-UseOnStackReplacement TestStackBangRbp + * + */ + public class TestStackBangRbp { +diff --git a/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java b/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java +index b5859b5c..99ed508d 100644 +--- a/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java ++++ b/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java +@@ -112,7 +112,7 @@ class TestMaxHeapSizeTools { + } + + private static void checkInvalidMinInitialHeapCombinations(String gcflag) throws Exception { +- expectError(new String[] { gcflag, "-Xms8M", "-XX:InitialHeapSize=4M", "-version" }); ++ expectError(new String[] { gcflag, "-Xms64M", "-XX:InitialHeapSize=32M", "-version" }); + } + + private static void checkValidMinInitialHeapCombinations(String gcflag) throws Exception { +diff --git a/hotspot/test/gc/g1/TestHumongousAllocInitialMark.java b/hotspot/test/gc/g1/TestHumongousAllocInitialMark.java +index 473ce666..b6e5c3d6 100644 +--- a/hotspot/test/gc/g1/TestHumongousAllocInitialMark.java ++++ b/hotspot/test/gc/g1/TestHumongousAllocInitialMark.java +@@ -31,7 +31,9 @@ + import com.oracle.java.testlibrary.*; + + public class TestHumongousAllocInitialMark { +- private static final int heapSize = 200; // MB ++ // Heap sizes < 224 MB are increased to 224 MB if vm_page_size == 64K to ++ // fulfill alignment constraints. ++ private static final int heapSize = 224; // MB + private static final int heapRegionSize = 1; // MB + private static final int initiatingHeapOccupancyPercent = 50; // % + +diff --git a/hotspot/test/runtime/6929067/invoke.c b/hotspot/test/runtime/6929067/invoke.c +index 8dde2cd6..cf8014be 100644 +--- a/hotspot/test/runtime/6929067/invoke.c ++++ b/hotspot/test/runtime/6929067/invoke.c +@@ -68,7 +68,7 @@ floobydust (void *p) + int + main (int argc, const char** argv) + { +- options[0].optionString = "-Xss320k"; ++ options[0].optionString = "-Xss512k"; + + vm_args.version = JNI_VERSION_1_2; + vm_args.ignoreUnrecognized = JNI_TRUE; +diff --git a/hotspot/test/runtime/InitialThreadOverflow/invoke.cxx b/hotspot/test/runtime/InitialThreadOverflow/invoke.cxx +index 55213c0f..2bca88f1 100644 +--- a/hotspot/test/runtime/InitialThreadOverflow/invoke.cxx ++++ b/hotspot/test/runtime/InitialThreadOverflow/invoke.cxx +@@ -48,7 +48,7 @@ floobydust (void *p) { + int + main (int argc, const char** argv) { + JavaVMOption options[1]; +- options[0].optionString = (char*) "-Xss320k"; ++ options[0].optionString = (char*) "-Xss512k"; + + JavaVMInitArgs vm_args; + vm_args.version = JNI_VERSION_1_2; diff --git a/8143925-enhancing-CounterMode.crypt-for-AESCrypt.patch b/8143925-enhancing-CounterMode.crypt-for-AESCrypt.patch new file mode 100644 index 0000000000000000000000000000000000000000..81acb5c4ec2e49c9990e1cf2ed85d1ecad7211ac --- /dev/null +++ b/8143925-enhancing-CounterMode.crypt-for-AESCrypt.patch @@ -0,0 +1,3938 @@ +From 02b097417275acaad294d71a852c2def2222be25 Mon Sep 17 00:00:00 2001 +From: kuenking111 +Date: Sat, 3 Sep 2022 14:17:50 +0000 +Subject: [PATCH 1/6] 8143925-enhancing-CounterMode.crypt-for-AESCrypt + +--- + .../src/cpu/aarch64/vm/assembler_aarch64.hpp | 35 +- + .../cpu/aarch64/vm/macroAssembler_aarch64.hpp | 17 + + .../aarch64/vm/macroAssembler_aarch64_aes.cpp | 685 ++++++++++++++++++ + .../cpu/aarch64/vm/stubGenerator_aarch64.cpp | 324 ++++++++- + .../cpu/aarch64/vm/stubRoutines_aarch64.hpp | 2 +- + .../src/cpu/aarch64/vm/vm_version_aarch64.cpp | 13 +- + hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp | 5 + + hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp | 5 + + hotspot/src/cpu/x86/vm/assembler_x86.cpp | 74 +- + hotspot/src/cpu/x86/vm/assembler_x86.hpp | 12 + + .../src/cpu/x86/vm/stubGenerator_x86_32.cpp | 344 +++++++++ + .../src/cpu/x86/vm/stubGenerator_x86_64.cpp | 340 ++++++++- + hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp | 1 + + hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp | 5 + + .../src/cpu/x86/vm/stubRoutines_x86_32.hpp | 2 +- + .../src/cpu/x86/vm/stubRoutines_x86_64.hpp | 2 +- + hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 36 + + hotspot/src/share/vm/classfile/vmSymbols.hpp | 4 + + hotspot/src/share/vm/opto/escape.cpp | 1 + + hotspot/src/share/vm/opto/library_call.cpp | 174 +++++ + hotspot/src/share/vm/opto/runtime.cpp | 29 + + hotspot/src/share/vm/opto/runtime.hpp | 1 + + hotspot/src/share/vm/runtime/globals.hpp | 3 + + hotspot/src/share/vm/runtime/stubRoutines.cpp | 1 + + hotspot/src/share/vm/runtime/stubRoutines.hpp | 2 + + hotspot/src/share/vm/runtime/vmStructs.cpp | 1 + + .../test/compiler/7184394/TestAESBase.java | 4 +- + .../test/compiler/7184394/TestAESMain.java | 7 + + .../com/sun/crypto/provider/CounterMode.java | 11 +- + .../classes/com/sun/crypto/provider/GCTR.java | 89 +-- + .../com/sun/crypto/provider/GHASH.java | 20 +- + .../sun/security/ssl/SSLSocketImpl.java | 14 +- + .../security/ssl/SSLSocketInputRecord.java | 215 +++--- + .../sun/security/ssl/SSLTransport.java | 4 + + .../bench/javax/crypto/full/AESGCMBench.java | 128 ++++ + .../javax/crypto/full/AESGCMByteBuffer.java | 163 +++++ + .../bench/javax/crypto/full/CryptoBase.java | 102 +++ + .../bench/javax/crypto/small/AESGCMBench.java | 36 + + .../javax/crypto/small/AESGCMByteBuffer.java | 36 + + .../ssl/SSLSocketImpl/ClientTimeout.java | 3 +- + .../SSLSocketImpl/SSLExceptionForIOIssue.java | 4 +- + 41 files changed, 2738 insertions(+), 216 deletions(-) + create mode 100644 hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64_aes.cpp + create mode 100644 jdk/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMBench.java + create mode 100644 jdk/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMByteBuffer.java + create mode 100644 jdk/test/micro/org/openjdk/bench/javax/crypto/full/CryptoBase.java + create mode 100644 jdk/test/micro/org/openjdk/bench/javax/crypto/small/AESGCMBench.java + create mode 100644 jdk/test/micro/org/openjdk/bench/javax/crypto/small/AESGCMByteBuffer.java + +diff --git a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp +index b0fa9b5fc..9202e61f8 100644 +--- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp ++++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp +@@ -146,6 +146,21 @@ REGISTER_DECLARATION(Register, esp, r20); + + #define assert_cond(ARG1) assert(ARG1, #ARG1) + ++// In many places we've added C-style casts to silence compiler ++// warnings, for example when truncating a size_t to an int when we ++// know the size_t is a small struct. Such casts are risky because ++// they effectively disable useful compiler warnings. We can make our ++// lives safer with this function, which ensures that any cast is ++// reversible without loss of information. It doesn't check ++// everything: it isn't intended to make sure that pointer types are ++// compatible, for example. ++template ++T2 checked_cast(T1 thing) { ++ T2 result = static_cast(thing); ++ assert(static_cast(result) == thing, "must be"); ++ return result; ++} ++ + namespace asm_util { + uint32_t encode_logical_immediate(bool is32, uint64_t imm); + }; +@@ -193,7 +208,7 @@ public: + static inline uint32_t extract(uint32_t val, int msb, int lsb) { + int nbits = msb - lsb + 1; + assert_cond(msb >= lsb); +- uint32_t mask = (1U << nbits) - 1; ++ uint32_t mask = checked_cast(right_n_bits(nbits)); + uint32_t result = val >> lsb; + result &= mask; + return result; +@@ -208,7 +223,7 @@ public: + int nbits = msb - lsb + 1; + guarantee(val < (1U << nbits), "Field too big for insn"); + assert_cond(msb >= lsb); +- unsigned mask = (1U << nbits) - 1; ++ unsigned mask = checked_cast(right_n_bits(nbits)); + val <<= lsb; + mask <<= lsb; + unsigned target = *(unsigned *)a; +@@ -222,7 +237,7 @@ public: + long chk = val >> (nbits - 1); + guarantee (chk == -1 || chk == 0, "Field too big for insn"); + unsigned uval = val; +- unsigned mask = (1U << nbits) - 1; ++ unsigned mask = checked_cast(right_n_bits(nbits)); + uval &= mask; + uval <<= lsb; + mask <<= lsb; +@@ -234,9 +249,9 @@ public: + + void f(unsigned val, int msb, int lsb) { + int nbits = msb - lsb + 1; +- guarantee(val < (1U << nbits), "Field too big for insn"); ++ guarantee(val < (1ULL << nbits), "Field too big for insn"); + assert_cond(msb >= lsb); +- unsigned mask = (1U << nbits) - 1; ++ unsigned mask = checked_cast(right_n_bits(nbits)); + val <<= lsb; + mask <<= lsb; + insn |= val; +@@ -255,7 +270,7 @@ public: + long chk = val >> (nbits - 1); + guarantee (chk == -1 || chk == 0, "Field too big for insn"); + unsigned uval = val; +- unsigned mask = (1U << nbits) - 1; ++ unsigned mask = checked_cast(right_n_bits(nbits)); + uval &= mask; + f(uval, lsb + nbits - 1, lsb); + } +@@ -280,7 +295,7 @@ public: + + unsigned get(int msb = 31, int lsb = 0) { + int nbits = msb - lsb + 1; +- unsigned mask = ((1U << nbits) - 1) << lsb; ++ unsigned mask = checked_cast(right_n_bits(nbits)) << lsb; + assert_cond((bits & mask) == mask); + return (insn & mask) >> lsb; + } +@@ -1991,21 +2006,21 @@ public: + starti; + f(0,31), f((int)T & 1, 30); + f(op1, 29, 21), f(0, 20, 16), f(op2, 15, 12); +- f((int)T >> 1, 11, 10), rf(Xn, 5), rf(Vt, 0); ++ f((int)T >> 1, 11, 10), srf(Xn, 5), rf(Vt, 0); + } + void ld_st(FloatRegister Vt, SIMD_Arrangement T, Register Xn, + int imm, int op1, int op2) { + starti; + f(0,31), f((int)T & 1, 30); + f(op1 | 0b100, 29, 21), f(0b11111, 20, 16), f(op2, 15, 12); +- f((int)T >> 1, 11, 10), rf(Xn, 5), rf(Vt, 0); ++ f((int)T >> 1, 11, 10), srf(Xn, 5), rf(Vt, 0); + } + void ld_st(FloatRegister Vt, SIMD_Arrangement T, Register Xn, + Register Xm, int op1, int op2) { + starti; + f(0,31), f((int)T & 1, 30); + f(op1 | 0b100, 29, 21), rf(Xm, 16), f(op2, 15, 12); +- f((int)T >> 1, 11, 10), rf(Xn, 5), rf(Vt, 0); ++ f((int)T >> 1, 11, 10), srf(Xn, 5), rf(Vt, 0); + } + + void ld_st(FloatRegister Vt, SIMD_Arrangement T, Address a, int op1, int op2) { +diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +index 0ca694038..d334f1b69 100644 +--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp ++++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +@@ -1240,6 +1240,23 @@ public: + void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, + Register zlen, Register tmp1, Register tmp2, Register tmp3, + Register tmp4, Register tmp5, Register tmp6, Register tmp7); ++ void ghash_multiply(FloatRegister result_lo, FloatRegister result_hi, ++ FloatRegister a, FloatRegister b, FloatRegister a1_xor_a0, ++ FloatRegister tmp1, FloatRegister tmp2, FloatRegister tmp3); ++ void ghash_reduce(FloatRegister result, FloatRegister lo, FloatRegister hi, ++ FloatRegister p, FloatRegister z, FloatRegister t1); ++ void ghash_processBlocks_wide(address p, Register state, Register subkeyH, ++ Register data, Register blocks, int unrolls); ++ void ghash_modmul (FloatRegister result, ++ FloatRegister result_lo, FloatRegister result_hi, FloatRegister b, ++ FloatRegister a, FloatRegister vzr, FloatRegister a1_xor_a0, FloatRegister p, ++ FloatRegister t1, FloatRegister t2, FloatRegister t3); ++ ++ void aesenc_loadkeys(Register key, Register keylen); ++ void aesecb_encrypt(Register from, Register to, Register keylen, ++ FloatRegister data = v0, int unrolls = 1); ++ void aesecb_decrypt(Register from, Register to, Register key, Register keylen); ++ void aes_round(FloatRegister input, FloatRegister subkey); + // ISB may be needed because of a safepoint + void maybe_isb() { isb(); } + +diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64_aes.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64_aes.cpp +new file mode 100644 +index 000000000..1db79c97a +--- /dev/null ++++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64_aes.cpp +@@ -0,0 +1,685 @@ ++/* ++ * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please 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 "macroAssembler_aarch64.hpp" ++#include "memory/resourceArea.hpp" ++#include "runtime/stubRoutines.hpp" ++ ++void MacroAssembler::aesecb_decrypt(Register from, Register to, Register key, Register keylen) { ++ Label L_doLast; ++ ++ ld1(v0, T16B, from); // get 16 bytes of input ++ ++ ld1(v5, T16B, post(key, 16)); ++ rev32(v5, T16B, v5); ++ ++ ld1(v1, v2, v3, v4, T16B, post(key, 64)); ++ rev32(v1, T16B, v1); ++ rev32(v2, T16B, v2); ++ rev32(v3, T16B, v3); ++ rev32(v4, T16B, v4); ++ aesd(v0, v1); ++ aesimc(v0, v0); ++ aesd(v0, v2); ++ aesimc(v0, v0); ++ aesd(v0, v3); ++ aesimc(v0, v0); ++ aesd(v0, v4); ++ aesimc(v0, v0); ++ ++ ld1(v1, v2, v3, v4, T16B, post(key, 64)); ++ rev32(v1, T16B, v1); ++ rev32(v2, T16B, v2); ++ rev32(v3, T16B, v3); ++ rev32(v4, T16B, v4); ++ aesd(v0, v1); ++ aesimc(v0, v0); ++ aesd(v0, v2); ++ aesimc(v0, v0); ++ aesd(v0, v3); ++ aesimc(v0, v0); ++ aesd(v0, v4); ++ aesimc(v0, v0); ++ ++ ld1(v1, v2, T16B, post(key, 32)); ++ rev32(v1, T16B, v1); ++ rev32(v2, T16B, v2); ++ ++ cmpw(keylen, 44); ++ br(Assembler::EQ, L_doLast); ++ ++ aesd(v0, v1); ++ aesimc(v0, v0); ++ aesd(v0, v2); ++ aesimc(v0, v0); ++ ++ ld1(v1, v2, T16B, post(key, 32)); ++ rev32(v1, T16B, v1); ++ rev32(v2, T16B, v2); ++ ++ cmpw(keylen, 52); ++ br(Assembler::EQ, L_doLast); ++ ++ aesd(v0, v1); ++ aesimc(v0, v0); ++ aesd(v0, v2); ++ aesimc(v0, v0); ++ ++ ld1(v1, v2, T16B, post(key, 32)); ++ rev32(v1, T16B, v1); ++ rev32(v2, T16B, v2); ++ ++ bind(L_doLast); ++ ++ aesd(v0, v1); ++ aesimc(v0, v0); ++ aesd(v0, v2); ++ ++ eor(v0, T16B, v0, v5); ++ ++ st1(v0, T16B, to); ++ ++ // Preserve the address of the start of the key ++ sub(key, key, keylen, LSL, exact_log2(sizeof (jint))); ++} ++ ++// Load expanded key into v17..v31 ++void MacroAssembler::aesenc_loadkeys(Register key, Register keylen) { ++ Label L_loadkeys_44, L_loadkeys_52; ++ cmpw(keylen, 52); ++ br(Assembler::LO, L_loadkeys_44); ++ br(Assembler::EQ, L_loadkeys_52); ++ ++ ld1(v17, v18, T16B, post(key, 32)); ++ rev32(v17, T16B, v17); ++ rev32(v18, T16B, v18); ++ bind(L_loadkeys_52); ++ ld1(v19, v20, T16B, post(key, 32)); ++ rev32(v19, T16B, v19); ++ rev32(v20, T16B, v20); ++ bind(L_loadkeys_44); ++ ld1(v21, v22, v23, v24, T16B, post(key, 64)); ++ rev32(v21, T16B, v21); ++ rev32(v22, T16B, v22); ++ rev32(v23, T16B, v23); ++ rev32(v24, T16B, v24); ++ ld1(v25, v26, v27, v28, T16B, post(key, 64)); ++ rev32(v25, T16B, v25); ++ rev32(v26, T16B, v26); ++ rev32(v27, T16B, v27); ++ rev32(v28, T16B, v28); ++ ld1(v29, v30, v31, T16B, post(key, 48)); ++ rev32(v29, T16B, v29); ++ rev32(v30, T16B, v30); ++ rev32(v31, T16B, v31); ++ ++ // Preserve the address of the start of the key ++ sub(key, key, keylen, LSL, exact_log2(sizeof (jint))); ++} ++ ++// NeoverseTM N1Software Optimization Guide: ++// Adjacent AESE/AESMC instruction pairs and adjacent AESD/AESIMC ++// instruction pairs will exhibit the performance characteristics ++// described in Section 4.6. ++void MacroAssembler::aes_round(FloatRegister input, FloatRegister subkey) { ++ aese(input, subkey); aesmc(input, input); ++} ++ ++// KernelGenerator ++// ++// The abstract base class of an unrolled function generator. ++// Subclasses override generate(), length(), and next() to generate ++// unrolled and interleaved functions. ++// ++// The core idea is that a subclass defines a method which generates ++// the base case of a function and a method to generate a clone of it, ++// shifted to a different set of registers. KernelGenerator will then ++// generate several interleaved copies of the function, with each one ++// using a different set of registers. ++ ++// The subclass must implement three methods: length(), which is the ++// number of instruction bundles in the intrinsic, generate(int n) ++// which emits the nth instruction bundle in the intrinsic, and next() ++// which takes an instance of the generator and returns a version of it, ++// shifted to a new set of registers. ++ ++class KernelGenerator: public MacroAssembler { ++protected: ++ const int _unrolls; ++public: ++ KernelGenerator(Assembler *as, int unrolls) ++ : MacroAssembler(as->code()), _unrolls(unrolls) { } ++ virtual void generate(int index) = 0; ++ virtual int length() = 0; ++ virtual KernelGenerator *next() = 0; ++ int unrolls() { return _unrolls; } ++ void unroll(); ++}; ++ ++void KernelGenerator::unroll() { ++ ResourceMark rm; ++ KernelGenerator **generators ++ = NEW_RESOURCE_ARRAY(KernelGenerator *, unrolls()); ++ ++ generators[0] = this; ++ for (int i = 1; i < unrolls(); i++) { ++ generators[i] = generators[i-1]->next(); ++ } ++ ++ for (int j = 0; j < length(); j++) { ++ for (int i = 0; i < unrolls(); i++) { ++ generators[i]->generate(j); ++ } ++ } ++} ++ ++// An unrolled and interleaved generator for AES encryption. ++class AESKernelGenerator: public KernelGenerator { ++ Register _from, _to; ++ const Register _keylen; ++ FloatRegister _data; ++ const FloatRegister _subkeys; ++ bool _once; ++ Label _rounds_44, _rounds_52; ++ ++public: ++ AESKernelGenerator(Assembler *as, int unrolls, ++ Register from, Register to, Register keylen, FloatRegister data, ++ FloatRegister subkeys, bool once = true) ++ : KernelGenerator(as, unrolls), ++ _from(from), _to(to), _keylen(keylen), _data(data), ++ _subkeys(subkeys), _once(once) { ++ } ++ ++ virtual void generate(int index) { ++ switch (index) { ++ case 0: ++ if (_from != noreg) { ++ ld1(_data, T16B, _from); // get 16 bytes of input ++ } ++ break; ++ case 1: ++ if (_once) { ++ cmpw(_keylen, 52); ++ br(Assembler::LO, _rounds_44); ++ br(Assembler::EQ, _rounds_52); ++ } ++ break; ++ case 2: aes_round(_data, _subkeys + 0); break; ++ case 3: aes_round(_data, _subkeys + 1); break; ++ case 4: ++ if (_once) bind(_rounds_52); ++ break; ++ case 5: aes_round(_data, _subkeys + 2); break; ++ case 6: aes_round(_data, _subkeys + 3); break; ++ case 7: ++ if (_once) bind(_rounds_44); ++ break; ++ case 8: aes_round(_data, _subkeys + 4); break; ++ case 9: aes_round(_data, _subkeys + 5); break; ++ case 10: aes_round(_data, _subkeys + 6); break; ++ case 11: aes_round(_data, _subkeys + 7); break; ++ case 12: aes_round(_data, _subkeys + 8); break; ++ case 13: aes_round(_data, _subkeys + 9); break; ++ case 14: aes_round(_data, _subkeys + 10); break; ++ case 15: aes_round(_data, _subkeys + 11); break; ++ case 16: aes_round(_data, _subkeys + 12); break; ++ case 17: aese(_data, _subkeys + 13); break; ++ case 18: eor(_data, T16B, _data, _subkeys + 14); break; ++ case 19: ++ if (_to != noreg) { ++ st1(_data, T16B, _to); ++ } ++ break; ++ default: ShouldNotReachHere(); ++ } ++ } ++ ++ virtual KernelGenerator *next() { ++ return new AESKernelGenerator(this, _unrolls, ++ _from, _to, _keylen, ++ _data + 1, _subkeys, /*once*/false); ++ } ++ ++ virtual int length() { return 20; } ++}; ++ ++// Uses expanded key in v17..v31 ++// Returns encrypted values in inputs. ++// If to != noreg, store value at to; likewise from ++// Preserves key, keylen ++// Increments from, to ++// Input data in v0, v1, ... ++// unrolls controls the number of times to unroll the generated function ++void MacroAssembler::aesecb_encrypt(Register from, Register to, Register keylen, ++ FloatRegister data, int unrolls) { ++ AESKernelGenerator(this, unrolls, from, to, keylen, data, v17) .unroll(); ++} ++ ++// ghash_multiply and ghash_reduce are the non-unrolled versions of ++// the GHASH function generators. ++void MacroAssembler::ghash_multiply(FloatRegister result_lo, FloatRegister result_hi, ++ FloatRegister a, FloatRegister b, FloatRegister a1_xor_a0, ++ FloatRegister tmp1, FloatRegister tmp2, FloatRegister tmp3) { ++ // Karatsuba multiplication performs a 128*128 -> 256-bit ++ // multiplication in three 128-bit multiplications and a few ++ // additions. ++ // ++ // (C1:C0) = A1*B1, (D1:D0) = A0*B0, (E1:E0) = (A0+A1)(B0+B1) ++ // (A1:A0)(B1:B0) = C1:(C0+C1+D1+E1):(D1+C0+D0+E0):D0 ++ // ++ // Inputs: ++ // ++ // A0 in a.d[0] (subkey) ++ // A1 in a.d[1] ++ // (A1+A0) in a1_xor_a0.d[0] ++ // ++ // B0 in b.d[0] (state) ++ // B1 in b.d[1] ++ ++ ext(tmp1, T16B, b, b, 0x08); ++ pmull2(result_hi, T1Q, b, a, T2D); // A1*B1 ++ eor(tmp1, T16B, tmp1, b); // (B1+B0) ++ pmull(result_lo, T1Q, b, a, T1D); // A0*B0 ++ pmull(tmp2, T1Q, tmp1, a1_xor_a0, T1D); // (A1+A0)(B1+B0) ++ ++ ext(tmp1, T16B, result_lo, result_hi, 0x08); ++ eor(tmp3, T16B, result_hi, result_lo); // A1*B1+A0*B0 ++ eor(tmp2, T16B, tmp2, tmp1); ++ eor(tmp2, T16B, tmp2, tmp3); ++ ++ // Register pair holds the result of carry-less multiplication ++ ins(result_hi, D, tmp2, 0, 1); ++ ins(result_lo, D, tmp2, 1, 0); ++} ++ ++void MacroAssembler::ghash_reduce(FloatRegister result, FloatRegister lo, FloatRegister hi, ++ FloatRegister p, FloatRegister vzr, FloatRegister t1) { ++ const FloatRegister t0 = result; ++ ++ // The GCM field polynomial f is z^128 + p(z), where p = ++ // z^7+z^2+z+1. ++ // ++ // z^128 === -p(z) (mod (z^128 + p(z))) ++ // ++ // so, given that the product we're reducing is ++ // a == lo + hi * z^128 ++ // substituting, ++ // === lo - hi * p(z) (mod (z^128 + p(z))) ++ // ++ // we reduce by multiplying hi by p(z) and subtracting the result ++ // from (i.e. XORing it with) lo. Because p has no nonzero high ++ // bits we can do this with two 64-bit multiplications, lo*p and ++ // hi*p. ++ ++ pmull2(t0, T1Q, hi, p, T2D); ++ ext(t1, T16B, t0, vzr, 8); ++ eor(hi, T16B, hi, t1); ++ ext(t1, T16B, vzr, t0, 8); ++ eor(lo, T16B, lo, t1); ++ pmull(t0, T1Q, hi, p, T1D); ++ eor(result, T16B, lo, t0); ++} ++ ++class GHASHMultiplyGenerator: public KernelGenerator { ++ FloatRegister _result_lo, _result_hi, _b, ++ _a, _vzr, _a1_xor_a0, _p, ++ _tmp1, _tmp2, _tmp3; ++ ++public: ++ GHASHMultiplyGenerator(Assembler *as, int unrolls, ++ FloatRegister result_lo, FloatRegister result_hi, ++ /* offsetted registers */ ++ FloatRegister b, ++ /* non-offsetted (shared) registers */ ++ FloatRegister a, FloatRegister a1_xor_a0, FloatRegister p, FloatRegister vzr, ++ /* offseted (temp) registers */ ++ FloatRegister tmp1, FloatRegister tmp2, FloatRegister tmp3) ++ : KernelGenerator(as, unrolls), ++ _result_lo(result_lo), _result_hi(result_hi), _b(b), ++ _a(a), _vzr(vzr), _a1_xor_a0(a1_xor_a0), _p(p), ++ _tmp1(tmp1), _tmp2(tmp2), _tmp3(tmp3) { } ++ ++ static const int register_stride = 7; ++ ++ virtual void generate(int index) { ++ // Karatsuba multiplication performs a 128*128 -> 256-bit ++ // multiplication in three 128-bit multiplications and a few ++ // additions. ++ // ++ // (C1:C0) = A1*B1, (D1:D0) = A0*B0, (E1:E0) = (A0+A1)(B0+B1) ++ // (A1:A0)(B1:B0) = C1:(C0+C1+D1+E1):(D1+C0+D0+E0):D0 ++ // ++ // Inputs: ++ // ++ // A0 in a.d[0] (subkey) ++ // A1 in a.d[1] ++ // (A1+A0) in a1_xor_a0.d[0] ++ // ++ // B0 in b.d[0] (state) ++ // B1 in b.d[1] ++ ++ switch (index) { ++ case 0: ext(_tmp1, T16B, _b, _b, 0x08); break; ++ case 1: pmull2(_result_hi, T1Q, _b, _a, T2D); // A1*B1 ++ break; ++ case 2: eor(_tmp1, T16B, _tmp1, _b); // (B1+B0) ++ break; ++ case 3: pmull(_result_lo, T1Q, _b, _a, T1D); // A0*B0 ++ break; ++ case 4: pmull(_tmp2, T1Q, _tmp1, _a1_xor_a0, T1D); // (A1+A0)(B1+B0) ++ break; ++ ++ case 5: ext(_tmp1, T16B, _result_lo, _result_hi, 0x08); break; ++ case 6: eor(_tmp3, T16B, _result_hi, _result_lo); // A1*B1+A0*B0 ++ break; ++ case 7: eor(_tmp2, T16B, _tmp2, _tmp1); break; ++ case 8: eor(_tmp2, T16B, _tmp2, _tmp3); break; ++ ++ // Register pair <_result_hi:_result_lo> holds the _result of carry-less multiplication ++ case 9: ins(_result_hi, D, _tmp2, 0, 1); break; ++ case 10: ins(_result_lo, D, _tmp2, 1, 0); break; ++ default: ShouldNotReachHere(); ++ } ++ } ++ ++ virtual KernelGenerator *next() { ++ GHASHMultiplyGenerator *result ++ = new GHASHMultiplyGenerator(this, _unrolls, _result_lo, _result_hi, ++ _b, _a, _a1_xor_a0, _p, _vzr, ++ _tmp1, _tmp2, _tmp3); ++ result->_result_lo += register_stride; ++ result->_result_hi += register_stride; ++ result->_b += register_stride; ++ result->_tmp1 += register_stride; ++ result->_tmp2 += register_stride; ++ result->_tmp3 += register_stride; ++ return result; ++ } ++ ++ virtual int length() { return 11; } ++}; ++ ++// Reduce the 128-bit product in hi:lo by the GCM field polynomial. ++// The FloatRegister argument called data is optional: if it is a ++// valid register, we interleave LD1 instructions with the ++// reduction. This is to reduce latency next time around the loop. ++class GHASHReduceGenerator: public KernelGenerator { ++ FloatRegister _result, _lo, _hi, _p, _vzr, _data, _t1; ++ int _once; ++public: ++ GHASHReduceGenerator(Assembler *as, int unrolls, ++ /* offsetted registers */ ++ FloatRegister result, FloatRegister lo, FloatRegister hi, ++ /* non-offsetted (shared) registers */ ++ FloatRegister p, FloatRegister vzr, FloatRegister data, ++ /* offseted (temp) registers */ ++ FloatRegister t1) ++ : KernelGenerator(as, unrolls), ++ _result(result), _lo(lo), _hi(hi), ++ _p(p), _vzr(vzr), _data(data), _t1(t1), _once(true) { } ++ ++ static const int register_stride = 7; ++ ++ virtual void generate(int index) { ++ const FloatRegister t0 = _result; ++ ++ switch (index) { ++ // The GCM field polynomial f is z^128 + p(z), where p = ++ // z^7+z^2+z+1. ++ // ++ // z^128 === -p(z) (mod (z^128 + p(z))) ++ // ++ // so, given that the product we're reducing is ++ // a == lo + hi * z^128 ++ // substituting, ++ // === lo - hi * p(z) (mod (z^128 + p(z))) ++ // ++ // we reduce by multiplying hi by p(z) and subtracting the _result ++ // from (i.e. XORing it with) lo. Because p has no nonzero high ++ // bits we can do this with two 64-bit multiplications, lo*p and ++ // hi*p. ++ ++ case 0: pmull2(t0, T1Q, _hi, _p, T2D); break; ++ case 1: ext(_t1, T16B, t0, _vzr, 8); break; ++ case 2: eor(_hi, T16B, _hi, _t1); break; ++ case 3: ext(_t1, T16B, _vzr, t0, 8); break; ++ case 4: eor(_lo, T16B, _lo, _t1); break; ++ case 5: pmull(t0, T1Q, _hi, _p, T1D); break; ++ case 6: eor(_result, T16B, _lo, t0); break; ++ default: ShouldNotReachHere(); ++ } ++ ++ // Sprinkle load instructions into the generated instructions ++ if (_data->is_valid() && _once) { ++ assert(length() >= unrolls(), "not enough room for inteleaved loads"); ++ if (index < unrolls()) { ++ ld1((_data + index*register_stride), T16B, post(r2, 0x10)); ++ } ++ } ++ } ++ ++ virtual KernelGenerator *next() { ++ GHASHReduceGenerator *result ++ = new GHASHReduceGenerator(this, _unrolls, ++ _result, _lo, _hi, _p, _vzr, _data, _t1); ++ result->_result += register_stride; ++ result->_hi += register_stride; ++ result->_lo += register_stride; ++ result->_t1 += register_stride; ++ result->_once = false; ++ return result; ++ } ++ ++ int length() { return 7; } ++}; ++ ++// Perform a GHASH multiply/reduce on a single FloatRegister. ++void MacroAssembler::ghash_modmul(FloatRegister result, ++ FloatRegister result_lo, FloatRegister result_hi, FloatRegister b, ++ FloatRegister a, FloatRegister vzr, FloatRegister a1_xor_a0, FloatRegister p, ++ FloatRegister t1, FloatRegister t2, FloatRegister t3) { ++ ghash_multiply(result_lo, result_hi, a, b, a1_xor_a0, t1, t2, t3); ++ ghash_reduce(result, result_lo, result_hi, p, vzr, t1); ++} ++ ++// Interleaved GHASH processing. ++// ++// Clobbers all vector registers. ++// ++void MacroAssembler::ghash_processBlocks_wide(address field_polynomial, Register state, ++ Register subkeyH, ++ Register data, Register blocks, int unrolls) { ++ int register_stride = 7; ++ ++ // Bafflingly, GCM uses little-endian for the byte order, but ++ // big-endian for the bit order. For example, the polynomial 1 is ++ // represented as the 16-byte string 80 00 00 00 | 12 bytes of 00. ++ // ++ // So, we must either reverse the bytes in each word and do ++ // everything big-endian or reverse the bits in each byte and do ++ // it little-endian. On AArch64 it's more idiomatic to reverse ++ // the bits in each byte (we have an instruction, RBIT, to do ++ // that) and keep the data in little-endian bit order throught the ++ // calculation, bit-reversing the inputs and outputs. ++ ++ assert(unrolls * register_stride < 32, "out of registers"); ++ ++ FloatRegister a1_xor_a0 = v28; ++ FloatRegister Hprime = v29; ++ FloatRegister vzr = v30; ++ FloatRegister p = v31; ++ eor(vzr, T16B, vzr, vzr); // zero register ++ ++ ldrq(p, field_polynomial); // The field polynomial ++ ++ ldrq(v0, Address(state)); ++ ldrq(Hprime, Address(subkeyH)); ++ ++ rev64(v0, T16B, v0); // Bit-reverse words in state and subkeyH ++ rbit(v0, T16B, v0); ++ rev64(Hprime, T16B, Hprime); ++ rbit(Hprime, T16B, Hprime); ++ ++ // Powers of H -> Hprime ++ ++ Label already_calculated, done; ++ { ++ // The first time around we'll have to calculate H**2, H**3, etc. ++ // Look at the largest power of H in the subkeyH array to see if ++ // it's already been calculated. ++ ldp(rscratch1, rscratch2, Address(subkeyH, 16 * (unrolls - 1))); ++ orr(rscratch1, rscratch1, rscratch2); ++ cbnz(rscratch1, already_calculated); ++ ++ orr(v6, T16B, Hprime, Hprime); // Start with H in v6 and Hprime ++ for (int i = 1; i < unrolls; i++) { ++ ext(a1_xor_a0, T16B, Hprime, Hprime, 0x08); // long-swap subkeyH into a1_xor_a0 ++ eor(a1_xor_a0, T16B, a1_xor_a0, Hprime); // xor subkeyH into subkeyL (Karatsuba: (A1+A0)) ++ ghash_modmul(/*result*/v6, /*result_lo*/v5, /*result_hi*/v4, /*b*/v6, ++ Hprime, vzr, a1_xor_a0, p, ++ /*temps*/v1, v3, v2); ++ rev64(v1, T16B, v6); ++ rbit(v1, T16B, v1); ++ strq(v1, Address(subkeyH, 16 * i)); ++ } ++ b(done); ++ } ++ { ++ bind(already_calculated); ++ ++ // Load the largest power of H we need into v6. ++ ldrq(v6, Address(subkeyH, 16 * (unrolls - 1))); ++ rev64(v6, T16B, v6); ++ rbit(v6, T16B, v6); ++ } ++ bind(done); ++ ++ orr(Hprime, T16B, v6, v6); // Move H ** unrolls into Hprime ++ ++ // Hprime contains (H ** 1, H ** 2, ... H ** unrolls) ++ // v0 contains the initial state. Clear the others. ++ for (int i = 1; i < unrolls; i++) { ++ int ofs = register_stride * i; ++ eor(ofs+v0, T16B, ofs+v0, ofs+v0); // zero each state register ++ } ++ ++ ext(a1_xor_a0, T16B, Hprime, Hprime, 0x08); // long-swap subkeyH into a1_xor_a0 ++ eor(a1_xor_a0, T16B, a1_xor_a0, Hprime); // xor subkeyH into subkeyL (Karatsuba: (A1+A0)) ++ ++ // Load #unrolls blocks of data ++ for (int ofs = 0; ofs < unrolls * register_stride; ofs += register_stride) { ++ ld1(v2+ofs, T16B, post(data, 0x10)); ++ } ++ ++ // Register assignments, replicated across 4 clones, v0 ... v23 ++ // ++ // v0: input / output: current state, result of multiply/reduce ++ // v1: temp ++ // v2: input: one block of data (the ciphertext) ++ // also used as a temp once the data has been consumed ++ // v3: temp ++ // v4: output: high part of product ++ // v5: output: low part ... ++ // v6: unused ++ // ++ // Not replicated: ++ // ++ // v28: High part of H xor low part of H' ++ // v29: H' (hash subkey) ++ // v30: zero ++ // v31: Reduction polynomial of the Galois field ++ ++ // Inner loop. ++ // Do the whole load/add/multiply/reduce over all our data except ++ // the last few rows. ++ { ++ Label L_ghash_loop; ++ bind(L_ghash_loop); ++ ++ // Prefetching doesn't help here. In fact, on Neoverse N1 it's worse. ++ // prfm(Address(data, 128), PLDL1KEEP); ++ ++ // Xor data into current state ++ for (int ofs = 0; ofs < unrolls * register_stride; ofs += register_stride) { ++ rbit((v2+ofs), T16B, (v2+ofs)); ++ eor((v2+ofs), T16B, v0+ofs, (v2+ofs)); // bit-swapped data ^ bit-swapped state ++ } ++ ++ // Generate fully-unrolled multiply-reduce in two stages. ++ ++ (new GHASHMultiplyGenerator(this, unrolls, ++ /*result_lo*/v5, /*result_hi*/v4, /*data*/v2, ++ Hprime, a1_xor_a0, p, vzr, ++ /*temps*/v1, v3, /* reuse b*/v2))->unroll(); ++ ++ // NB: GHASHReduceGenerator also loads the next #unrolls blocks of ++ // data into v0, v0+ofs, the current state. ++ (new GHASHReduceGenerator (this, unrolls, ++ /*result*/v0, /*lo*/v5, /*hi*/v4, p, vzr, ++ /*data*/v2, /*temp*/v3))->unroll(); ++ ++ sub(blocks, blocks, unrolls); ++ cmp(blocks, (unsigned char)(unrolls * 2)); ++ br(GE, L_ghash_loop); ++ } ++ ++ // Merge the #unrolls states. Note that the data for the next ++ // iteration has already been loaded into v4, v4+ofs, etc... ++ ++ // First, we multiply/reduce each clone by the appropriate power of H. ++ for (int i = 0; i < unrolls; i++) { ++ int ofs = register_stride * i; ++ ldrq(Hprime, Address(subkeyH, 16 * (unrolls - i - 1))); ++ ++ rbit(v2+ofs, T16B, v2+ofs); ++ eor(v2+ofs, T16B, ofs+v0, v2+ofs); // bit-swapped data ^ bit-swapped state ++ ++ rev64(Hprime, T16B, Hprime); ++ rbit(Hprime, T16B, Hprime); ++ ext(a1_xor_a0, T16B, Hprime, Hprime, 0x08); // long-swap subkeyH into a1_xor_a0 ++ eor(a1_xor_a0, T16B, a1_xor_a0, Hprime); // xor subkeyH into subkeyL (Karatsuba: (A1+A0)) ++ ghash_modmul(/*result*/v0+ofs, /*result_lo*/v5+ofs, /*result_hi*/v4+ofs, /*b*/v2+ofs, ++ Hprime, vzr, a1_xor_a0, p, ++ /*temps*/v1+ofs, v3+ofs, /* reuse b*/v2+ofs); ++ } ++ ++ // Then we sum the results. ++ for (int i = 0; i < unrolls - 1; i++) { ++ int ofs = register_stride * i; ++ eor(v0, T16B, v0, v0 + register_stride + ofs); ++ } ++ ++ sub(blocks, blocks, (unsigned char)unrolls); ++ ++ // And finally bit-reverse the state back to big endian. ++ rev64(v0, T16B, v0); ++ rbit(v0, T16B, v0); ++ st1(v0, T16B, state); ++} +\ No newline at end of file +diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +index 2e2e8ae78..c024dec55 100644 +--- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp ++++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +@@ -2804,6 +2804,266 @@ class StubGenerator: public StubCodeGenerator { + return start; + } + ++ // CTR AES crypt. ++ // Arguments: ++ // ++ // Inputs: ++ // c_rarg0 - source byte array address ++ // c_rarg1 - destination byte array address ++ // c_rarg2 - K (key) in little endian int array ++ // c_rarg3 - counter vector byte array address ++ // c_rarg4 - input length ++ // c_rarg5 - saved encryptedCounter start ++ // c_rarg6 - saved used length ++ // ++ // Output: ++ // r0 - input length ++ // ++ address generate_counterMode_AESCrypt() { ++ const Register in = c_rarg0; ++ const Register out = c_rarg1; ++ const Register key = c_rarg2; ++ const Register counter = c_rarg3; ++ const Register saved_len = c_rarg4, len = r10; ++ const Register saved_encrypted_ctr = c_rarg5; ++ const Register used_ptr = c_rarg6, used = r12; ++ ++ const Register offset = r7; ++ const Register keylen = r11; ++ ++ const unsigned char block_size = 16; ++ const int bulk_width = 4; ++ // NB: bulk_width can be 4 or 8. 8 gives slightly faster ++ // performance with larger data sizes, but it also means that the ++ // fast path isn't used until you have at least 8 blocks, and up ++ // to 127 bytes of data will be executed on the slow path. For ++ // that reason, and also so as not to blow away too much icache, 4 ++ // blocks seems like a sensible compromise. ++ ++ // Algorithm: ++ // ++ // if (len == 0) { ++ // goto DONE; ++ // } ++ // int result = len; ++ // do { ++ // if (used >= blockSize) { ++ // if (len >= bulk_width * blockSize) { ++ // CTR_large_block(); ++ // if (len == 0) ++ // goto DONE; ++ // } ++ // for (;;) { ++ // 16ByteVector v0 = counter; ++ // embeddedCipher.encryptBlock(v0, 0, encryptedCounter, 0); ++ // used = 0; ++ // if (len < blockSize) ++ // break; /* goto NEXT */ ++ // 16ByteVector v1 = load16Bytes(in, offset); ++ // v1 = v1 ^ encryptedCounter; ++ // store16Bytes(out, offset); ++ // used = blockSize; ++ // offset += blockSize; ++ // len -= blockSize; ++ // if (len == 0) ++ // goto DONE; ++ // } ++ // } ++ // NEXT: ++ // out[outOff++] = (byte)(in[inOff++] ^ encryptedCounter[used++]); ++ // len--; ++ // } while (len != 0); ++ // DONE: ++ // return result; ++ // ++ // CTR_large_block() ++ // Wide bulk encryption of whole blocks. ++ ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "counterMode_AESCrypt"); ++ const address start = __ pc(); ++ __ enter(); ++ ++ Label DONE, CTR_large_block, large_block_return; ++ __ ldrw(used, Address(used_ptr)); ++ __ cbzw(saved_len, DONE); ++ ++ __ mov(len, saved_len); ++ __ mov(offset, 0); ++ ++ // Compute #rounds for AES based on the length of the key array ++ __ ldrw(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); ++ ++ __ aesenc_loadkeys(key, keylen); ++ ++ { ++ Label L_CTR_loop, NEXT; ++ ++ __ bind(L_CTR_loop); ++ ++ __ cmp(used, block_size); ++ __ br(__ LO, NEXT); ++ ++ // Maybe we have a lot of data ++ __ subsw(rscratch1, len, bulk_width * block_size); ++ __ br(__ HS, CTR_large_block); ++ __ BIND(large_block_return); ++ __ cbzw(len, DONE); ++ ++ // Setup the counter ++ __ movi(v4, __ T4S, 0); ++ __ movi(v5, __ T4S, 1); ++ __ ins(v4, __ S, v5, 3, 3); // v4 contains { 0, 0, 0, 1 } ++ ++ __ ld1(v0, __ T16B, counter); // Load the counter into v0 ++ __ rev32(v16, __ T16B, v0); ++ __ addv(v16, __ T4S, v16, v4); ++ __ rev32(v16, __ T16B, v16); ++ __ st1(v16, __ T16B, counter); // Save the incremented counter back ++ ++ { ++ // We have fewer than bulk_width blocks of data left. Encrypt ++ // them one by one until there is less than a full block ++ // remaining, being careful to save both the encrypted counter ++ // and the counter. ++ ++ Label inner_loop; ++ __ bind(inner_loop); ++ // Counter to encrypt is in v0 ++ __ aesecb_encrypt(noreg, noreg, keylen); ++ __ st1(v0, __ T16B, saved_encrypted_ctr); ++ ++ // Do we have a remaining full block? ++ ++ __ mov(used, 0); ++ __ cmp(len, block_size); ++ __ br(__ LO, NEXT); ++ ++ // Yes, we have a full block ++ __ ldrq(v1, Address(in, offset)); ++ __ eor(v1, __ T16B, v1, v0); ++ __ strq(v1, Address(out, offset)); ++ __ mov(used, block_size); ++ __ add(offset, offset, block_size); ++ ++ __ subw(len, len, block_size); ++ __ cbzw(len, DONE); ++ ++ // Increment the counter, store it back ++ __ orr(v0, __ T16B, v16, v16); ++ __ rev32(v16, __ T16B, v16); ++ __ addv(v16, __ T4S, v16, v4); ++ __ rev32(v16, __ T16B, v16); ++ __ st1(v16, __ T16B, counter); // Save the incremented counter back ++ ++ __ b(inner_loop); ++ } ++ ++ __ BIND(NEXT); ++ ++ // Encrypt a single byte, and loop. ++ // We expect this to be a rare event. ++ __ ldrb(rscratch1, Address(in, offset)); ++ __ ldrb(rscratch2, Address(saved_encrypted_ctr, used)); ++ __ eor(rscratch1, rscratch1, rscratch2); ++ __ strb(rscratch1, Address(out, offset)); ++ __ add(offset, offset, 1); ++ __ add(used, used, 1); ++ __ subw(len, len,1); ++ __ cbnzw(len, L_CTR_loop); ++ } ++ ++ __ bind(DONE); ++ __ strw(used, Address(used_ptr)); ++ __ mov(r0, saved_len); ++ ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(lr); ++ ++ // Bulk encryption ++ ++ __ BIND (CTR_large_block); ++ assert(bulk_width == 4 || bulk_width == 8, "must be"); ++ ++ if (bulk_width == 8) { ++ __ sub(sp, sp, 4 * 16); ++ __ st1(v12, v13, v14, v15, __ T16B, Address(sp)); ++ } ++ __ sub(sp, sp, 4 * 16); ++ __ st1(v8, v9, v10, v11, __ T16B, Address(sp)); ++ RegSet saved_regs = (RegSet::of(in, out, offset) ++ + RegSet::of(saved_encrypted_ctr, used_ptr, len)); ++ __ push(saved_regs, sp); ++ __ andr(len, len, -16 * bulk_width); // 8/4 encryptions, 16 bytes per encryption ++ __ add(in, in, offset); ++ __ add(out, out, offset); ++ ++ // Keys should already be loaded into the correct registers ++ ++ __ ld1(v0, __ T16B, counter); // v0 contains the first counter ++ __ rev32(v16, __ T16B, v0); // v16 contains byte-reversed counter ++ ++ // AES/CTR loop ++ { ++ Label L_CTR_loop; ++ __ BIND(L_CTR_loop); ++ ++ // Setup the counters ++ __ movi(v8, __ T4S, 0); ++ __ movi(v9, __ T4S, 1); ++ __ ins(v8, __ S, v9, 3, 3); // v8 contains { 0, 0, 0, 1 } ++ ++ for (FloatRegister f = v0; f < v0 + bulk_width; f++) { ++ __ rev32(f, __ T16B, v16); ++ __ addv(v16, __ T4S, v16, v8); ++ } ++ ++ __ ld1(v8, v9, v10, v11, __ T16B, __ post(in, 4 * 16)); ++ ++ // Encrypt the counters ++ __ aesecb_encrypt(noreg, noreg, keylen, v0, bulk_width); ++ ++ if (bulk_width == 8) { ++ __ ld1(v12, v13, v14, v15, __ T16B, __ post(in, 4 * 16)); ++ } ++ ++ // XOR the encrypted counters with the inputs ++ for (int i = 0; i < bulk_width; i++) { ++ __ eor(v0 + i, __ T16B, v0 + i, v8 + i); ++ } ++ ++ // Write the encrypted data ++ __ st1(v0, v1, v2, v3, __ T16B, __ post(out, 4 * 16)); ++ if (bulk_width == 8) { ++ __ st1(v4, v5, v6, v7, __ T16B, __ post(out, 4 * 16)); ++ } ++ ++ __ subw(len, len, 16 * bulk_width); ++ __ cbnzw(len, L_CTR_loop); ++ } ++ ++ // Save the counter back where it goes ++ __ rev32(v16, __ T16B, v16); ++ __ st1(v16, __ T16B, counter); ++ ++ __ pop(saved_regs, sp); ++ ++ __ ld1(v8, v9, v10, v11, __ T16B, __ post(sp, 4 * 16)); ++ if (bulk_width == 8) { ++ __ ld1(v12, v13, v14, v15, __ T16B, __ post(sp, 4 * 16)); ++ } ++ ++ __ andr(rscratch1, len, -16 * bulk_width); ++ __ sub(len, len, rscratch1); ++ __ add(offset, offset, rscratch1); ++ __ mov(used, 16); ++ __ strw(used, Address(used_ptr)); ++ __ b(large_block_return); ++ ++ return start; ++ } ++ ++ + // Arguments: + // + // Inputs: +@@ -3677,6 +3937,56 @@ class StubGenerator: public StubCodeGenerator { + return start; + } + ++ address generate_ghash_processBlocks_wide() { ++ address small = generate_ghash_processBlocks(); ++ ++ StubCodeMark mark(this, "StubRoutines", "ghash_processBlocks_wide"); ++ __ align(wordSize * 2); ++ address p = __ pc(); ++ __ emit_int64(0x87); // The low-order bits of the field ++ // polynomial (i.e. p = z^7+z^2+z+1) ++ // repeated in the low and high parts of a ++ // 128-bit vector ++ __ emit_int64(0x87); ++ ++ __ align(CodeEntryAlignment); ++ address start = __ pc(); ++ ++ Register state = c_rarg0; ++ Register subkeyH = c_rarg1; ++ Register data = c_rarg2; ++ Register blocks = c_rarg3; ++ ++ const int unroll = 4; ++ ++ __ cmp(blocks, (unsigned char)(unroll * 2)); ++ __ br(__ LT, small); ++ ++ if (unroll > 1) { ++ // Save state before entering routine ++ __ sub(sp, sp, 4 * 16); ++ __ st1(v12, v13, v14, v15, __ T16B, Address(sp)); ++ __ sub(sp, sp, 4 * 16); ++ __ st1(v8, v9, v10, v11, __ T16B, Address(sp)); ++ } ++ ++ __ ghash_processBlocks_wide(p, state, subkeyH, data, blocks, unroll); ++ ++ if (unroll > 1) { ++ // And restore state ++ __ ld1(v8, v9, v10, v11, __ T16B, __ post(sp, 4 * 16)); ++ __ ld1(v12, v13, v14, v15, __ T16B, __ post(sp, 4 * 16)); ++ } ++ ++ __ cmp(blocks, 0u); ++ __ br(__ GT, small); ++ ++ __ ret(lr); ++ ++ return start; ++ } ++ ++ + // Continuation point for throwing of implicit exceptions that are + // not handled in the current activation. Fabricates an exception + // oop and initiates normal exception dispatching in this +@@ -4687,6 +4997,15 @@ class StubGenerator: public StubCodeGenerator { + StubRoutines::_montgomerySquare = g.generate_multiply(); + } + ++ // generate GHASH intrinsics code ++ if (UseGHASHIntrinsics) { ++ if (UseAESCTRIntrinsics) { ++ StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks_wide(); ++ } else { ++ StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); ++ } ++ } ++ + if (UseAESIntrinsics) { + StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); + StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); +@@ -4694,9 +5013,8 @@ class StubGenerator: public StubCodeGenerator { + StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt(); + } + +- // generate GHASH intrinsics code +- if (UseGHASHIntrinsics) { +- StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); ++ if (UseAESCTRIntrinsics) { ++ StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt(); + } + + if (UseSHA1Intrinsics) { +diff --git a/hotspot/src/cpu/aarch64/vm/stubRoutines_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/stubRoutines_aarch64.hpp +index d1c312ab3..05619ce7f 100644 +--- a/hotspot/src/cpu/aarch64/vm/stubRoutines_aarch64.hpp ++++ b/hotspot/src/cpu/aarch64/vm/stubRoutines_aarch64.hpp +@@ -37,7 +37,7 @@ static bool returns_to_call_stub(address return_pc) { + + enum platform_dependent_constants { + code_size1 = 19000, // simply increase if too small (assembler will crash if too small) +- code_size2 = 22000 // simply increase if too small (assembler will crash if too small) ++ code_size2 = 32000 // simply increase if too small (assembler will crash if too small) + }; + + class aarch64 { +diff --git a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp +index 9808337a0..de636fb83 100644 +--- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp ++++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp +@@ -233,12 +233,21 @@ void VM_Version::get_processor_features() { + warning("UseAESIntrinsics enabled, but UseAES not, enabling"); + UseAES = true; + } ++ if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { ++ FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); ++ } + } else { + if (UseAES) { +- warning("UseAES specified, but not supported on this CPU"); ++ warning("AES instructions are not available on this CPU"); ++ FLAG_SET_DEFAULT(UseAES, false); + } + if (UseAESIntrinsics) { +- warning("UseAESIntrinsics specified, but not supported on this CPU"); ++ warning("AES intrinsics are not available on this CPU"); ++ FLAG_SET_DEFAULT(UseAESIntrinsics, false); ++ } ++ if (UseAESCTRIntrinsics) { ++ warning("AES/CTR intrinsics are not available on this CPU"); ++ FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } + } + +diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +index b5ce1cfa9..fea8b1f87 100644 +--- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp ++++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +@@ -194,6 +194,11 @@ void VM_Version::initialize() { + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } + ++ if (UseAESCTRIntrinsics) { ++ warning("AES/CTR intrinsics are not available on this CPU"); ++ FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); ++ } ++ + if (UseGHASHIntrinsics) { + warning("GHASH intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); +diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +index bd893e138..08d7a7311 100644 +--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp ++++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +@@ -319,6 +319,11 @@ void VM_Version::initialize() { + } + } + ++ if (UseAESCTRIntrinsics) { ++ warning("AES/CTR intrinsics are not available on this CPU"); ++ FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); ++ } ++ + // GHASH/GCM intrinsics + if (has_vis3() && (UseVIS > 2)) { + if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { +diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp +index 1759ecdfd..ddc1acfd8 100644 +--- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp ++++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp +@@ -2373,20 +2373,52 @@ void Assembler::pcmpestri(XMMRegister dst, XMMRegister src, int imm8) { + + void Assembler::pextrd(Register dst, XMMRegister src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); +- int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, false); ++ int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, false); + emit_int8(0x16); + emit_int8((unsigned char)(0xC0 | encode)); + emit_int8(imm8); + } + ++void Assembler::pextrd(Address dst, XMMRegister src, int imm8) { ++ assert(VM_Version::supports_sse4_1(), ""); ++ simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F_3A, false); ++ emit_int8(0x16); ++ emit_operand(src, dst); ++ emit_int8(imm8); ++} ++ + void Assembler::pextrq(Register dst, XMMRegister src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); +- int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, true); ++ int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, true); + emit_int8(0x16); + emit_int8((unsigned char)(0xC0 | encode)); + emit_int8(imm8); + } + ++void Assembler::pextrq(Address dst, XMMRegister src, int imm8) { ++ assert(VM_Version::supports_sse4_1(), ""); ++ simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F_3A, true); ++ emit_int8(0x16); ++ emit_operand(src, dst); ++ emit_int8(imm8); ++} ++ ++void Assembler::pextrw(Address dst, XMMRegister src, int imm8) { ++ assert(VM_Version::supports_sse4_1(), ""); ++ simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F_3A); ++ emit_int8((unsigned char)0x15); ++ emit_operand(src, dst); ++ emit_int8(imm8); ++} ++ ++void Assembler::pextrb(Address dst, XMMRegister src, int imm8) { ++ assert(VM_Version::supports_sse4_1(), ""); ++ simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F_3A); ++ emit_int8(0x14); ++ emit_operand(src, dst); ++ emit_int8(imm8); ++} ++ + void Assembler::pinsrd(XMMRegister dst, Register src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, false); +@@ -2395,6 +2427,14 @@ void Assembler::pinsrd(XMMRegister dst, Register src, int imm8) { + emit_int8(imm8); + } + ++void Assembler::pinsrd(XMMRegister dst, Address src, int imm8) { ++ assert(VM_Version::supports_sse4_1(), ""); ++ simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, false); ++ emit_int8(0x22); ++ emit_operand(dst,src); ++ emit_int8(imm8); ++} ++ + void Assembler::pinsrq(XMMRegister dst, Register src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, true); +@@ -2403,6 +2443,30 @@ void Assembler::pinsrq(XMMRegister dst, Register src, int imm8) { + emit_int8(imm8); + } + ++void Assembler::pinsrq(XMMRegister dst, Address src, int imm8) { ++ assert(VM_Version::supports_sse4_1(), ""); ++ simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, true); ++ emit_int8(0x22); ++ emit_operand(dst, src); ++ emit_int8(imm8); ++} ++ ++void Assembler::pinsrw(XMMRegister dst, Address src, int imm8) { ++ assert(VM_Version::supports_sse2(), ""); ++ simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F); ++ emit_int8((unsigned char)0xC4); ++ emit_operand(dst, src); ++ emit_int8(imm8); ++} ++ ++void Assembler::pinsrb(XMMRegister dst, Address src, int imm8) { ++ assert(VM_Version::supports_sse4_1(), ""); ++ simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A); ++ emit_int8(0x20); ++ emit_operand(dst, src); ++ emit_int8(imm8); ++} ++ + void Assembler::pmovzxbw(XMMRegister dst, Address src) { + assert(VM_Version::supports_sse4_1(), ""); + InstructionMark im(this); +@@ -3075,6 +3139,12 @@ void Assembler::xorl(Register dst, Register src) { + emit_arith(0x33, 0xC0, dst, src); + } + ++void Assembler::xorb(Register dst, Address src) { ++ InstructionMark im(this); ++ prefix(src, dst); ++ emit_int8(0x32); ++ emit_operand(dst, src); ++} + + // AVX 3-operands scalar float-point arithmetic instructions + +diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp +index 5ea01311e..c2e70bc2a 100644 +--- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp ++++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp +@@ -1479,10 +1479,20 @@ private: + // SSE 4.1 extract + void pextrd(Register dst, XMMRegister src, int imm8); + void pextrq(Register dst, XMMRegister src, int imm8); ++ void pextrd(Address dst, XMMRegister src, int imm8); ++ void pextrq(Address dst, XMMRegister src, int imm8); ++ void pextrb(Address dst, XMMRegister src, int imm8); ++ // SSE 2 extract ++ void pextrw(Address dst, XMMRegister src, int imm8); + + // SSE 4.1 insert + void pinsrd(XMMRegister dst, Register src, int imm8); + void pinsrq(XMMRegister dst, Register src, int imm8); ++ void pinsrd(XMMRegister dst, Address src, int imm8); ++ void pinsrq(XMMRegister dst, Address src, int imm8); ++ void pinsrb(XMMRegister dst, Address src, int imm8); ++ // SSE 2 insert ++ void pinsrw(XMMRegister dst, Address src, int imm8); + + // SSE4.1 packed move + void pmovzxbw(XMMRegister dst, XMMRegister src); +@@ -1687,6 +1697,8 @@ private: + void xorl(Register dst, Address src); + void xorl(Register dst, Register src); + ++ void xorb(Register dst, Address src); ++ + void xorq(Register dst, Address src); + void xorq(Register dst, Register src); + +diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp +index 2e5599807..f555f3326 100644 +--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp ++++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp +@@ -2153,6 +2153,17 @@ class StubGenerator: public StubCodeGenerator { + return start; + } + ++ address generate_counter_shuffle_mask() { ++ __ align(16); ++ StubCodeMark mark(this, "StubRoutines", "counter_shuffle_mask"); ++ address start = __ pc(); ++ __ emit_data(0x0c0d0e0f, relocInfo::none, 0); ++ __ emit_data(0x08090a0b, relocInfo::none, 0); ++ __ emit_data(0x04050607, relocInfo::none, 0); ++ __ emit_data(0x00010203, relocInfo::none, 0); ++ return start; ++ } ++ + // Utility routine for loading a 128-bit key word in little endian format + // can optionally specify that the shuffle mask is already in an xmmregister + void load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask=NULL) { +@@ -2178,6 +2189,31 @@ class StubGenerator: public StubCodeGenerator { + __ aesdec(xmmdst, xmmtmp); + } + ++ // Utility routine for increase 128bit counter (iv in CTR mode) ++ // XMM_128bit, D3, D2, D1, D0 ++ void inc_counter(Register reg, XMMRegister xmmdst, int inc_delta, Label& next_block) { ++ __ pextrd(reg, xmmdst, 0x0); ++ __ addl(reg, inc_delta); ++ __ pinsrd(xmmdst, reg, 0x0); ++ __ jcc(Assembler::carryClear, next_block); // jump if no carry ++ ++ __ pextrd(reg, xmmdst, 0x01); // Carry-> D1 ++ __ addl(reg, 0x01); ++ __ pinsrd(xmmdst, reg, 0x01); ++ __ jcc(Assembler::carryClear, next_block); // jump if no carry ++ ++ __ pextrd(reg, xmmdst, 0x02); // Carry-> D2 ++ __ addl(reg, 0x01); ++ __ pinsrd(xmmdst, reg, 0x02); ++ __ jcc(Assembler::carryClear, next_block); // jump if no carry ++ ++ __ pextrd(reg, xmmdst, 0x03); // Carry -> D3 ++ __ addl(reg, 0x01); ++ __ pinsrd(xmmdst, reg, 0x03); ++ ++ __ BIND(next_block); // next instruction ++ } ++ + + // Arguments: + // +@@ -2719,6 +2755,309 @@ class StubGenerator: public StubCodeGenerator { + return start; + } + ++ ++ // CTR AES crypt. ++ // In 32-bit stub, parallelize 4 blocks at a time ++ // Arguments: ++ // ++ // Inputs: ++ // c_rarg0 - source byte array address ++ // c_rarg1 - destination byte array address ++ // c_rarg2 - K (key) in little endian int array ++ // c_rarg3 - counter vector byte array address ++ // c_rarg4 - input length ++ // ++ // Output: ++ // rax - input length ++ // ++ address generate_counterMode_AESCrypt_Parallel() { ++ assert(UseAES, "need AES instructions and misaligned SSE support"); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "counterMode_AESCrypt"); ++ address start = __ pc(); ++ const Register from = rsi; // source array address ++ const Register to = rdx; // destination array address ++ const Register key = rcx; // key array address ++ const Register counter = rdi; // counter byte array initialized from initvector array address ++ ++ // and left with the results of the last encryption block ++ const Register len_reg = rbx; ++ const Register pos = rax; ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ handleSOERegisters(true /*saving*/); // save rbx, rsi, rdi ++ ++ // load registers from incoming parameters ++ const Address from_param(rbp, 8+0); ++ const Address to_param (rbp, 8+4); ++ const Address key_param (rbp, 8+8); ++ const Address rvec_param (rbp, 8+12); ++ const Address len_param (rbp, 8+16); ++ const Address saved_counter_param(rbp, 8 + 20); ++ const Address used_addr_param(rbp, 8 + 24); ++ ++ __ movptr(from , from_param); ++ __ movptr(to , to_param); ++ //__ movptr(key, key_param); ++ //__ movptr(counter, rvec_param); ++ __ movptr(len_reg , len_param); ++ //__ movptr(pos, 0); ++ ++ // Use the partially used encrpyted counter from last invocation ++ Label L_exit_preLoop, L_preLoop_start; ++ ++ // Use the registers 'counter' and 'key' here in this preloop ++ // to hold of last 2 params 'used' and 'saved_encCounter_start' ++ Register used = counter; ++ Register saved_encCounter_start = key; ++ Register used_addr = saved_encCounter_start; ++ ++ __ movptr(used_addr, used_addr_param); ++ __ movptr(used, Address(used_addr, 0)); ++ __ movptr(saved_encCounter_start, saved_counter_param); ++ ++ __ BIND(L_preLoop_start); ++ __ cmpptr(used, 16); ++ __ jcc(Assembler::aboveEqual, L_exit_preLoop); ++ __ cmpptr(len_reg, 0); ++ __ jcc(Assembler::lessEqual, L_exit_preLoop); ++ __ movb(rax, Address(saved_encCounter_start, used)); ++ __ xorb(rax, Address(from, 0)); ++ __ movb(Address(to, 0), rax); ++ __ addptr(from, 1); ++ __ addptr(to, 1); ++ __ addptr(used, 1); ++ __ subptr(len_reg, 1); ++ ++ __ jmp(L_preLoop_start); ++ ++ __ BIND(L_exit_preLoop); ++ __ movptr(used_addr, used_addr_param); ++ __ movptr(used_addr, used_addr_param); ++ __ movl(Address(used_addr, 0), used); ++ ++ // load the parameters 'key' and 'counter' ++ __ movptr(key, key_param); ++ __ movptr(counter, rvec_param); ++ ++ // xmm register assignments for the loops below ++ const XMMRegister xmm_curr_counter = xmm0; ++ const XMMRegister xmm_counter_shuf_mask = xmm1; // need to be reloaded ++ const XMMRegister xmm_key_shuf_mask = xmm2; // need to be reloaded ++ const XMMRegister xmm_key = xmm3; ++ const XMMRegister xmm_result0 = xmm4; ++ const XMMRegister xmm_result1 = xmm5; ++ const XMMRegister xmm_result2 = xmm6; ++ const XMMRegister xmm_result3 = xmm7; ++ const XMMRegister xmm_from0 = xmm1; //reuse XMM register ++ const XMMRegister xmm_from1 = xmm2; ++ const XMMRegister xmm_from2 = xmm3; ++ const XMMRegister xmm_from3 = xmm4; ++ ++ //for key_128, key_192, key_256 ++ const int rounds[3] = {10, 12, 14}; ++ Label L_singleBlockLoopTop[3]; ++ Label L_multiBlock_loopTop[3]; ++ Label L_key192_top, L_key256_top; ++ Label L_incCounter[3][4]; // 3: different key length, 4: 4 blocks at a time ++ Label L_incCounter_single[3]; //for single block, key128, key192, key256 ++ Label L_processTail_insr[3], L_processTail_4_insr[3], L_processTail_2_insr[3], L_processTail_1_insr[3], L_processTail_exit_insr[3]; ++ Label L_processTail_extr[3], L_processTail_4_extr[3], L_processTail_2_extr[3], L_processTail_1_extr[3], L_processTail_exit_extr[3]; ++ ++ Label L_exit; ++ const int PARALLEL_FACTOR = 4; //because of the limited register number ++ ++ // initialize counter with initial counter ++ __ movdqu(xmm_curr_counter, Address(counter, 0x00)); ++ __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); ++ __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled for increase ++ ++ // key length could be only {11, 13, 15} * 4 = {44, 52, 60} ++ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ __ movl(rax, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); ++ __ cmpl(rax, 52); ++ __ jcc(Assembler::equal, L_key192_top); ++ __ cmpl(rax, 60); ++ __ jcc(Assembler::equal, L_key256_top); ++ ++ //key128 begins here ++ __ movptr(pos, 0); // init pos before L_multiBlock_loopTop ++ ++#define CTR_DoFour(opc, src_reg) \ ++ __ opc(xmm_result0, src_reg); \ ++ __ opc(xmm_result1, src_reg); \ ++ __ opc(xmm_result2, src_reg); \ ++ __ opc(xmm_result3, src_reg); ++ ++ // k == 0 : generate code for key_128 ++ // k == 1 : generate code for key_192 ++ // k == 2 : generate code for key_256 ++ for (int k = 0; k < 3; ++k) { ++ //multi blocks starts here ++ __ align(OptoLoopAlignment); ++ __ BIND(L_multiBlock_loopTop[k]); ++ __ cmpptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // see if at least PARALLEL_FACTOR blocks left ++ __ jcc(Assembler::less, L_singleBlockLoopTop[k]); ++ ++ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); ++ ++ //load, then increase counters ++ CTR_DoFour(movdqa, xmm_curr_counter); ++ __ push(rbx); ++ inc_counter(rbx, xmm_result1, 0x01, L_incCounter[k][0]); ++ inc_counter(rbx, xmm_result2, 0x02, L_incCounter[k][1]); ++ inc_counter(rbx, xmm_result3, 0x03, L_incCounter[k][2]); ++ inc_counter(rbx, xmm_curr_counter, 0x04, L_incCounter[k][3]); ++ __ pop (rbx); ++ ++ load_key(xmm_key, key, 0x00, xmm_key_shuf_mask); // load Round 0 key. interleaving for better performance ++ ++ CTR_DoFour(pshufb, xmm_counter_shuf_mask); // after increased, shuffled counters back for PXOR ++ CTR_DoFour(pxor, xmm_key); //PXOR with Round 0 key ++ ++ for (int i = 1; i < rounds[k]; ++i) { ++ load_key(xmm_key, key, (0x10 * i), xmm_key_shuf_mask); ++ CTR_DoFour(aesenc, xmm_key); ++ } ++ load_key(xmm_key, key, (0x10 * rounds[k]), xmm_key_shuf_mask); ++ CTR_DoFour(aesenclast, xmm_key); ++ ++ // get next PARALLEL_FACTOR blocks into xmm_from registers ++ __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); ++ __ movdqu(xmm_from1, Address(from, pos, Address::times_1, 1 * AESBlockSize)); ++ __ movdqu(xmm_from2, Address(from, pos, Address::times_1, 2 * AESBlockSize)); ++ ++ // PXOR with input text ++ __ pxor(xmm_result0, xmm_from0); //result0 is xmm4 ++ __ pxor(xmm_result1, xmm_from1); ++ __ pxor(xmm_result2, xmm_from2); ++ ++ // store PARALLEL_FACTOR results into the next 64 bytes of output ++ __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); ++ __ movdqu(Address(to, pos, Address::times_1, 1 * AESBlockSize), xmm_result1); ++ __ movdqu(Address(to, pos, Address::times_1, 2 * AESBlockSize), xmm_result2); ++ ++ // do it here after xmm_result0 is saved, because xmm_from3 reuse the same register of xmm_result0. ++ __ movdqu(xmm_from3, Address(from, pos, Address::times_1, 3 * AESBlockSize)); ++ __ pxor(xmm_result3, xmm_from3); ++ __ movdqu(Address(to, pos, Address::times_1, 3 * AESBlockSize), xmm_result3); ++ ++ __ addptr(pos, PARALLEL_FACTOR * AESBlockSize); // increase the length of crypt text ++ __ subptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // decrease the remaining length ++ __ jmp(L_multiBlock_loopTop[k]); ++ ++ // singleBlock starts here ++ __ align(OptoLoopAlignment); ++ __ BIND(L_singleBlockLoopTop[k]); ++ __ cmpptr(len_reg, 0); ++ __ jcc(Assembler::equal, L_exit); ++ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); ++ __ movdqa(xmm_result0, xmm_curr_counter); ++ load_key(xmm_key, key, 0x00, xmm_key_shuf_mask); ++ __ push(rbx);//rbx is used for increasing counter ++ inc_counter(rbx, xmm_curr_counter, 0x01, L_incCounter_single[k]); ++ __ pop (rbx); ++ __ pshufb(xmm_result0, xmm_counter_shuf_mask); ++ __ pxor(xmm_result0, xmm_key); ++ for (int i = 1; i < rounds[k]; i++) { ++ load_key(xmm_key, key, (0x10 * i), xmm_key_shuf_mask); ++ __ aesenc(xmm_result0, xmm_key); ++ } ++ load_key(xmm_key, key, (0x10 * rounds[k]), xmm_key_shuf_mask); ++ __ aesenclast(xmm_result0, xmm_key); ++ __ cmpptr(len_reg, AESBlockSize); ++ __ jcc(Assembler::less, L_processTail_insr[k]); ++ __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); ++ __ pxor(xmm_result0, xmm_from0); ++ __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); ++ __ addptr(pos, AESBlockSize); ++ __ subptr(len_reg, AESBlockSize); ++ __ jmp(L_singleBlockLoopTop[k]); ++ ++ __ BIND(L_processTail_insr[k]); ++ __ addptr(pos, len_reg); ++ __ testptr(len_reg, 8); ++ __ jcc(Assembler::zero, L_processTail_4_insr[k]); ++ __ subptr(pos,8); ++ __ pinsrd(xmm_from0, Address(from, pos), 0); ++ __ pinsrd(xmm_from0, Address(from, pos, Address::times_1, 4), 1); ++ __ BIND(L_processTail_4_insr[k]); ++ __ testptr(len_reg, 4); ++ __ jcc(Assembler::zero, L_processTail_2_insr[k]); ++ __ subptr(pos,4); ++ __ pslldq(xmm_from0, 4); ++ __ pinsrd(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_2_insr[k]); ++ __ testptr(len_reg, 2); ++ __ jcc(Assembler::zero, L_processTail_1_insr[k]); ++ __ subptr(pos, 2); ++ __ pslldq(xmm_from0, 2); ++ __ pinsrw(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_1_insr[k]); ++ __ testptr(len_reg, 1); ++ __ jcc(Assembler::zero, L_processTail_exit_insr[k]); ++ __ subptr(pos, 1); ++ __ pslldq(xmm_from0, 1); ++ __ pinsrb(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_exit_insr[k]); ++ ++ __ movptr(saved_encCounter_start, saved_counter_param); ++ __ movdqu(Address(saved_encCounter_start, 0), xmm_result0); ++ __ pxor(xmm_result0, xmm_from0); ++ ++ __ testptr(len_reg, 8); ++ __ jcc(Assembler::zero, L_processTail_4_extr[k]); ++ __ pextrd(Address(to, pos), xmm_result0, 0); ++ __ pextrd(Address(to, pos, Address::times_1, 4), xmm_result0, 1); ++ __ psrldq(xmm_result0, 8); ++ __ addptr(pos, 8); ++ __ BIND(L_processTail_4_extr[k]); ++ __ testptr(len_reg, 4); ++ __ jcc(Assembler::zero, L_processTail_2_extr[k]); ++ __ pextrd(Address(to, pos), xmm_result0, 0); ++ __ psrldq(xmm_result0, 4); ++ __ addptr(pos, 4); ++ __ BIND(L_processTail_2_extr[k]); ++ __ testptr(len_reg, 2); ++ __ jcc(Assembler::zero, L_processTail_1_extr[k]); ++ __ pextrb(Address(to, pos), xmm_result0, 0); ++ __ pextrb(Address(to, pos, Address::times_1, 1), xmm_result0, 1); ++ __ psrldq(xmm_result0, 2); ++ __ addptr(pos, 2); ++ __ BIND(L_processTail_1_extr[k]); ++ __ testptr(len_reg, 1); ++ __ jcc(Assembler::zero, L_processTail_exit_extr[k]); ++ __ pextrb(Address(to, pos), xmm_result0, 0); ++ ++ __ BIND(L_processTail_exit_extr[k]); ++ __ movptr(used_addr, used_addr_param); ++ __ movl(Address(used_addr, 0), len_reg); ++ __ jmp(L_exit); ++ } ++ ++ __ BIND(L_exit); ++ __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); ++ __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled back. ++ __ movdqu(Address(counter, 0), xmm_curr_counter); //save counter back ++ handleSOERegisters(false /*restoring*/); ++ __ movptr(rax, len_param); // return length ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++ ++ __ BIND (L_key192_top); ++ __ movptr(pos, 0); // init pos before L_multiBlock_loopTop ++ __ jmp(L_multiBlock_loopTop[1]); //key192 ++ ++ __ BIND (L_key256_top); ++ __ movptr(pos, 0); // init pos before L_multiBlock_loopTop ++ __ jmp(L_multiBlock_loopTop[2]); //key192 ++ ++ return start; ++ } ++ ++ + // byte swap x86 long + address generate_ghash_long_swap_mask() { + __ align(CodeEntryAlignment); +@@ -3181,6 +3520,11 @@ class StubGenerator: public StubCodeGenerator { + StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt(); + } + ++ if (UseAESCTRIntrinsics) { ++ StubRoutines::x86::_counter_shuffle_mask_addr = generate_counter_shuffle_mask(); ++ StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt_Parallel(); ++ } ++ + // Generate GHASH intrinsics code + if (UseGHASHIntrinsics) { + StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask(); +diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +index c5811b28b..254f63392 100644 +--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp ++++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +@@ -3010,6 +3010,15 @@ class StubGenerator: public StubCodeGenerator { + return start; + } + ++ address generate_counter_shuffle_mask() { ++ __ align(16); ++ StubCodeMark mark(this, "StubRoutines", "counter_shuffle_mask"); ++ address start = __ pc(); ++ __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none); ++ __ emit_data64(0x0001020304050607, relocInfo::none); ++ return start; ++ } ++ + // Utility routine for loading a 128-bit key word in little endian format + // can optionally specify that the shuffle mask is already in an xmmregister + void load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask=NULL) { +@@ -3021,6 +3030,18 @@ class StubGenerator: public StubCodeGenerator { + } + } + ++ // Utility routine for increase 128bit counter (iv in CTR mode) ++ void inc_counter(Register reg, XMMRegister xmmdst, int inc_delta, Label& next_block) { ++ __ pextrq(reg, xmmdst, 0x0); ++ __ addq(reg, inc_delta); ++ __ pinsrq(xmmdst, reg, 0x0); ++ __ jcc(Assembler::carryClear, next_block); // jump if no carry ++ __ pextrq(reg, xmmdst, 0x01); // Carry ++ __ addq(reg, 0x01); ++ __ pinsrq(xmmdst, reg, 0x01); //Carry end ++ __ BIND(next_block); // next instruction ++ } ++ + // Arguments: + // + // Inputs: +@@ -3639,6 +3660,320 @@ class StubGenerator: public StubCodeGenerator { + return start; + } + ++ // This is a version of CTR/AES crypt which does 6 blocks in a loop at a time ++ // to hide instruction latency ++ // ++ // Arguments: ++ // ++ // Inputs: ++ // c_rarg0 - source byte array address ++ // c_rarg1 - destination byte array address ++ // c_rarg2 - K (key) in little endian int array ++ // c_rarg3 - counter vector byte array address ++ // Linux ++ // c_rarg4 - input length ++ // c_rarg5 - saved encryptedCounter start ++ // rbp + 6 * wordSize - saved used length ++ // Windows ++ // rbp + 6 * wordSize - input length ++ // rbp + 7 * wordSize - saved encryptedCounter start ++ // rbp + 8 * wordSize - saved used length ++ // ++ // Output: ++ // rax - input length ++ // ++ address generate_counterMode_AESCrypt_Parallel() { ++ assert(UseAES, "need AES instructions and misaligned SSE support"); ++ __ align(CodeEntryAlignment); ++ StubCodeMark mark(this, "StubRoutines", "counterMode_AESCrypt"); ++ address start = __ pc(); ++ const Register from = c_rarg0; // source array address ++ const Register to = c_rarg1; // destination array address ++ const Register key = c_rarg2; // key array address ++ const Register counter = c_rarg3; // counter byte array initialized from counter array address ++ // and left with the results of the last encryption block ++#ifndef _WIN64 ++ const Register len_reg = c_rarg4; ++ const Register saved_encCounter_start = c_rarg5; ++ const Register used_addr = r10; ++ const Address used_mem(rbp, 2 * wordSize); ++ const Register used = r11; ++#else ++ const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 ++ const Address saved_encCounter_mem(rbp, 7 * wordSize); // length is on stack on Win64 ++ const Address used_mem(rbp, 8 * wordSize); // length is on stack on Win64 ++ const Register len_reg = r10; // pick the first volatile windows register ++ const Register saved_encCounter_start = r11; ++ const Register used_addr = r13; ++ const Register used = r14; ++#endif ++ const Register pos = rax; ++ ++ const int PARALLEL_FACTOR = 6; ++ const XMMRegister xmm_counter_shuf_mask = xmm0; ++ const XMMRegister xmm_key_shuf_mask = xmm1; // used temporarily to swap key bytes up front ++ const XMMRegister xmm_curr_counter = xmm2; ++ ++ const XMMRegister xmm_key_tmp0 = xmm3; ++ const XMMRegister xmm_key_tmp1 = xmm4; ++ ++ // registers holding the four results in the parallelized loop ++ const XMMRegister xmm_result0 = xmm5; ++ const XMMRegister xmm_result1 = xmm6; ++ const XMMRegister xmm_result2 = xmm7; ++ const XMMRegister xmm_result3 = xmm8; ++ const XMMRegister xmm_result4 = xmm9; ++ const XMMRegister xmm_result5 = xmm10; ++ ++ const XMMRegister xmm_from0 = xmm11; ++ const XMMRegister xmm_from1 = xmm12; ++ const XMMRegister xmm_from2 = xmm13; ++ const XMMRegister xmm_from3 = xmm14; //the last one is xmm14. we have to preserve it on WIN64. ++ const XMMRegister xmm_from4 = xmm3; //reuse xmm3~4. Because xmm_key_tmp0~1 are useless when loading input text ++ const XMMRegister xmm_from5 = xmm4; ++ ++ //for key_128, key_192, key_256 ++ const int rounds[3] = {10, 12, 14}; ++ Label L_exit_preLoop, L_preLoop_start; ++ Label L_multiBlock_loopTop[3]; ++ Label L_singleBlockLoopTop[3]; ++ Label L__incCounter[3][6]; //for 6 blocks ++ Label L__incCounter_single[3]; //for single block, key128, key192, key256 ++ Label L_processTail_insr[3], L_processTail_4_insr[3], L_processTail_2_insr[3], L_processTail_1_insr[3], L_processTail_exit_insr[3]; ++ Label L_processTail_extr[3], L_processTail_4_extr[3], L_processTail_2_extr[3], L_processTail_1_extr[3], L_processTail_exit_extr[3]; ++ ++ Label L_exit; ++ ++ __ enter(); // required for proper stackwalking of RuntimeStub frame ++ ++#ifdef _WIN64 ++ // save the xmm registers which must be preserved 6-14 ++ const int XMM_REG_NUM_KEY_LAST = 14; ++ __ subptr(rsp, -rsp_after_call_off * wordSize); ++ for (int i = 6; i <= XMM_REG_NUM_KEY_LAST; i++) { ++ __ movdqu(xmm_save(i), as_XMMRegister(i)); ++ } ++ ++ const Address r13_save(rbp, rdi_off * wordSize); ++ const Address r14_save(rbp, rsi_off * wordSize); ++ ++ __ movptr(r13_save, r13); ++ __ movptr(r14_save, r14); ++ ++ // on win64, fill len_reg from stack position ++ __ movl(len_reg, len_mem); ++ __ movptr(saved_encCounter_start, saved_encCounter_mem); ++ __ movptr(used_addr, used_mem); ++ __ movl(used, Address(used_addr, 0)); ++#else ++ __ push(len_reg); // Save ++ __ movptr(used_addr, used_mem); ++ __ movl(used, Address(used_addr, 0)); ++#endif ++ ++ __ push(rbx); // Save RBX ++ __ movdqu(xmm_curr_counter, Address(counter, 0x00)); // initialize counter with initial counter ++ __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); ++ __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled ++ __ movptr(pos, 0); ++ ++ // Use the partially used encrpyted counter from last invocation ++ __ BIND(L_preLoop_start); ++ __ cmpptr(used, 16); ++ __ jcc(Assembler::aboveEqual, L_exit_preLoop); ++ __ cmpptr(len_reg, 0); ++ __ jcc(Assembler::lessEqual, L_exit_preLoop); ++ __ movb(rbx, Address(saved_encCounter_start, used)); ++ __ xorb(rbx, Address(from, pos)); ++ __ movb(Address(to, pos), rbx); ++ __ addptr(pos, 1); ++ __ addptr(used, 1); ++ __ subptr(len_reg, 1); ++ ++ __ jmp(L_preLoop_start); ++ ++ __ BIND(L_exit_preLoop); ++ __ movl(Address(used_addr, 0), used); ++ ++ // key length could be only {11, 13, 15} * 4 = {44, 52, 60} ++ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); ++ __ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); ++ __ cmpl(rbx, 52); ++ __ jcc(Assembler::equal, L_multiBlock_loopTop[1]); ++ __ cmpl(rbx, 60); ++ __ jcc(Assembler::equal, L_multiBlock_loopTop[2]); ++ ++#define CTR_DoSix(opc, src_reg) \ ++ __ opc(xmm_result0, src_reg); \ ++ __ opc(xmm_result1, src_reg); \ ++ __ opc(xmm_result2, src_reg); \ ++ __ opc(xmm_result3, src_reg); \ ++ __ opc(xmm_result4, src_reg); \ ++ __ opc(xmm_result5, src_reg); ++ ++ // k == 0 : generate code for key_128 ++ // k == 1 : generate code for key_192 ++ // k == 2 : generate code for key_256 ++ for (int k = 0; k < 3; ++k) { ++ //multi blocks starts here ++ __ align(OptoLoopAlignment); ++ __ BIND(L_multiBlock_loopTop[k]); ++ __ cmpptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // see if at least PARALLEL_FACTOR blocks left ++ __ jcc(Assembler::less, L_singleBlockLoopTop[k]); ++ load_key(xmm_key_tmp0, key, 0x00, xmm_key_shuf_mask); ++ ++ //load, then increase counters ++ CTR_DoSix(movdqa, xmm_curr_counter); ++ inc_counter(rbx, xmm_result1, 0x01, L__incCounter[k][0]); ++ inc_counter(rbx, xmm_result2, 0x02, L__incCounter[k][1]); ++ inc_counter(rbx, xmm_result3, 0x03, L__incCounter[k][2]); ++ inc_counter(rbx, xmm_result4, 0x04, L__incCounter[k][3]); ++ inc_counter(rbx, xmm_result5, 0x05, L__incCounter[k][4]); ++ inc_counter(rbx, xmm_curr_counter, 0x06, L__incCounter[k][5]); ++ CTR_DoSix(pshufb, xmm_counter_shuf_mask); // after increased, shuffled counters back for PXOR ++ CTR_DoSix(pxor, xmm_key_tmp0); //PXOR with Round 0 key ++ ++ //load two ROUND_KEYs at a time ++ for (int i = 1; i < rounds[k]; ) { ++ load_key(xmm_key_tmp1, key, (0x10 * i), xmm_key_shuf_mask); ++ load_key(xmm_key_tmp0, key, (0x10 * (i+1)), xmm_key_shuf_mask); ++ CTR_DoSix(aesenc, xmm_key_tmp1); ++ i++; ++ if (i != rounds[k]) { ++ CTR_DoSix(aesenc, xmm_key_tmp0); ++ } else { ++ CTR_DoSix(aesenclast, xmm_key_tmp0); ++ } ++ i++; ++ } ++ ++ // get next PARALLEL_FACTOR blocks into xmm_result registers ++ __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); ++ __ movdqu(xmm_from1, Address(from, pos, Address::times_1, 1 * AESBlockSize)); ++ __ movdqu(xmm_from2, Address(from, pos, Address::times_1, 2 * AESBlockSize)); ++ __ movdqu(xmm_from3, Address(from, pos, Address::times_1, 3 * AESBlockSize)); ++ __ movdqu(xmm_from4, Address(from, pos, Address::times_1, 4 * AESBlockSize)); ++ __ movdqu(xmm_from5, Address(from, pos, Address::times_1, 5 * AESBlockSize)); ++ ++ __ pxor(xmm_result0, xmm_from0); ++ __ pxor(xmm_result1, xmm_from1); ++ __ pxor(xmm_result2, xmm_from2); ++ __ pxor(xmm_result3, xmm_from3); ++ __ pxor(xmm_result4, xmm_from4); ++ __ pxor(xmm_result5, xmm_from5); ++ ++ // store 6 results into the next 64 bytes of output ++ __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); ++ __ movdqu(Address(to, pos, Address::times_1, 1 * AESBlockSize), xmm_result1); ++ __ movdqu(Address(to, pos, Address::times_1, 2 * AESBlockSize), xmm_result2); ++ __ movdqu(Address(to, pos, Address::times_1, 3 * AESBlockSize), xmm_result3); ++ __ movdqu(Address(to, pos, Address::times_1, 4 * AESBlockSize), xmm_result4); ++ __ movdqu(Address(to, pos, Address::times_1, 5 * AESBlockSize), xmm_result5); ++ ++ __ addptr(pos, PARALLEL_FACTOR * AESBlockSize); // increase the length of crypt text ++ __ subptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // decrease the remaining length ++ __ jmp(L_multiBlock_loopTop[k]); ++ ++ // singleBlock starts here ++ __ align(OptoLoopAlignment); ++ __ BIND(L_singleBlockLoopTop[k]); ++ __ cmpptr(len_reg, 0); ++ __ jcc(Assembler::lessEqual, L_exit); ++ load_key(xmm_key_tmp0, key, 0x00, xmm_key_shuf_mask); ++ __ movdqa(xmm_result0, xmm_curr_counter); ++ inc_counter(rbx, xmm_curr_counter, 0x01, L__incCounter_single[k]); ++ __ pshufb(xmm_result0, xmm_counter_shuf_mask); ++ __ pxor(xmm_result0, xmm_key_tmp0); ++ for (int i = 1; i < rounds[k]; i++) { ++ load_key(xmm_key_tmp0, key, (0x10 * i), xmm_key_shuf_mask); ++ __ aesenc(xmm_result0, xmm_key_tmp0); ++ } ++ load_key(xmm_key_tmp0, key, (rounds[k] * 0x10), xmm_key_shuf_mask); ++ __ aesenclast(xmm_result0, xmm_key_tmp0); ++ __ cmpptr(len_reg, AESBlockSize); ++ __ jcc(Assembler::less, L_processTail_insr[k]); ++ __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); ++ __ pxor(xmm_result0, xmm_from0); ++ __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); ++ __ addptr(pos, AESBlockSize); ++ __ subptr(len_reg, AESBlockSize); ++ __ jmp(L_singleBlockLoopTop[k]); ++ __ BIND(L_processTail_insr[k]); ++ __ addptr(pos, len_reg); ++ __ testptr(len_reg, 8); ++ __ jcc(Assembler::zero, L_processTail_4_insr[k]); ++ __ subptr(pos,8); ++ __ pinsrq(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_4_insr[k]); ++ __ testptr(len_reg, 4); ++ __ jcc(Assembler::zero, L_processTail_2_insr[k]); ++ __ subptr(pos,4); ++ __ pslldq(xmm_from0, 4); ++ __ pinsrd(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_2_insr[k]); ++ __ testptr(len_reg, 2); ++ __ jcc(Assembler::zero, L_processTail_1_insr[k]); ++ __ subptr(pos, 2); ++ __ pslldq(xmm_from0, 2); ++ __ pinsrw(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_1_insr[k]); ++ __ testptr(len_reg, 1); ++ __ jcc(Assembler::zero, L_processTail_exit_insr[k]); ++ __ subptr(pos, 1); ++ __ pslldq(xmm_from0, 1); ++ __ pinsrb(xmm_from0, Address(from, pos), 0); ++ __ BIND(L_processTail_exit_insr[k]); ++ ++ __ movdqu(Address(saved_encCounter_start, 0), xmm_result0); ++ __ pxor(xmm_result0, xmm_from0); ++ ++ __ testptr(len_reg, 8); ++ __ jcc(Assembler::zero, L_processTail_4_extr[k]); ++ __ pextrq(Address(to, pos), xmm_result0, 0); ++ __ psrldq(xmm_result0, 8); ++ __ addptr(pos, 8); ++ __ BIND(L_processTail_4_extr[k]); ++ __ testptr(len_reg, 4); ++ __ jcc(Assembler::zero, L_processTail_2_extr[k]); ++ __ pextrd(Address(to, pos), xmm_result0, 0); ++ __ psrldq(xmm_result0, 4); ++ __ addptr(pos, 4); ++ __ BIND(L_processTail_2_extr[k]); ++ __ testptr(len_reg, 2); ++ __ jcc(Assembler::zero, L_processTail_1_extr[k]); ++ __ pextrw(Address(to, pos), xmm_result0, 0); ++ __ psrldq(xmm_result0, 2); ++ __ addptr(pos, 2); ++ __ BIND(L_processTail_1_extr[k]); ++ __ testptr(len_reg, 1); ++ __ jcc(Assembler::zero, L_processTail_exit_extr[k]); ++ __ pextrb(Address(to, pos), xmm_result0, 0); ++ ++ __ BIND(L_processTail_exit_extr[k]); ++ __ movl(Address(used_addr, 0), len_reg); ++ __ jmp(L_exit); ++ ++ } ++ ++ __ BIND(L_exit); ++ __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled back. ++ __ movdqu(Address(counter, 0), xmm_curr_counter); //save counter back ++ __ pop(rbx); // pop the saved RBX. ++#ifdef _WIN64 ++ // restore regs belonging to calling function ++ for (int i = 6; i <= XMM_REG_NUM_KEY_LAST; i++) { ++ __ movdqu(as_XMMRegister(i), xmm_save(i)); ++ } ++ __ movl(rax, len_mem); ++ __ movptr(r13, r13_save); ++ __ movptr(r14, r14_save); ++#else ++ __ pop(rax); // return 'len' ++#endif ++ __ leave(); // required for proper stackwalking of RuntimeStub frame ++ __ ret(0); ++ return start; ++ } + + // byte swap x86 long + address generate_ghash_long_swap_mask() { +@@ -4239,12 +4574,15 @@ class StubGenerator: public StubCodeGenerator { + // don't bother generating these AES intrinsic stubs unless global flag is set + if (UseAESIntrinsics) { + StubRoutines::x86::_key_shuffle_mask_addr = generate_key_shuffle_mask(); // needed by the others +- + StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); + StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); + StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt(); + StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel(); + } ++ if (UseAESCTRIntrinsics){ ++ StubRoutines::x86::_counter_shuffle_mask_addr = generate_counter_shuffle_mask(); ++ StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt_Parallel(); ++ } + + // Generate GHASH intrinsics code + if (UseGHASHIntrinsics) { +diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp +index 9b0d8fc75..617879377 100644 +--- a/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp ++++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp +@@ -33,6 +33,7 @@ + + address StubRoutines::x86::_verify_mxcsr_entry = NULL; + address StubRoutines::x86::_key_shuffle_mask_addr = NULL; ++address StubRoutines::x86::_counter_shuffle_mask_addr = NULL; + address StubRoutines::x86::_ghash_long_swap_mask_addr = NULL; + address StubRoutines::x86::_ghash_byte_swap_mask_addr = NULL; + +diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp +index bb160486c..70b5a34ac 100644 +--- a/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp ++++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp +@@ -33,6 +33,10 @@ + static address _verify_mxcsr_entry; + // shuffle mask for fixing up 128-bit words consisting of big-endian 32-bit integers + static address _key_shuffle_mask_addr; ++ ++ //shuffle mask for big-endian 128-bit integers ++ static address _counter_shuffle_mask_addr; ++ + // masks and table for CRC32 + static uint64_t _crc_by128_masks[]; + static juint _crc_table[]; +@@ -43,6 +47,7 @@ + public: + static address verify_mxcsr_entry() { return _verify_mxcsr_entry; } + static address key_shuffle_mask_addr() { return _key_shuffle_mask_addr; } ++ static address counter_shuffle_mask_addr() { return _counter_shuffle_mask_addr; } + static address crc_by128_masks_addr() { return (address)_crc_by128_masks; } + static address ghash_long_swap_mask_addr() { return _ghash_long_swap_mask_addr; } + static address ghash_byte_swap_mask_addr() { return _ghash_byte_swap_mask_addr; } +diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp +index bca5d493c..538f83e69 100644 +--- a/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp ++++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp +@@ -31,7 +31,7 @@ + + enum platform_dependent_constants { + code_size1 = 9000, // simply increase if too small (assembler will crash if too small) +- code_size2 = 22000 // simply increase if too small (assembler will crash if too small) ++ code_size2 = 25800 // simply increase if too small (assembler will crash if too small) + }; + + class x86 { +diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp +index b048fd74e..f963cd2f8 100644 +--- a/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp ++++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp +@@ -33,7 +33,7 @@ static bool returns_to_call_stub(address return_pc) { return return_pc == _ + + enum platform_dependent_constants { + code_size1 = 19000, // simply increase if too small (assembler will crash if too small) +- code_size2 = 24000 // simply increase if too small (assembler will crash if too small) ++ code_size2 = 27000 // simply increase if too small (assembler will crash if too small) + }; + + class x86 { +diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +index 46b3e32ea..ce3037d76 100644 +--- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp ++++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +@@ -573,6 +573,28 @@ void VM_Version::get_processor_features() { + } + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } ++ ++ // --AES-CTR begins-- ++ if (!UseAESIntrinsics) { ++ if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { ++ warning("AES-CTR intrinsics require UseAESIntrinsics flag to be enabled. Intrinsics will be disabled."); ++ FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); ++ } ++ } else { ++ if(supports_sse4_1() && UseSSE >= 4) { ++ if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { ++ FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true); ++ } ++ } else { ++ // The AES-CTR intrinsic stubs require AES instruction support (of course) ++ // but also require sse4.1 mode or higher for instructions it use. ++ if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { ++ warning("X86 AES-CTR intrinsics require SSE4.1 instructions or higher. Intrinsics will be disabled."); ++ } ++ FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); ++ } ++ } ++ // --AES-CTR ends-- + } + } else if (UseAES || UseAESIntrinsics) { + if (UseAES && !FLAG_IS_DEFAULT(UseAES)) { +@@ -583,6 +605,10 @@ void VM_Version::get_processor_features() { + warning("AES intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } ++ if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { ++ warning("AES-CTR intrinsics are not available on this CPU"); ++ FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); ++ } + } + + // Use CLMUL instructions if available. +@@ -606,6 +632,16 @@ void VM_Version::get_processor_features() { + FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); + } + ++ if (UseAESIntrinsics) { ++ if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { ++ UseAESCTRIntrinsics = true; ++ } ++ } else if (UseAESCTRIntrinsics) { ++ if (!FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) ++ warning("AES/CTR intrinsics are not available on this CPU"); ++ FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); ++ } ++ + // GHASH/GCM intrinsics + if (UseCLMUL && (UseSSE > 2)) { + if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { +diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp +index 942d172a1..4ca2a3ad4 100644 +--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp ++++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp +@@ -846,6 +846,10 @@ + do_name( decrypt_name, "implDecrypt") \ + do_signature(byteArray_int_int_byteArray_int_signature, "([BII[BI)I") \ + \ ++ do_class(com_sun_crypto_provider_counterMode, "com/sun/crypto/provider/CounterMode") \ ++ do_intrinsic(_counterMode_AESCrypt, com_sun_crypto_provider_counterMode, crypt_name, byteArray_int_int_byteArray_int_signature, F_R) \ ++ do_name( crypt_name, "implCrypt") \ ++ \ + /* support for sun.security.provider.SHA */ \ + do_class(sun_security_provider_sha, "sun/security/provider/SHA") \ + do_intrinsic(_sha_implCompress, sun_security_provider_sha, implCompress_name, implCompress_signature, F_R) \ +diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp +index 6f8ffe608..a0e497f08 100644 +--- a/hotspot/src/share/vm/opto/escape.cpp ++++ b/hotspot/src/share/vm/opto/escape.cpp +@@ -952,6 +952,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { + strcmp(call->as_CallLeaf()->_name, "aescrypt_decryptBlock") == 0 || + strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_encryptAESCrypt") == 0 || + strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_decryptAESCrypt") == 0 || ++ strcmp(call->as_CallLeaf()->_name, "counterMode_AESCrypt") == 0 || + strcmp(call->as_CallLeaf()->_name, "ghash_processBlocks") == 0 || + strcmp(call->as_CallLeaf()->_name, "sha1_implCompress") == 0 || + strcmp(call->as_CallLeaf()->_name, "sha1_implCompressMB") == 0 || +diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp +index bb721f6f1..2add82dd1 100644 +--- a/hotspot/src/share/vm/opto/library_call.cpp ++++ b/hotspot/src/share/vm/opto/library_call.cpp +@@ -196,6 +196,7 @@ class LibraryCallKit : public GraphKit { + return generate_method_call(method_id, true, false); + } + Node * load_field_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, bool is_exact, bool is_static); ++ Node * field_address_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, bool is_exact, bool is_static, ciInstanceKlass * fromKls); + + Node* make_string_method_node(int opcode, Node* str1_start, Node* cnt1, Node* str2_start, Node* cnt2); + Node* make_string_method_node(int opcode, Node* str1, Node* str2); +@@ -309,7 +310,9 @@ class LibraryCallKit : public GraphKit { + bool inline_reference_get(); + bool inline_aescrypt_Block(vmIntrinsics::ID id); + bool inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id); ++ bool inline_counterMode_AESCrypt(vmIntrinsics::ID id); + Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting); ++ Node* inline_counterMode_AESCrypt_predicate(); + Node* get_key_start_from_aescrypt_object(Node* aescrypt_object); + Node* get_original_key_start_from_aescrypt_object(Node* aescrypt_object); + bool inline_ghash_processBlocks(); +@@ -558,6 +561,13 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { + predicates = 1; + break; + ++ case vmIntrinsics::_counterMode_AESCrypt: ++ if (!UseAESCTRIntrinsics) { ++ return NULL; ++ } ++ predicates = 1; ++ break; ++ + case vmIntrinsics::_sha_implCompress: + if (!UseSHA1Intrinsics) return NULL; + break; +@@ -950,6 +960,9 @@ bool LibraryCallKit::try_to_inline(int predicate) { + case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: + return inline_cipherBlockChaining_AESCrypt(intrinsic_id()); + ++ case vmIntrinsics::_counterMode_AESCrypt: ++ return inline_counterMode_AESCrypt(intrinsic_id()); ++ + case vmIntrinsics::_sha_implCompress: + case vmIntrinsics::_sha2_implCompress: + case vmIntrinsics::_sha5_implCompress: +@@ -1021,6 +1034,8 @@ Node* LibraryCallKit::try_to_predicate(int predicate) { + return inline_cipherBlockChaining_AESCrypt_predicate(false); + case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: + return inline_cipherBlockChaining_AESCrypt_predicate(true); ++ case vmIntrinsics::_counterMode_AESCrypt: ++ return inline_counterMode_AESCrypt_predicate(); + case vmIntrinsics::_digestBase_implCompressMB: + return inline_digestBase_implCompressMB_predicate(predicate); + +@@ -6581,6 +6596,39 @@ Node * LibraryCallKit::load_field_from_object(Node * fromObj, const char * field + return loadedField; + } + ++Node * LibraryCallKit::field_address_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, ++ bool is_exact = true, bool is_static = false, ++ ciInstanceKlass * fromKls = NULL) { ++ if (fromKls == NULL) { ++ const TypeInstPtr* tinst = _gvn.type(fromObj)->isa_instptr(); ++ assert(tinst != NULL, "obj is null"); ++ assert(tinst->klass()->is_loaded(), "obj is not loaded"); ++ assert(!is_exact || tinst->klass_is_exact(), "klass not exact"); ++ fromKls = tinst->klass()->as_instance_klass(); ++ } ++ else { ++ assert(is_static, "only for static field access"); ++ } ++ ciField* field = fromKls->get_field_by_name(ciSymbol::make(fieldName), ++ ciSymbol::make(fieldTypeString), ++ is_static); ++ ++ assert(field != NULL, "undefined field"); ++ assert(!field->is_volatile(), "not defined for volatile fields"); ++ ++ if (is_static) { ++ const TypeInstPtr* tip = TypeInstPtr::make(fromKls->java_mirror()); ++ fromObj = makecon(tip); ++ } ++ ++ // Next code copied from Parse::do_get_xxx(): ++ ++ // Compute address and memory type. ++ int offset = field->offset_in_bytes(); ++ Node *adr = basic_plus_adr(fromObj, fromObj, offset); ++ ++ return adr; ++} + + //------------------------------inline_aescrypt_Block----------------------- + bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { +@@ -6747,6 +6795,90 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { + return true; + } + ++//------------------------------inline_counterMode_AESCrypt----------------------- ++bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { ++ assert(UseAES, "need AES instruction support"); ++ if (!UseAESCTRIntrinsics) return false; ++ ++ address stubAddr = NULL; ++ const char *stubName = NULL; ++ if (id == vmIntrinsics::_counterMode_AESCrypt) { ++ stubAddr = StubRoutines::counterMode_AESCrypt(); ++ stubName = "counterMode_AESCrypt"; ++ } ++ if (stubAddr == NULL) return false; ++ ++ Node* counterMode_object = argument(0); ++ Node* src = argument(1); ++ Node* src_offset = argument(2); ++ Node* len = argument(3); ++ Node* dest = argument(4); ++ Node* dest_offset = argument(5); ++ ++ // (1) src and dest are arrays. ++ const Type* src_type = src->Value(&_gvn); ++ const Type* dest_type = dest->Value(&_gvn); ++ const TypeAryPtr* top_src = src_type->isa_aryptr(); ++ const TypeAryPtr* top_dest = dest_type->isa_aryptr(); ++ assert(top_src != NULL && top_src->klass() != NULL && ++ top_dest != NULL && top_dest->klass() != NULL, "args are strange"); ++ ++ // checks are the responsibility of the caller ++ Node* src_start = src; ++ Node* dest_start = dest; ++ if (src_offset != NULL || dest_offset != NULL) { ++ assert(src_offset != NULL && dest_offset != NULL, ""); ++ src_start = array_element_address(src, src_offset, T_BYTE); ++ dest_start = array_element_address(dest, dest_offset, T_BYTE); ++ } ++ ++ // if we are in this set of code, we "know" the embeddedCipher is an AESCrypt object ++ // (because of the predicated logic executed earlier). ++ // so we cast it here safely. ++ // this requires a newer class file that has this array as littleEndian ints, otherwise we revert to java ++ Node* embeddedCipherObj = load_field_from_object(counterMode_object, "embeddedCipher", "Lcom/sun/crypto/provider/SymmetricCipher;", /*is_exact*/ false); ++ if (embeddedCipherObj == NULL) return false; ++ // cast it to what we know it will be at runtime ++ const TypeInstPtr* tinst = _gvn.type(counterMode_object)->isa_instptr(); ++ assert(tinst != NULL, "CTR obj is null"); ++ assert(tinst->klass()->is_loaded(), "CTR obj is not loaded"); ++ ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); ++ assert(klass_AESCrypt->is_loaded(), "predicate checks that this class is loaded"); ++ ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); ++ const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_AESCrypt); ++ const TypeOopPtr* xtype = aklass->as_instance_type(); ++ Node* aescrypt_object = new (C) CheckCastPPNode(control(), embeddedCipherObj, xtype); ++ aescrypt_object = _gvn.transform(aescrypt_object); ++ // we need to get the start of the aescrypt_object's expanded key array ++ Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); ++ if (k_start == NULL) return false; ++ // similarly, get the start address of the r vector ++ Node* obj_counter = load_field_from_object(counterMode_object, "counter", "[B", /*is_exact*/ false); ++ if (obj_counter == NULL) return false; ++ Node* cnt_start = array_element_address(obj_counter, intcon(0), T_BYTE); ++ ++ Node* saved_encCounter = load_field_from_object(counterMode_object, "encryptedCounter", "[B", /*is_exact*/ false); ++ if (saved_encCounter == NULL) return false; ++ Node* saved_encCounter_start = array_element_address(saved_encCounter, intcon(0), T_BYTE); ++ Node* used = field_address_from_object(counterMode_object, "used", "I", /*is_exact*/ false); ++ ++ Node* ctrCrypt; ++ if (Matcher::pass_original_key_for_aes()) { ++ // no SPARC version for AES/CTR intrinsics now. ++ return false; ++ } ++ // Call the stub, passing src_start, dest_start, k_start, r_start and src_len ++ ctrCrypt = make_runtime_call(RC_LEAF|RC_NO_FP, ++ OptoRuntime::counterMode_aescrypt_Type(), ++ stubAddr, stubName, TypePtr::BOTTOM, ++ src_start, dest_start, k_start, cnt_start, len, saved_encCounter_start, used); ++ ++ // return cipher length (int) ++ Node* retvalue = _gvn.transform(new (C) ProjNode(ctrCrypt, TypeFunc::Parms)); ++ set_result(retvalue); ++ return true; ++} ++ + //------------------------------get_key_start_from_aescrypt_object----------------------- + Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { + #ifdef PPC64 +@@ -6841,6 +6973,48 @@ Node* LibraryCallKit::inline_cipherBlockChaining_AESCrypt_predicate(bool decrypt + return _gvn.transform(region); + } + ++//----------------------------inline_counterMode_AESCrypt_predicate---------------------------- ++// Return node representing slow path of predicate check. ++// the pseudo code we want to emulate with this predicate is: ++// for encryption: ++// if (embeddedCipherObj instanceof AESCrypt) do_intrinsic, else do_javapath ++// for decryption: ++// if ((embeddedCipherObj instanceof AESCrypt) && (cipher!=plain)) do_intrinsic, else do_javapath ++// note cipher==plain is more conservative than the original java code but that's OK ++// ++ ++Node* LibraryCallKit::inline_counterMode_AESCrypt_predicate() { ++ // The receiver was checked for NULL already. ++ Node* objCTR = argument(0); ++ ++ // Load embeddedCipher field of CipherBlockChaining object. ++ Node* embeddedCipherObj = load_field_from_object(objCTR, "embeddedCipher", "Lcom/sun/crypto/provider/SymmetricCipher;", /*is_exact*/ false); ++ ++ // get AESCrypt klass for instanceOf check ++ // AESCrypt might not be loaded yet if some other SymmetricCipher got us to this compile point ++ // will have same classloader as CipherBlockChaining object ++ const TypeInstPtr* tinst = _gvn.type(objCTR)->isa_instptr(); ++ assert(tinst != NULL, "CTRobj is null"); ++ assert(tinst->klass()->is_loaded(), "CTRobj is not loaded"); ++ ++ // we want to do an instanceof comparison against the AESCrypt class ++ ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); ++ if (!klass_AESCrypt->is_loaded()) { ++ // if AESCrypt is not even loaded, we never take the intrinsic fast path ++ Node* ctrl = control(); ++ set_control(top()); // no regular fast path ++ return ctrl; ++ } ++ ++ ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); ++ Node* instof = gen_instanceof(embeddedCipherObj, makecon(TypeKlassPtr::make(instklass_AESCrypt))); ++ Node* cmp_instof = _gvn.transform(new (C) CmpINode(instof, intcon(1))); ++ Node* bool_instof = _gvn.transform(new (C) BoolNode(cmp_instof, BoolTest::ne)); ++ Node* instof_false = generate_guard(bool_instof, NULL, PROB_MIN); ++ ++ return instof_false; // even if it is NULL ++} ++ + //------------------------------inline_ghash_processBlocks + bool LibraryCallKit::inline_ghash_processBlocks() { + address stubAddr; +diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp +index 0a86211ba..1c51be19b 100644 +--- a/hotspot/src/share/vm/opto/runtime.cpp ++++ b/hotspot/src/share/vm/opto/runtime.cpp +@@ -1021,6 +1021,35 @@ const TypeFunc* OptoRuntime::cipherBlockChaining_aescrypt_Type() { + return TypeFunc::make(domain, range); + } + ++//for counterMode calls of aescrypt encrypt/decrypt, four pointers and a length, returning int ++const TypeFunc* OptoRuntime::counterMode_aescrypt_Type() { ++ // create input type (domain) ++ int num_args = 7; ++ if (Matcher::pass_original_key_for_aes()) { ++ num_args = 8; ++ } ++ int argcnt = num_args; ++ const Type** fields = TypeTuple::fields(argcnt); ++ int argp = TypeFunc::Parms; ++ fields[argp++] = TypePtr::NOTNULL; // src ++ fields[argp++] = TypePtr::NOTNULL; // dest ++ fields[argp++] = TypePtr::NOTNULL; // k array ++ fields[argp++] = TypePtr::NOTNULL; // counter array ++ fields[argp++] = TypeInt::INT; // src len ++ fields[argp++] = TypePtr::NOTNULL; // saved_encCounter ++ fields[argp++] = TypePtr::NOTNULL; // saved used addr ++ if (Matcher::pass_original_key_for_aes()) { ++ fields[argp++] = TypePtr::NOTNULL; // original k array ++ } ++ assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); ++ const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); ++ // returning cipher len (int) ++ fields = TypeTuple::fields(1); ++ fields[TypeFunc::Parms + 0] = TypeInt::INT; ++ const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); ++ return TypeFunc::make(domain, range); ++} ++ + /* + * void implCompress(byte[] buf, int ofs) + */ +diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp +index 47133d58c..f27e7d507 100644 +--- a/hotspot/src/share/vm/opto/runtime.hpp ++++ b/hotspot/src/share/vm/opto/runtime.hpp +@@ -299,6 +299,7 @@ private: + + static const TypeFunc* aescrypt_block_Type(); + static const TypeFunc* cipherBlockChaining_aescrypt_Type(); ++ static const TypeFunc* counterMode_aescrypt_Type(); + + static const TypeFunc* sha_implCompress_Type(); + static const TypeFunc* digestBase_implCompressMB_Type(); +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 65dfcf69b..91e52f033 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -734,6 +734,9 @@ class CommandLineFlags { + product(bool, UseAESIntrinsics, false, \ + "Use intrinsics for AES versions of crypto") \ + \ ++ product(bool, UseAESCTRIntrinsics, false, \ ++ "Use intrinsics for the paralleled version of AES/CTR crypto") \ ++ \ + product(bool, UseSHA1Intrinsics, false, \ + "Use intrinsics for SHA-1 crypto hash function") \ + \ +diff --git a/hotspot/src/share/vm/runtime/stubRoutines.cpp b/hotspot/src/share/vm/runtime/stubRoutines.cpp +index f2106d13a..d66237137 100644 +--- a/hotspot/src/share/vm/runtime/stubRoutines.cpp ++++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp +@@ -124,6 +124,7 @@ address StubRoutines::_aescrypt_encryptBlock = NULL; + address StubRoutines::_aescrypt_decryptBlock = NULL; + address StubRoutines::_cipherBlockChaining_encryptAESCrypt = NULL; + address StubRoutines::_cipherBlockChaining_decryptAESCrypt = NULL; ++address StubRoutines::_counterMode_AESCrypt = NULL; + address StubRoutines::_ghash_processBlocks = NULL; + + address StubRoutines::_sha1_implCompress = NULL; +diff --git a/hotspot/src/share/vm/runtime/stubRoutines.hpp b/hotspot/src/share/vm/runtime/stubRoutines.hpp +index 16075d9f4..9fb589540 100644 +--- a/hotspot/src/share/vm/runtime/stubRoutines.hpp ++++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp +@@ -202,6 +202,7 @@ class StubRoutines: AllStatic { + static address _aescrypt_decryptBlock; + static address _cipherBlockChaining_encryptAESCrypt; + static address _cipherBlockChaining_decryptAESCrypt; ++ static address _counterMode_AESCrypt; + static address _ghash_processBlocks; + + static address _sha1_implCompress; +@@ -370,6 +371,7 @@ class StubRoutines: AllStatic { + static address aescrypt_decryptBlock() { return _aescrypt_decryptBlock; } + static address cipherBlockChaining_encryptAESCrypt() { return _cipherBlockChaining_encryptAESCrypt; } + static address cipherBlockChaining_decryptAESCrypt() { return _cipherBlockChaining_decryptAESCrypt; } ++ static address counterMode_AESCrypt() { return _counterMode_AESCrypt; } + static address ghash_processBlocks() { return _ghash_processBlocks; } + + static address sha1_implCompress() { return _sha1_implCompress; } +diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp +index 3f2bfeb74..842b5840d 100644 +--- a/hotspot/src/share/vm/runtime/vmStructs.cpp ++++ b/hotspot/src/share/vm/runtime/vmStructs.cpp +@@ -815,6 +815,7 @@ typedef TwoOopHashtable SymbolTwoOopHashtable; + static_field(StubRoutines, _aescrypt_decryptBlock, address) \ + static_field(StubRoutines, _cipherBlockChaining_encryptAESCrypt, address) \ + static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \ ++ static_field(StubRoutines, _counterMode_AESCrypt, address) \ + static_field(StubRoutines, _ghash_processBlocks, address) \ + static_field(StubRoutines, _updateBytesCRC32, address) \ + static_field(StubRoutines, _crc_table_adr, address) \ +diff --git a/hotspot/test/compiler/7184394/TestAESBase.java b/hotspot/test/compiler/7184394/TestAESBase.java +index 5c3e6881e..afda2a1f7 100644 +--- a/hotspot/test/compiler/7184394/TestAESBase.java ++++ b/hotspot/test/compiler/7184394/TestAESBase.java +@@ -106,8 +106,8 @@ abstract public class TestAESBase { + cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE"); + dCipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE"); + +- // CBC init +- if (mode.equals("CBC")) { ++ // CBC or CTR init ++ if (mode.equals("CBC") || mode.equals("CTR")) { + IvParameterSpec initVector = new IvParameterSpec(iv); + cipher.init(Cipher.ENCRYPT_MODE, key, initVector); + algParams = cipher.getParameters(); +diff --git a/hotspot/test/compiler/7184394/TestAESMain.java b/hotspot/test/compiler/7184394/TestAESMain.java +index ddd8eeaef..65949420a 100644 +--- a/hotspot/test/compiler/7184394/TestAESMain.java ++++ b/hotspot/test/compiler/7184394/TestAESMain.java +@@ -48,6 +48,13 @@ + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 -DpaddingStr=NoPadding -DmsgSize=640 TestAESMain ++ * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR TestAESMain ++ * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DencInputOffset=1 TestAESMain ++ * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DencOutputOffset=1 TestAESMain ++ * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DdecOutputOffset=1 TestAESMain ++ * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DencInputOffset=1 -DencOutputOffset=1 TestAESMain ++ * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 TestAESMain ++ * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 -DpaddingStr=NoPadding -DmsgSize=640 TestAESMain + * + * @author Tom Deneau + */ +diff --git a/jdk/src/share/classes/com/sun/crypto/provider/CounterMode.java b/jdk/src/share/classes/com/sun/crypto/provider/CounterMode.java +index aea9336c9..c2bd38a71 100644 +--- a/jdk/src/share/classes/com/sun/crypto/provider/CounterMode.java ++++ b/jdk/src/share/classes/com/sun/crypto/provider/CounterMode.java +@@ -39,10 +39,10 @@ import java.security.InvalidKeyException; + * @author Andreas Sterbenz + * @since 1.4.2 + */ +-final class CounterMode extends FeedbackCipher { ++class CounterMode extends FeedbackCipher { + + // current counter value +- private final byte[] counter; ++ final byte[] counter; + + // encrypted bytes of the previous counter value + private final byte[] encryptedCounter; +@@ -137,7 +137,7 @@ final class CounterMode extends FeedbackCipher { + * cipherOffset. + * + * @param in the buffer with the input data to be encrypted +- * @param inOffset the offset in plain ++ * @param inOff the offset in plain + * @param len the length of the input data + * @param out the buffer for the result + * @param outOff the offset in cipher +@@ -176,6 +176,11 @@ final class CounterMode extends FeedbackCipher { + RangeUtil.nullAndBoundsCheck(in, inOff, len); + RangeUtil.nullAndBoundsCheck(out, outOff, len); + ++ return implCrypt(in, inOff, len, out, outOff); ++ } ++ ++ // Implementation of crpyt() method. Possibly replaced with a compiler intrinsic. ++ private int implCrypt(byte[] in, int inOff, int len, byte[] out, int outOff) { + int result = len; + while (len-- > 0) { + if (used >= blockSize) { +diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java b/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java +index f8a3eaa0a..6a394e448 100644 +--- a/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java ++++ b/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2013, 2017 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -29,52 +29,43 @@ + + package com.sun.crypto.provider; + +-import java.security.*; +-import javax.crypto.*; ++import javax.crypto.IllegalBlockSizeException; + import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; + + /** + * This class represents the GCTR function defined in NIST 800-38D +- * under section 6.5. It needs to be constructed w/ an initialized +- * cipher object, and initial counter block(ICB). Given an input X +- * of arbitrary length, it processes and returns an output which has +- * the same length as X. The invariants of this class are: +- * +- * (1) The length of intialCounterBlk (and also of its clones, e.g., +- * fields counter and counterSave) is equal to AES_BLOCK_SIZE. +- * +- * (2) After construction, the field counter never becomes null, it +- * always contains a byte array of length AES_BLOCK_SIZE. ++ * under section 6.5. With a given cipher object and initial counter ++ * block, a counter mode operation is performed. Blocksize is limited ++ * to 16 bytes. + * + * If any invariant is broken, failures can occur because the + * AESCrypt.encryptBlock method can be intrinsified on the HotSpot VM + * (see JDK-8067648 for details). + * ++ * The counter mode operations can be intrinsified and parallelized ++ * by using CounterMode.implCrypt() if HotSpot VM supports it on the ++ * architecture. ++ * + *

This function is used in the implementation of GCM mode. + * + * @since 1.8 + */ +-final class GCTR { +- +- // these fields should not change after the object has been constructed +- private final SymmetricCipher aes; +- private final byte[] icb; +- +- // the current counter value +- private byte[] counter; ++final class GCTR extends CounterMode { + +- // needed for save/restore calls +- private byte[] counterSave = null; +- +- // NOTE: cipher should already be initialized + GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) { +- this.aes = cipher; ++ super(cipher); + if (initialCounterBlk.length != AES_BLOCK_SIZE) { + throw new RuntimeException("length of initial counter block (" + initialCounterBlk.length + + ") not equal to AES_BLOCK_SIZE (" + AES_BLOCK_SIZE + ")"); + } +- this.icb = initialCounterBlk; +- this.counter = icb.clone(); ++ ++ iv = initialCounterBlk; ++ reset(); ++ } ++ ++ @Override ++ String getFeedback() { ++ return "GCTR"; + } + + // input must be multiples of 128-bit blocks when calling update +@@ -89,23 +80,11 @@ final class GCTR { + throw new RuntimeException("output buffer too small"); + } + +- byte[] encryptedCntr = new byte[AES_BLOCK_SIZE]; +- +- int numOfCompleteBlocks = inLen / AES_BLOCK_SIZE; +- for (int i = 0; i < numOfCompleteBlocks; i++) { +- aes.encryptBlock(counter, 0, encryptedCntr, 0); +- for (int n = 0; n < AES_BLOCK_SIZE; n++) { +- int index = (i * AES_BLOCK_SIZE + n); +- out[outOfs + index] = +- (byte) ((in[inOfs + index] ^ encryptedCntr[n])); +- } +- GaloisCounterMode.increment32(counter); +- } +- return inLen; ++ return encrypt(in, inOfs, inLen, out, outOfs); + } + + // input can be arbitrary size when calling doFinal +- protected int doFinal(byte[] in, int inOfs, int inLen, byte[] out, ++ int doFinal(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) throws IllegalBlockSizeException { + try { + if (inLen < 0) { +@@ -118,7 +97,7 @@ final class GCTR { + if (lastBlockSize != 0) { + // do the last partial block + byte[] encryptedCntr = new byte[AES_BLOCK_SIZE]; +- aes.encryptBlock(counter, 0, encryptedCntr, 0); ++ embeddedCipher.encryptBlock(counter, 0, encryptedCntr, 0); + for (int n = 0; n < lastBlockSize; n++) { + out[outOfs + completeBlkLen + n] = + (byte) ((in[inOfs + completeBlkLen + n] ^ +@@ -131,28 +110,4 @@ final class GCTR { + } + return inLen; + } +- +- /** +- * Resets the content of this object to when it's first constructed. +- */ +- void reset() { +- System.arraycopy(icb, 0, counter, 0, icb.length); +- counterSave = null; +- } +- +- /** +- * Save the current content of this object. +- */ +- void save() { +- this.counterSave = this.counter.clone(); +- } +- +- /** +- * Restores the content of this object to the previous saved one. +- */ +- void restore() { +- if (this.counterSave != null) { +- this.counter = this.counterSave; +- } +- } + } +diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GHASH.java b/jdk/src/share/classes/com/sun/crypto/provider/GHASH.java +index dc42e6bbf..78f0723d7 100644 +--- a/jdk/src/share/classes/com/sun/crypto/provider/GHASH.java ++++ b/jdk/src/share/classes/com/sun/crypto/provider/GHASH.java +@@ -122,10 +122,10 @@ final class GHASH { + + } + +- /* subkeyH and state are stored in long[] for GHASH intrinsic use */ ++ /* subkeyHtbl and state are stored in long[] for GHASH intrinsic use */ + +- // hash subkey H; should not change after the object has been constructed +- private final long[] subkeyH; ++ // hashtable subkeyHtbl; holds 2*9 powers of subkeyH computed using carry-less multiplication ++ private long[] subkeyHtbl; + + // buffer for storing hash + private final long[] state; +@@ -147,9 +147,9 @@ final class GHASH { + throw new ProviderException("Internal error"); + } + state = new long[2]; +- this.subkeyH = new long[2]; +- this.subkeyH[0] = getLong(subkeyH, 0); +- this.subkeyH[1] = getLong(subkeyH, 8); ++ subkeyHtbl = new long[2*9]; ++ subkeyHtbl[0] = getLong(subkeyH, 0); ++ subkeyHtbl[1] = getLong(subkeyH, 8); + } + + /** +@@ -192,8 +192,8 @@ final class GHASH { + if (inLen == 0) { + return; + } +- ghashRangeCheck(in, inOfs, inLen, state, subkeyH); +- processBlocks(in, inOfs, inLen/AES_BLOCK_SIZE, state, subkeyH); ++ ghashRangeCheck(in, inOfs, inLen, state, subkeyHtbl); ++ processBlocks(in, inOfs, inLen/AES_BLOCK_SIZE, state, subkeyHtbl); + } + + private static void ghashRangeCheck(byte[] in, int inOfs, int inLen, long[] st, long[] subH) { +@@ -217,8 +217,8 @@ final class GHASH { + throw new RuntimeException("internal state has invalid length: " + + st.length); + } +- if (subH.length != 2) { +- throw new RuntimeException("internal subkeyH has invalid length: " + ++ if (subH.length != 18) { ++ throw new RuntimeException("internal subkeyHtbl has invalid length: " + + subH.length); + } + } +diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java +index ab93e3097..dd2618455 100644 +--- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java ++++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java +@@ -439,6 +439,8 @@ public final class SSLSocketImpl + if (!conContext.isNegotiated) { + readHandshakeRecord(); + } ++ } catch (InterruptedIOException iioe) { ++ handleException(iioe); + } catch (IOException ioe) { + throw conContext.fatal(Alert.HANDSHAKE_FAILURE, + "Couldn't kickstart handshaking", ioe); +@@ -1309,12 +1311,11 @@ public final class SSLSocketImpl + } + } catch (SSLException ssle) { + throw ssle; ++ } catch (InterruptedIOException iioe) { ++ // don't change exception in case of timeouts or interrupts ++ throw iioe; + } catch (IOException ioe) { +- if (!(ioe instanceof SSLException)) { +- throw new SSLException("readHandshakeRecord", ioe); +- } else { +- throw ioe; +- } ++ throw new SSLException("readHandshakeRecord", ioe); + } + } + +@@ -1375,6 +1376,9 @@ public final class SSLSocketImpl + } + } catch (SSLException ssle) { + throw ssle; ++ } catch (InterruptedIOException iioe) { ++ // don't change exception in case of timeouts or interrupts ++ throw iioe; + } catch (IOException ioe) { + if (!(ioe instanceof SSLException)) { + throw new SSLException("readApplicationRecord", ioe); +diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSocketInputRecord.java b/jdk/src/share/classes/sun/security/ssl/SSLSocketInputRecord.java +index 401822759..ab5712acc 100644 +--- a/jdk/src/share/classes/sun/security/ssl/SSLSocketInputRecord.java ++++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketInputRecord.java +@@ -26,6 +26,7 @@ + package sun.security.ssl; + + import java.io.EOFException; ++import java.io.InterruptedIOException; + import java.io.IOException; + import java.io.InputStream; + import java.io.OutputStream; +@@ -47,37 +48,31 @@ import sun.security.ssl.SSLCipher.SSLReadCipher; + final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + private InputStream is = null; + private OutputStream os = null; +- private final byte[] temporary = new byte[1024]; ++ private final byte[] header = new byte[headerSize]; ++ private int headerOff = 0; ++ // Cache for incomplete record body. ++ private ByteBuffer recordBody = ByteBuffer.allocate(1024); + + private boolean formatVerified = false; // SSLv2 ruled out? + + // Cache for incomplete handshake messages. + private ByteBuffer handshakeBuffer = null; + +- private boolean hasHeader = false; // Had read the record header +- + SSLSocketInputRecord(HandshakeHash handshakeHash) { + super(handshakeHash, SSLReadCipher.nullTlsReadCipher()); + } + + @Override + int bytesInCompletePacket() throws IOException { +- if (!hasHeader) { +- // read exactly one record +- try { +- int really = read(is, temporary, 0, headerSize); +- if (really < 0) { +- // EOF: peer shut down incorrectly +- return -1; +- } +- } catch (EOFException eofe) { +- // The caller will handle EOF. +- return -1; +- } +- hasHeader = true; ++ // read header ++ try { ++ readHeader(); ++ } catch (EOFException eofe) { ++ // The caller will handle EOF. ++ return -1; + } + +- byte byteZero = temporary[0]; ++ byte byteZero = header[0]; + int len = 0; + + /* +@@ -93,9 +88,9 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + * Last sanity check that it's not a wild record + */ + if (!ProtocolVersion.isNegotiable( +- temporary[1], temporary[2], false)) { ++ header[1], header[2], false)) { + throw new SSLException("Unrecognized record version " + +- ProtocolVersion.nameOf(temporary[1], temporary[2]) + ++ ProtocolVersion.nameOf(header[1], header[2]) + + " , plaintext connection?"); + } + +@@ -109,8 +104,8 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + /* + * One of the SSLv3/TLS message types. + */ +- len = ((temporary[3] & 0xFF) << 8) + +- (temporary[4] & 0xFF) + headerSize; ++ len = ((header[3] & 0xFF) << 8) + ++ (header[4] & 0xFF) + headerSize; + } else { + /* + * Must be SSLv2 or something unknown. +@@ -121,11 +116,11 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + */ + boolean isShort = ((byteZero & 0x80) != 0); + +- if (isShort && ((temporary[2] == 1) || (temporary[2] == 4))) { ++ if (isShort && ((header[2] == 1) || (header[2] == 4))) { + if (!ProtocolVersion.isNegotiable( +- temporary[3], temporary[4], false)) { ++ header[3], header[4], false)) { + throw new SSLException("Unrecognized record version " + +- ProtocolVersion.nameOf(temporary[3], temporary[4]) + ++ ProtocolVersion.nameOf(header[3], header[4]) + + " , plaintext connection?"); + } + +@@ -138,9 +133,9 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + // + // int mask = (isShort ? 0x7F : 0x3F); + // len = ((byteZero & mask) << 8) + +- // (temporary[1] & 0xFF) + (isShort ? 2 : 3); ++ // (header[1] & 0xFF) + (isShort ? 2 : 3); + // +- len = ((byteZero & 0x7F) << 8) + (temporary[1] & 0xFF) + 2; ++ len = ((byteZero & 0x7F) << 8) + (header[1] & 0xFF) + 2; + } else { + // Gobblygook! + throw new SSLException( +@@ -160,34 +155,41 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + return null; + } + +- if (!hasHeader) { +- // read exactly one record +- int really = read(is, temporary, 0, headerSize); +- if (really < 0) { +- throw new EOFException("SSL peer shut down incorrectly"); +- } +- hasHeader = true; +- } ++ // read header ++ readHeader(); + +- Plaintext plaintext = null; +- if (!formatVerified) { +- formatVerified = true; ++ Plaintext[] plaintext = null; ++ boolean cleanInBuffer = true; ++ try { ++ if (!formatVerified) { ++ formatVerified = true; + +- /* +- * The first record must either be a handshake record or an +- * alert message. If it's not, it is either invalid or an +- * SSLv2 message. +- */ +- if ((temporary[0] != ContentType.HANDSHAKE.id) && +- (temporary[0] != ContentType.ALERT.id)) { +- hasHeader = false; +- return handleUnknownRecord(temporary); ++ /* ++ * The first record must either be a handshake record or an ++ * alert message. If it's not, it is either invalid or an ++ * SSLv2 message. ++ */ ++ if ((header[0] != ContentType.HANDSHAKE.id) && ++ (header[0] != ContentType.ALERT.id)) { ++ plaintext = handleUnknownRecord(); ++ } + } +- } + +- // The record header should has consumed. +- hasHeader = false; +- return decodeInputRecord(temporary); ++ // The record header should has consumed. ++ if (plaintext == null) { ++ plaintext = decodeInputRecord(); ++ } ++ } catch(InterruptedIOException e) { ++ // do not clean header and recordBody in case of Socket Timeout ++ cleanInBuffer = false; ++ throw e; ++ } finally { ++ if (cleanInBuffer) { ++ headerOff = 0; ++ recordBody.clear(); ++ } ++ } ++ return plaintext; + } + + @Override +@@ -200,9 +202,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + this.os = outputStream; + } + +- // Note that destination may be null +- private Plaintext[] decodeInputRecord( +- byte[] header) throws IOException, BadPaddingException { ++ private Plaintext[] decodeInputRecord() throws IOException, BadPaddingException { + byte contentType = header[0]; // pos: 0 + byte majorVersion = header[1]; // pos: 1 + byte minorVersion = header[2]; // pos: 2 +@@ -227,30 +227,27 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + } + + // +- // Read a complete record. ++ // Read a complete record and store in the recordBody ++ // recordBody is used to cache incoming record and restore in case of ++ // read operation timedout + // +- ByteBuffer destination = ByteBuffer.allocate(headerSize + contentLen); +- int dstPos = destination.position(); +- destination.put(temporary, 0, headerSize); +- while (contentLen > 0) { +- int howmuch = Math.min(temporary.length, contentLen); +- int really = read(is, temporary, 0, howmuch); +- if (really < 0) { +- throw new EOFException("SSL peer shut down incorrectly"); ++ if (recordBody.position() == 0) { ++ if (recordBody.capacity() < contentLen) { ++ recordBody = ByteBuffer.allocate(contentLen); + } +- +- destination.put(temporary, 0, howmuch); +- contentLen -= howmuch; ++ recordBody.limit(contentLen); ++ } else { ++ contentLen = recordBody.remaining(); + } +- destination.flip(); +- destination.position(dstPos + headerSize); ++ readFully(contentLen); ++ recordBody.flip(); + + if (SSLLogger.isOn && SSLLogger.isOn("record")) { + SSLLogger.fine( + "READ: " + + ProtocolVersion.nameOf(majorVersion, minorVersion) + + " " + ContentType.nameOf(contentType) + ", length = " + +- destination.remaining()); ++ recordBody.remaining()); + } + + // +@@ -259,7 +256,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + ByteBuffer fragment; + try { + Plaintext plaintext = +- readCipher.decrypt(contentType, destination, null); ++ readCipher.decrypt(contentType, recordBody, null); + fragment = plaintext.fragment; + contentType = plaintext.contentType; + } catch (BadPaddingException bpe) { +@@ -368,8 +365,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + }; + } + +- private Plaintext[] handleUnknownRecord( +- byte[] header) throws IOException, BadPaddingException { ++ private Plaintext[] handleUnknownRecord() throws IOException, BadPaddingException { + byte firstByte = header[0]; + byte thirdByte = header[2]; + +@@ -411,32 +407,29 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + } + + int msgLen = ((header[0] & 0x7F) << 8) | (header[1] & 0xFF); +- +- ByteBuffer destination = ByteBuffer.allocate(headerSize + msgLen); +- destination.put(temporary, 0, headerSize); +- msgLen -= 3; // had read 3 bytes of content as header +- while (msgLen > 0) { +- int howmuch = Math.min(temporary.length, msgLen); +- int really = read(is, temporary, 0, howmuch); +- if (really < 0) { +- throw new EOFException("SSL peer shut down incorrectly"); ++ if (recordBody.position() == 0) { ++ if (recordBody.capacity() < (headerSize + msgLen)) { ++ recordBody = ByteBuffer.allocate(headerSize + msgLen); + } +- +- destination.put(temporary, 0, howmuch); +- msgLen -= howmuch; ++ recordBody.limit(headerSize + msgLen); ++ recordBody.put(header, 0, headerSize); ++ } else { ++ msgLen = recordBody.remaining(); + } +- destination.flip(); ++ msgLen -= 3; // had read 3 bytes of content as header ++ readFully(msgLen); ++ recordBody.flip(); + + /* + * If we can map this into a V3 ClientHello, read and + * hash the rest of the V2 handshake, turn it into a + * V3 ClientHello message, and pass it up. + */ +- destination.position(2); // exclude the header +- handshakeHash.receive(destination); +- destination.position(0); ++ recordBody.position(2); // exclude the header ++ handshakeHash.receive(recordBody); ++ recordBody.position(0); + +- ByteBuffer converted = convertToClientHello(destination); ++ ByteBuffer converted = convertToClientHello(recordBody); + + if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + SSLLogger.fine( +@@ -456,28 +449,42 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { + } + } + +- // Read the exact bytes of data, otherwise, return -1. +- private static int read(InputStream is, +- byte[] buffer, int offset, int len) throws IOException { +- int n = 0; +- while (n < len) { +- int readLen = is.read(buffer, offset + n, len - n); +- if (readLen < 0) { +- if (SSLLogger.isOn && SSLLogger.isOn("packet")) { +- SSLLogger.fine("Raw read: EOF"); +- } +- return -1; ++ // Read the exact bytes of data, otherwise, throw IOException. ++ private int readFully(int len) throws IOException { ++ int end = len + recordBody.position(); ++ int off = recordBody.position(); ++ try { ++ while (off < end) { ++ off += read(is, recordBody.array(), off, end - off); + } ++ } finally { ++ recordBody.position(off); ++ } ++ return len; ++ } ++ ++ // Read SSE record header, otherwise, throw IOException. ++ private int readHeader() throws IOException { ++ while (headerOff < headerSize) { ++ headerOff += read(is, header, headerOff, headerSize - headerOff); ++ } ++ return headerSize; ++ } + ++ private static int read(InputStream is, byte[] buf, int off, int len) throws IOException { ++ int readLen = is.read(buf, off, len); ++ if (readLen < 0) { + if (SSLLogger.isOn && SSLLogger.isOn("packet")) { +- ByteBuffer bb = ByteBuffer.wrap(buffer, offset + n, readLen); +- SSLLogger.fine("Raw read", bb); ++ SSLLogger.fine("Raw read: EOF"); + } +- +- n += readLen; ++ throw new EOFException("SSL peer shut down incorrectly"); + } + +- return n; ++ if (SSLLogger.isOn && SSLLogger.isOn("packet")) { ++ ByteBuffer bb = ByteBuffer.wrap(buf, off, readLen); ++ SSLLogger.fine("Raw read", bb); ++ } ++ return readLen; + } + + // Try to use up the input stream without impact the performance too much. +diff --git a/jdk/src/share/classes/sun/security/ssl/SSLTransport.java b/jdk/src/share/classes/sun/security/ssl/SSLTransport.java +index b3d03b370..78e13ea2c 100644 +--- a/jdk/src/share/classes/sun/security/ssl/SSLTransport.java ++++ b/jdk/src/share/classes/sun/security/ssl/SSLTransport.java +@@ -27,6 +27,7 @@ package sun.security.ssl; + + import java.io.EOFException; + import java.io.IOException; ++import java.io.InterruptedIOException; + import java.nio.ByteBuffer; + import javax.crypto.AEADBadTagException; + import javax.crypto.BadPaddingException; +@@ -134,6 +135,9 @@ interface SSLTransport { + } catch (EOFException eofe) { + // rethrow EOFException, the call will handle it if neede. + throw eofe; ++ } catch (InterruptedIOException iioe) { ++ // don't close the Socket in case of timeouts or interrupts. ++ throw iioe; + } catch (IOException ioe) { + throw context.fatal(Alert.UNEXPECTED_MESSAGE, ioe); + } +diff --git a/jdk/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMBench.java b/jdk/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMBench.java +new file mode 100644 +index 000000000..258672f59 +--- /dev/null ++++ b/jdk/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMBench.java +@@ -0,0 +1,128 @@ ++/* ++ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openjdk.bench.javax.crypto.full; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++ ++import javax.crypto.Cipher; ++import javax.crypto.spec.GCMParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++ ++/** ++ * This performance tests runs AES/GCM encryption and decryption using byte[] ++ * as input and output buffers for single and multi-part testing. ++ * ++ * This test rotates the IV and creates a new GCMParameterSpec for each encrypt ++ * benchmark operation ++ */ ++ ++public class AESGCMBench extends CryptoBase { ++ ++ @Param({"128"}) ++ private int keyLength; ++ ++ @Param({"1024", "1500", "4096", "16384"}) ++ private int dataSize; ++ ++ byte[] encryptedData; ++ byte[] in, out; ++ private Cipher encryptCipher; ++ private Cipher decryptCipher; ++ SecretKeySpec ks; ++ GCMParameterSpec gcm_spec; ++ byte[] iv; ++ ++ private static final int IV_BUFFER_SIZE = 32; ++ private static final int IV_MODULO = IV_BUFFER_SIZE - 16; ++ int iv_index = 0; ++ int updateLen = 0; ++ ++ private int next_iv_index() { ++ int r = iv_index; ++ iv_index = (iv_index + 1) % IV_MODULO; ++ return r; ++ } ++ ++ @Setup ++ public void setup() throws Exception { ++ setupProvider(); ++ ++ // Setup key material ++ byte[] keystring = fillSecureRandom(new byte[keyLength / 8]); ++ ks = new SecretKeySpec(keystring, "AES"); ++ iv = fillSecureRandom(new byte[IV_BUFFER_SIZE]); ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ ++ // Setup Cipher classes ++ encryptCipher = makeCipher(prov, "AES/GCM/NoPadding"); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ decryptCipher = makeCipher(prov, "AES/GCM/NoPadding"); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, ++ encryptCipher.getParameters(). ++ getParameterSpec(GCMParameterSpec.class)); ++ ++ // Setup input/output buffers ++ in = fillRandom(new byte[dataSize]); ++ encryptedData = new byte[encryptCipher.getOutputSize(in.length)]; ++ out = new byte[encryptedData.length]; ++ encryptCipher.doFinal(in, 0, in.length, encryptedData, 0); ++ updateLen = in.length / 2; ++ ++ } ++ ++ @Benchmark ++ public void encrypt() throws Exception { ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ encryptCipher.doFinal(in, 0, in.length, out, 0); ++ } ++ ++ @Benchmark ++ public void encryptMultiPart() throws Exception { ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ int outOfs = encryptCipher.update(in, 0, updateLen, out, 0); ++ encryptCipher.doFinal(in, updateLen, in.length - updateLen, ++ out, outOfs); ++ } ++ ++ @Benchmark ++ public void decrypt() throws Exception { ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, ++ encryptCipher.getParameters(). ++ getParameterSpec(GCMParameterSpec.class)); ++ decryptCipher.doFinal(encryptedData, 0, encryptedData.length, out, 0); ++ } ++ ++ @Benchmark ++ public void decryptMultiPart() throws Exception { ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, ++ encryptCipher.getParameters(). ++ getParameterSpec(GCMParameterSpec.class)); ++ decryptCipher.update(encryptedData, 0, updateLen, out, 0); ++ decryptCipher.doFinal(encryptedData, updateLen, ++ encryptedData.length - updateLen, out, 0); ++ } ++} +\ No newline at end of file +diff --git a/jdk/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMByteBuffer.java b/jdk/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMByteBuffer.java +new file mode 100644 +index 000000000..cb6d20c51 +--- /dev/null ++++ b/jdk/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMByteBuffer.java +@@ -0,0 +1,163 @@ ++/* ++ * Copyright (c) 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 org.openjdk.bench.javax.crypto.full; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++ ++import javax.crypto.Cipher; ++import javax.crypto.spec.GCMParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++import java.nio.ByteBuffer; ++ ++/** ++ * This performance tests runs AES/GCM encryption and decryption using heap and ++ * direct ByteBuffers as input and output buffers for single and multi-part ++ * operations. ++ * ++ * This test rotates the IV and creates a new GCMParameterSpec for each encrypt ++ * benchmark operation ++ */ ++ ++public class AESGCMByteBuffer extends CryptoBase { ++ ++ @Param({"128"}) ++ private int keyLength; ++ ++ @Param({"1024", "1500", "4096", "16384"}) ++ private int dataSize; ++ ++ @Param({"direct", "heap"}) ++ private String dataMethod; ++ ++ byte[] data; ++ ByteBuffer encryptedData; ++ ByteBuffer in, out; ++ private Cipher encryptCipher; ++ private Cipher decryptCipher; ++ SecretKeySpec ks; ++ GCMParameterSpec gcm_spec; ++ byte[] iv; ++ ++ private static final int IV_BUFFER_SIZE = 32; ++ private static final int IV_MODULO = IV_BUFFER_SIZE - 16; ++ int iv_index = 0; ++ int updateLen = 0; ++ ++ private int next_iv_index() { ++ int r = iv_index; ++ iv_index = (iv_index + 1) % IV_MODULO; ++ return r; ++ } ++ ++ @Setup ++ public void setup() throws Exception { ++ setupProvider(); ++ ++ // Setup key material ++ byte[] keystring = fillSecureRandom(new byte[keyLength / 8]); ++ ks = new SecretKeySpec(keystring, "AES"); ++ iv = fillSecureRandom(new byte[IV_BUFFER_SIZE]); ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ ++ // Setup Cipher classes ++ encryptCipher = makeCipher(prov, "AES/GCM/NoPadding"); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ decryptCipher = makeCipher(prov, "AES/GCM/NoPadding"); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, ++ encryptCipher.getParameters(). ++ getParameterSpec(GCMParameterSpec.class)); ++ ++ // Setup input/output buffers ++ data = fillRandom(new byte[dataSize]); ++ if (dataMethod.equalsIgnoreCase("direct")) { ++ in = ByteBuffer.allocateDirect(data.length); ++ in.put(data); ++ in.flip(); ++ encryptedData = ByteBuffer.allocateDirect( ++ encryptCipher.getOutputSize(data.length)); ++ out = ByteBuffer.allocateDirect(encryptedData.capacity()); ++ } else if (dataMethod.equalsIgnoreCase("heap")) { ++ in = ByteBuffer.wrap(data); ++ encryptedData = ByteBuffer.allocate( ++ encryptCipher.getOutputSize(data.length)); ++ out = ByteBuffer.allocate(encryptedData.capacity()); ++ } ++ ++ encryptCipher.doFinal(in, encryptedData); ++ encryptedData.flip(); ++ in.flip(); ++ updateLen = in.remaining() / 2; ++ } ++ ++ @Benchmark ++ public void encrypt() throws Exception { ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ encryptCipher.doFinal(in, out); ++ out.flip(); ++ in.flip(); ++ } ++ ++ @Benchmark ++ public void encryptMultiPart() throws Exception { ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ in.limit(updateLen); ++ encryptCipher.update(in, out); ++ in.limit(in.capacity()); ++ encryptCipher.doFinal(in, out); ++ out.flip(); ++ in.flip(); ++ } ++ ++ @Benchmark ++ public void decrypt() throws Exception { ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, ++ encryptCipher.getParameters(). ++ getParameterSpec(GCMParameterSpec.class)); ++ decryptCipher.doFinal(encryptedData, out); ++ encryptedData.flip(); ++ out.flip(); ++ } ++ ++ @Benchmark ++ public void decryptMultiPart() throws Exception { ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, ++ encryptCipher.getParameters(). ++ getParameterSpec(GCMParameterSpec.class)); ++ ++ int len = encryptedData.remaining(); ++ encryptedData.limit(updateLen); ++ decryptCipher.update(encryptedData, out); ++ encryptedData.limit(len); ++ ++ decryptCipher.doFinal(encryptedData, out); ++ encryptedData.flip(); ++ out.flip(); ++ } ++ ++} +\ No newline at end of file +diff --git a/jdk/test/micro/org/openjdk/bench/javax/crypto/full/CryptoBase.java b/jdk/test/micro/org/openjdk/bench/javax/crypto/full/CryptoBase.java +new file mode 100644 +index 000000000..4af12703b +--- /dev/null ++++ b/jdk/test/micro/org/openjdk/bench/javax/crypto/full/CryptoBase.java +@@ -0,0 +1,102 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openjdk.bench.javax.crypto.full; ++ ++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 javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import javax.crypto.NoSuchPaddingException; ++import java.security.NoSuchAlgorithmException; ++import java.security.Provider; ++import java.security.SecureRandom; ++import java.security.Security; ++import java.util.Random; ++import java.util.concurrent.TimeUnit; ++ ++ ++@Fork(jvmArgsAppend = {"-XX:+AlwaysPreTouch"}, value = 5) ++@Warmup(iterations = 3, time = 3) ++@Measurement(iterations = 8, time = 2) ++@OutputTimeUnit(TimeUnit.SECONDS) ++@State(Scope.Thread) ++@BenchmarkMode(Mode.Throughput) ++public class CryptoBase { ++ ++ @Param({""}) ++ private String provider; ++ ++ public Provider prov = null; ++ ++ @Setup ++ public void setupProvider() { ++ if (provider != null && !provider.isEmpty()) { ++ prov = Security.getProvider(provider); ++ if (prov == null) { ++ throw new RuntimeException("Can't find prodiver \"" + provider + "\""); ++ } ++ } ++ } ++ ++ public static Cipher makeCipher(Provider prov, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException { ++ return (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ } ++ ++ public static byte[][] fillRandom(byte[][] data) { ++ Random rnd = new Random(); ++ for (byte[] d : data) { ++ rnd.nextBytes(d); ++ } ++ return data; ++ } ++ ++ public static byte[] fillRandom(byte[] data) { ++ Random rnd = new Random(); ++ rnd.nextBytes(data); ++ return data; ++ } ++ ++ public static byte[] fillSecureRandom(byte[] data) { ++ SecureRandom rnd = new SecureRandom(); ++ rnd.nextBytes(data); ++ return data; ++ } ++ ++ public static byte[][] fillEncrypted(byte[][] data, Cipher encryptCipher) throws BadPaddingException, IllegalBlockSizeException { ++ byte[][] encryptedData = new byte[data.length][]; ++ for (int i = 0; i < encryptedData.length; i++) { ++ encryptedData[i] = encryptCipher.doFinal(data[i]); ++ } ++ return encryptedData; ++ } ++} +\ No newline at end of file +diff --git a/jdk/test/micro/org/openjdk/bench/javax/crypto/small/AESGCMBench.java b/jdk/test/micro/org/openjdk/bench/javax/crypto/small/AESGCMBench.java +new file mode 100644 +index 000000000..a21b0c87f +--- /dev/null ++++ b/jdk/test/micro/org/openjdk/bench/javax/crypto/small/AESGCMBench.java +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openjdk.bench.javax.crypto.small; ++ ++import org.openjdk.jmh.annotations.Param; ++ ++public class AESGCMBench extends ++ org.openjdk.bench.javax.crypto.full.AESGCMBench { ++ ++ @Param({"128"}) ++ private int keyLength; ++ ++ @Param({"1024"}) ++ private int dataSize; ++ ++} +\ No newline at end of file +diff --git a/jdk/test/micro/org/openjdk/bench/javax/crypto/small/AESGCMByteBuffer.java b/jdk/test/micro/org/openjdk/bench/javax/crypto/small/AESGCMByteBuffer.java +new file mode 100644 +index 000000000..2e389d300 +--- /dev/null ++++ b/jdk/test/micro/org/openjdk/bench/javax/crypto/small/AESGCMByteBuffer.java +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openjdk.bench.javax.crypto.small; ++ ++import org.openjdk.jmh.annotations.Param; ++ ++public class AESGCMByteBuffer extends ++ org.openjdk.bench.javax.crypto.full.AESGCMByteBuffer { ++ ++ @Param({"128"}) ++ private int keyLength; ++ ++ @Param({"1024"}) ++ private int dataSize; ++ ++} +\ No newline at end of file +diff --git a/jdk/test/sun/security/ssl/SSLSocketImpl/ClientTimeout.java b/jdk/test/sun/security/ssl/SSLSocketImpl/ClientTimeout.java +index 3eb1d7b89..7678cc71f 100644 +--- a/jdk/test/sun/security/ssl/SSLSocketImpl/ClientTimeout.java ++++ b/jdk/test/sun/security/ssl/SSLSocketImpl/ClientTimeout.java +@@ -26,8 +26,7 @@ + + /* + * @test +- * @bug 4836493 +- * @ignore need further evaluation ++ * @bug 4836493 8239798 + * @summary Socket timeouts for SSLSockets causes data corruption. + * @run main/othervm ClientTimeout + */ +diff --git a/jdk/test/sun/security/ssl/SSLSocketImpl/SSLExceptionForIOIssue.java b/jdk/test/sun/security/ssl/SSLSocketImpl/SSLExceptionForIOIssue.java +index 3e626a257..5578ea725 100644 +--- a/jdk/test/sun/security/ssl/SSLSocketImpl/SSLExceptionForIOIssue.java ++++ b/jdk/test/sun/security/ssl/SSLSocketImpl/SSLExceptionForIOIssue.java +@@ -36,7 +36,7 @@ + + import javax.net.ssl.*; + import java.io.*; +-import java.net.InetAddress; ++import java.net.*; + + public class SSLExceptionForIOIssue implements SSLContextTemplate { + +@@ -139,7 +139,7 @@ public class SSLExceptionForIOIssue implements SSLContextTemplate { + } catch (SSLProtocolException | SSLHandshakeException sslhe) { + clientException = sslhe; + System.err.println("unexpected client exception: " + sslhe); +- } catch (SSLException ssle) { ++ } catch (SSLException | SocketTimeoutException ssle) { + // the expected exception, ignore it + System.err.println("expected client exception: " + ssle); + } catch (Exception e) { +-- +2.17.1 + diff --git a/8159720-Failure-of-C2-compilation-with-tiered-preven.patch b/8159720-Failure-of-C2-compilation-with-tiered-preven.patch new file mode 100644 index 0000000000000000000000000000000000000000..a52d0c90a81ef183ecc162b86487ce0d0e75d5b2 --- /dev/null +++ b/8159720-Failure-of-C2-compilation-with-tiered-preven.patch @@ -0,0 +1,114 @@ +From 717ae5f43045b1e2d6f95c52fbd81c54ebf50977 Mon Sep 17 00:00:00 2001 +Date: Fri, 16 Sep 2022 01:12:20 +0000 +Subject: 8159720: Failure of C2 compilation with tiered prevents some + C1 compilations. + +--- + hotspot/src/share/vm/opto/compile.cpp | 2 +- + hotspot/src/share/vm/opto/compile.hpp | 10 +++------- + hotspot/src/share/vm/opto/matcher.cpp | 8 ++++---- + hotspot/src/share/vm/opto/parse1.cpp | 4 ++-- + 4 files changed, 10 insertions(+), 14 deletions(-) + +diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp +index 5a42422e1..4a32e8a9f 100644 +--- a/hotspot/src/share/vm/opto/compile.cpp ++++ b/hotspot/src/share/vm/opto/compile.cpp +@@ -791,7 +791,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr + } + if (failing()) return; + if (cg == NULL) { +- record_method_not_compilable_all_tiers("cannot parse method"); ++ record_method_not_compilable("cannot parse method"); + return; + } + JVMState* jvms = build_start_state(start(), tf()); +diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp +index 1150fd549..fb12b6874 100644 +--- a/hotspot/src/share/vm/opto/compile.hpp ++++ b/hotspot/src/share/vm/opto/compile.hpp +@@ -742,16 +742,12 @@ class Compile : public Phase { + bool failure_reason_is(const char* r) { return (r==_failure_reason) || (r!=NULL && _failure_reason!=NULL && strcmp(r, _failure_reason)==0); } + + void record_failure(const char* reason); +- void record_method_not_compilable(const char* reason, bool all_tiers = false) { +- // All bailouts cover "all_tiers" when TieredCompilation is off. +- if (!TieredCompilation) all_tiers = true; +- env()->record_method_not_compilable(reason, all_tiers); ++ void record_method_not_compilable(const char* reason) { ++ // Bailouts cover "all_tiers" when TieredCompilation is off. ++ env()->record_method_not_compilable(reason, !TieredCompilation); + // Record failure reason. + record_failure(reason); + } +- void record_method_not_compilable_all_tiers(const char* reason) { +- record_method_not_compilable(reason, true); +- } + bool check_node_count(uint margin, const char* reason) { + if (live_nodes() + margin > max_node_limit()) { + record_method_not_compilable(reason); +diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp +index 07b8ee4c6..b26015ce6 100644 +--- a/hotspot/src/share/vm/opto/matcher.cpp ++++ b/hotspot/src/share/vm/opto/matcher.cpp +@@ -137,7 +137,7 @@ OptoReg::Name Matcher::warp_incoming_stk_arg( VMReg reg ) { + _in_arg_limit = OptoReg::add(warped, 1); // Bump max stack slot seen + if (!RegMask::can_represent_arg(warped)) { + // the compiler cannot represent this method's calling sequence +- C->record_method_not_compilable_all_tiers("unsupported incoming calling sequence"); ++ C->record_method_not_compilable("unsupported incoming calling sequence"); + return OptoReg::Bad; + } + return warped; +@@ -1148,7 +1148,7 @@ OptoReg::Name Matcher::warp_outgoing_stk_arg( VMReg reg, OptoReg::Name begin_out + if( warped >= out_arg_limit_per_call ) + out_arg_limit_per_call = OptoReg::add(warped,1); + if (!RegMask::can_represent_arg(warped)) { +- C->record_method_not_compilable_all_tiers("unsupported calling sequence"); ++ C->record_method_not_compilable("unsupported calling sequence"); + return OptoReg::Bad; + } + return warped; +@@ -1327,7 +1327,7 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { + uint r_cnt = mcall->tf()->range()->cnt(); + MachProjNode *proj = new (C) MachProjNode( mcall, r_cnt+10000, RegMask::Empty, MachProjNode::fat_proj ); + if (!RegMask::can_represent_arg(OptoReg::Name(out_arg_limit_per_call-1))) { +- C->record_method_not_compilable_all_tiers("unsupported outgoing calling sequence"); ++ C->record_method_not_compilable("unsupported outgoing calling sequence"); + } else { + for (int i = begin_out_arg_area; i < out_arg_limit_per_call; i++) + proj->_rout.Insert(OptoReg::Name(i)); +@@ -1515,7 +1515,7 @@ Node *Matcher::Label_Root( const Node *n, State *svec, Node *control, const Node + // out of stack space. See bugs 6272980 & 6227033 for more info. + LabelRootDepth++; + if (LabelRootDepth > MaxLabelRootDepth) { +- C->record_method_not_compilable_all_tiers("Out of stack space, increase MaxLabelRootDepth"); ++ C->record_method_not_compilable("Out of stack space, increase MaxLabelRootDepth"); + return NULL; + } + uint care = 0; // Edges matcher cares about +diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp +index a9ef4f910..4fcd58cb4 100644 +--- a/hotspot/src/share/vm/opto/parse1.cpp ++++ b/hotspot/src/share/vm/opto/parse1.cpp +@@ -415,7 +415,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) + _iter.reset_to_method(method()); + _flow = method()->get_flow_analysis(); + if (_flow->failing()) { +- C->record_method_not_compilable_all_tiers(_flow->failure_reason()); ++ C->record_method_not_compilable(_flow->failure_reason()); + } + + #ifndef PRODUCT +@@ -1088,7 +1088,7 @@ SafePointNode* Parse::create_entry_map() { + // Check for really stupid bail-out cases. + uint len = TypeFunc::Parms + method()->max_locals() + method()->max_stack(); + if (len >= 32760) { +- C->record_method_not_compilable_all_tiers("too many local variables"); ++ C->record_method_not_compilable("too many local variables"); + return NULL; + } + +-- +2.18.0.huawei.25 + diff --git a/8168926.patch b/8168926.patch deleted file mode 100644 index 2eef8859afc511bf16dda001ba30f870fd750b38..0000000000000000000000000000000000000000 --- a/8168926.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 72853c670c97aae4eab64a5e9edb3c7176beaf6a Mon Sep 17 00:00:00 2001 -Date: Fri, 22 Jan 2021 16:36:41 +0800 -Subject: 8168926: C2: Bytecode escape analyzer crashes due to - stack overflow - -Summary: :8168926: C2: Bytecode escape analyzer crashes due to stack overflow -LLT: N/A -Bug url: https://bugs.openjdk.java.net/browse/JDK-8168926 ---- - hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp | 30 ++++++++++++++++++-- - hotspot/src/share/vm/ci/ciMethod.hpp | 12 +++++--- - 2 files changed, 35 insertions(+), 7 deletions(-) - -diff --git a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp -index 2b9e0e514..34bdbe94d 100644 ---- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp -+++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp -@@ -894,9 +894,33 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl - ciMethod* target = s.get_method(ignored_will_link, &declared_signature); - ciKlass* holder = s.get_declared_method_holder(); - assert(declared_signature != NULL, "cannot be null"); -- // Push appendix argument, if one. -- if (s.has_appendix()) { -- state.apush(unknown_obj); -+ // If the current bytecode has an attached appendix argument, -+ // push an unknown object to represent that argument. (Analysis -+ // of dynamic call sites, especially invokehandle calls, needs -+ // the appendix argument on the stack, in addition to "regular" arguments -+ // pushed onto the stack by bytecode instructions preceding the call.) -+ // -+ // The escape analyzer does _not_ use the ciBytecodeStream::has_appendix(s) -+ // method to determine whether the current bytecode has an appendix argument. -+ // The has_appendix() method obtains the appendix from the -+ // ConstantPoolCacheEntry::_f1 field, which can happen concurrently with -+ // resolution of dynamic call sites. Callees in the -+ // ciBytecodeStream::get_method() call above also access the _f1 field; -+ // interleaving the get_method() and has_appendix() calls in the current -+ // method with call site resolution can lead to an inconsistent view of -+ // the current method's argument count. In particular, some interleaving(s) -+ // can cause the method's argument count to not include the appendix, which -+ // then leads to stack over-/underflow in the escape analyzer. -+ // -+ // Instead of pushing the argument if has_appendix() is true, the escape analyzer -+ // pushes an appendix for all call sites targeted by invokedynamic and invokehandle -+ // instructions, except if the call site is the _invokeBasic intrinsic -+ // (that intrinsic is always targeted by an invokehandle instruction but does -+ // not have an appendix argument). -+ if (target->is_loaded() && -+ Bytecodes::has_optional_appendix(s.cur_bc_raw()) && -+ target->intrinsic_id() != vmIntrinsics::_invokeBasic) { -+ state.apush(unknown_obj); - } - // Pass in raw bytecode because we need to see invokehandle instructions. - invoke(state, s.cur_bc_raw(), target, holder); -diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp -index 307452422..99d8dbe67 100644 ---- a/hotspot/src/share/vm/ci/ciMethod.hpp -+++ b/hotspot/src/share/vm/ci/ciMethod.hpp -@@ -133,15 +133,19 @@ class ciMethod : public ciMetadata { - check_is_loaded(); - return _signature->size() + (_flags.is_static() ? 0 : 1); - } -- // Report the number of elements on stack when invoking this method. -- // This is different than the regular arg_size because invokedynamic -- // has an implicit receiver. -+ // Report the number of elements on stack when invoking the current method. -+ // If the method is loaded, arg_size() gives precise information about the -+ // number of stack elements (using the method's signature and its flags). -+ // However, if the method is not loaded, the number of stack elements must -+ // be determined differently, as the method's flags are not yet available. -+ // The invoke_arg_size() method assumes in that case that all bytecodes except -+ // invokestatic and invokedynamic have a receiver that is also pushed onto the -+ // stack by the caller of the current method. - int invoke_arg_size(Bytecodes::Code code) const { - if (is_loaded()) { - return arg_size(); - } else { - int arg_size = _signature->size(); -- // Add a receiver argument, maybe: - if (code != Bytecodes::_invokestatic && - code != Bytecodes::_invokedynamic) { - arg_size++; --- -2.19.0 - diff --git a/8173361-various-crashes-in-JvmtiExport-post_compiled.patch b/8173361-various-crashes-in-JvmtiExport-post_compiled.patch deleted file mode 100755 index 2b14cc7a333bce48c10049f12810d85d683adb50..0000000000000000000000000000000000000000 --- a/8173361-various-crashes-in-JvmtiExport-post_compiled.patch +++ /dev/null @@ -1,290 +0,0 @@ -diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp -index 175c195c6..01e878022 100644 ---- a/hotspot/src/share/vm/code/nmethod.cpp -+++ b/hotspot/src/share/vm/code/nmethod.cpp -@@ -1656,24 +1656,28 @@ bool nmethod::can_unload(BoolObjectClosure* is_alive, oop* root, bool unloading_ - // Transfer information from compilation to jvmti - void nmethod::post_compiled_method_load_event() { - -- Method* moop = method(); -+ // This is a bad time for a safepoint. We don't want -+ // this nmethod to get unloaded while we're queueing the event. -+ No_Safepoint_Verifier nsv; -+ -+ Method* m = method(); - #ifndef USDT2 - HS_DTRACE_PROBE8(hotspot, compiled__method__load, -- moop->klass_name()->bytes(), -- moop->klass_name()->utf8_length(), -- moop->name()->bytes(), -- moop->name()->utf8_length(), -- moop->signature()->bytes(), -- moop->signature()->utf8_length(), -+ m->klass_name()->bytes(), -+ m->klass_name()->utf8_length(), -+ m->name()->bytes(), -+ m->name()->utf8_length(), -+ m->signature()->bytes(), -+ m->signature()->utf8_length(), - insts_begin(), insts_size()); - #else /* USDT2 */ - HOTSPOT_COMPILED_METHOD_LOAD( -- (char *) moop->klass_name()->bytes(), -- moop->klass_name()->utf8_length(), -- (char *) moop->name()->bytes(), -- moop->name()->utf8_length(), -- (char *) moop->signature()->bytes(), -- moop->signature()->utf8_length(), -+ (char *) m->klass_name()->bytes(), -+ m->klass_name()->utf8_length(), -+ (char *) m->name()->bytes(), -+ m->name()->utf8_length(), -+ (char *) m->signature()->bytes(), -+ m->signature()->utf8_length(), - insts_begin(), insts_size()); - #endif /* USDT2 */ - -diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp -index 895fbbf07..367c9a09d 100644 ---- a/hotspot/src/share/vm/oops/instanceKlass.cpp -+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp -@@ -1786,7 +1786,7 @@ jmethodID InstanceKlass::get_jmethod_id(instanceKlassHandle ik_h, methodHandle m - // we're single threaded or at a safepoint - no locking needed - get_jmethod_id_length_value(jmeths, idnum, &length, &id); - } else { -- MutexLocker ml(JmethodIdCreation_lock); -+ MutexLockerEx ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag); - get_jmethod_id_length_value(jmeths, idnum, &length, &id); - } - } -@@ -1836,7 +1836,7 @@ jmethodID InstanceKlass::get_jmethod_id(instanceKlassHandle ik_h, methodHandle m - id = get_jmethod_id_fetch_or_update(ik_h, idnum, new_id, new_jmeths, - &to_dealloc_id, &to_dealloc_jmeths); - } else { -- MutexLocker ml(JmethodIdCreation_lock); -+ MutexLockerEx ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag); - id = get_jmethod_id_fetch_or_update(ik_h, idnum, new_id, new_jmeths, - &to_dealloc_id, &to_dealloc_jmeths); - } -diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp -index 9b612598f..967ed200d 100644 ---- a/hotspot/src/share/vm/prims/jvmtiExport.cpp -+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp -@@ -1754,7 +1754,7 @@ jvmtiCompiledMethodLoadInlineRecord* create_inline_record(nmethod* nm) { - int stackframe = 0; - for(ScopeDesc* sd = nm->scope_desc_at(p->real_pc(nm));sd != NULL;sd = sd->sender()) { - // sd->method() can be NULL for stubs but not for nmethods. To be completely robust, include an assert that we should never see a null sd->method() -- assert(sd->method() != NULL, "sd->method() cannot be null."); -+ guarantee(sd->method() != NULL, "sd->method() cannot be null."); - record->pcinfo[scope].methods[stackframe] = sd->method()->jmethod_id(); - record->pcinfo[scope].bcis[stackframe] = sd->bci(); - stackframe++; -diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.cpp b/hotspot/src/share/vm/prims/jvmtiImpl.cpp -index 3c66b1671..3bcd15ed6 100644 ---- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp -+++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp -@@ -897,9 +897,6 @@ JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event( - nmethod* nm) { - JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD); - event._event_data.compiled_method_load = nm; -- // Keep the nmethod alive until the ServiceThread can process -- // this deferred event. -- nmethodLocker::lock_nmethod(nm); - return event; - } - -@@ -932,14 +929,12 @@ JvmtiDeferredEvent JvmtiDeferredEvent::dynamic_code_generated_event( - } - - void JvmtiDeferredEvent::post() { -- assert(ServiceThread::is_service_thread(Thread::current()), -+ assert(Thread::current()->is_service_thread(), - "Service thread must post enqueued events"); - switch(_type) { - case TYPE_COMPILED_METHOD_LOAD: { - nmethod* nm = _event_data.compiled_method_load; - JvmtiExport::post_compiled_method_load(nm); -- // done with the deferred event so unlock the nmethod -- nmethodLocker::unlock_nmethod(nm); - break; - } - case TYPE_COMPILED_METHOD_UNLOAD: { -@@ -969,6 +964,21 @@ void JvmtiDeferredEvent::post() { - } - } - -+// Keep the nmethod for compiled_method_load from being unloaded. -+void JvmtiDeferredEvent::oops_do(OopClosure* f, CodeBlobClosure* cf) { -+ if (cf != NULL && _type == TYPE_COMPILED_METHOD_LOAD) { -+ cf->do_code_blob(_event_data.compiled_method_load); -+ } -+} -+ -+// The sweeper calls this and marks the nmethods here on the stack so that -+// they cannot be turned into zombies while in the queue. -+void JvmtiDeferredEvent::nmethods_do(CodeBlobClosure* cf) { -+ if (cf != NULL && _type == TYPE_COMPILED_METHOD_LOAD) { -+ cf->do_code_blob(_event_data.compiled_method_load); -+ } // May add UNLOAD event but it doesn't work yet. -+} -+ - JvmtiDeferredEventQueue::QueueNode* JvmtiDeferredEventQueue::_queue_tail = NULL; - JvmtiDeferredEventQueue::QueueNode* JvmtiDeferredEventQueue::_queue_head = NULL; - -@@ -1084,3 +1094,15 @@ void JvmtiDeferredEventQueue::process_pending_events() { - } - } - } -+ -+void JvmtiDeferredEventQueue::oops_do(OopClosure* f, CodeBlobClosure* cf) { -+ for(QueueNode* node = _queue_head; node != NULL; node = node->next()) { -+ node->event().oops_do(f, cf); -+ } -+} -+ -+void JvmtiDeferredEventQueue::nmethods_do(CodeBlobClosure* cf) { -+ for(QueueNode* node = _queue_head; node != NULL; node = node->next()) { -+ node->event().nmethods_do(cf); -+ } -+} -diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.hpp b/hotspot/src/share/vm/prims/jvmtiImpl.hpp -index 9f36f28fb..d74789451 100644 ---- a/hotspot/src/share/vm/prims/jvmtiImpl.hpp -+++ b/hotspot/src/share/vm/prims/jvmtiImpl.hpp -@@ -492,6 +492,10 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC { - - // Actually posts the event. - void post() NOT_JVMTI_RETURN; -+ // Sweeper support to keep nmethods from being zombied while in the queue. -+ void nmethods_do(CodeBlobClosure* cf); -+ // GC support to keep nmethod from being unloaded while in the queue. -+ void oops_do(OopClosure* f, CodeBlobClosure* cf); - }; - - /** -@@ -511,7 +515,7 @@ class JvmtiDeferredEventQueue : AllStatic { - QueueNode(const JvmtiDeferredEvent& event) - : _event(event), _next(NULL) {} - -- const JvmtiDeferredEvent& event() const { return _event; } -+ JvmtiDeferredEvent& event() { return _event; } - QueueNode* next() const { return _next; } - - void set_next(QueueNode* next) { _next = next; } -@@ -529,6 +533,10 @@ class JvmtiDeferredEventQueue : AllStatic { - static bool has_events() NOT_JVMTI_RETURN_(false); - static void enqueue(const JvmtiDeferredEvent& event) NOT_JVMTI_RETURN; - static JvmtiDeferredEvent dequeue() NOT_JVMTI_RETURN_(JvmtiDeferredEvent()); -+ // Sweeper support to keep nmethods from being zombied while in the queue. -+ static void nmethods_do(CodeBlobClosure* cf); -+ // GC support to keep nmethod from being unloaded while in the queue. -+ static void oops_do(OopClosure* f, CodeBlobClosure* cf); - - // Used to enqueue events without using a lock, for times (such as during - // safepoint) when we can't or don't want to lock the Service_lock. -diff --git a/hotspot/src/share/vm/runtime/serviceThread.cpp b/hotspot/src/share/vm/runtime/serviceThread.cpp -index c3a2b88a5..a2a32ad2b 100644 ---- a/hotspot/src/share/vm/runtime/serviceThread.cpp -+++ b/hotspot/src/share/vm/runtime/serviceThread.cpp -@@ -34,6 +34,7 @@ - #include "services/diagnosticFramework.hpp" - - ServiceThread* ServiceThread::_instance = NULL; -+JvmtiDeferredEvent* ServiceThread::_jvmti_event = NULL; - - void ServiceThread::initialize() { - EXCEPTION_MARK; -@@ -112,12 +113,15 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { - } - - if (has_jvmti_events) { -+ // Get the event under the Service_lock - jvmti_event = JvmtiDeferredEventQueue::dequeue(); -+ _jvmti_event = &jvmti_event; - } - } - - if (has_jvmti_events) { -- jvmti_event.post(); -+ _jvmti_event->post(); -+ _jvmti_event = NULL; // reset - } - - if (sensors_changed) { -@@ -138,6 +142,26 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { - } - } - --bool ServiceThread::is_service_thread(Thread* thread) { -- return thread == _instance; -+void ServiceThread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) { -+ JavaThread::oops_do(f, cld_f, cf); -+ // The ServiceThread "owns" the JVMTI Deferred events, scan them here -+ // to keep them alive until they are processed. -+ if (cf != NULL) { -+ if (_jvmti_event != NULL) { -+ _jvmti_event->oops_do(f, cf); -+ } -+ MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); -+ JvmtiDeferredEventQueue::oops_do(f, cf); -+ } -+} -+ -+void ServiceThread::nmethods_do(CodeBlobClosure* cf) { -+ JavaThread::nmethods_do(cf); -+ if (cf != NULL) { -+ if (_jvmti_event != NULL) { -+ _jvmti_event->nmethods_do(cf); -+ } -+ MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); -+ JvmtiDeferredEventQueue::nmethods_do(cf); -+ } - } -diff --git a/hotspot/src/share/vm/runtime/serviceThread.hpp b/hotspot/src/share/vm/runtime/serviceThread.hpp -index 42373e6f7..a9c219580 100644 ---- a/hotspot/src/share/vm/runtime/serviceThread.hpp -+++ b/hotspot/src/share/vm/runtime/serviceThread.hpp -@@ -29,11 +29,13 @@ - - // A JavaThread for low memory detection support and JVMTI - // compiled-method-load events. -+class JvmtiDeferredEvent; -+ - class ServiceThread : public JavaThread { - friend class VMStructs; - private: -- - static ServiceThread* _instance; -+ static JvmtiDeferredEvent* _jvmti_event; - - static void service_thread_entry(JavaThread* thread, TRAPS); - ServiceThread(ThreadFunction entry_point) : JavaThread(entry_point) {}; -@@ -43,9 +45,11 @@ class ServiceThread : public JavaThread { - - // Hide this thread from external view. - bool is_hidden_from_external_view() const { return true; } -+ bool is_service_thread() const { return true; } - -- // Returns true if the passed thread is the service thread. -- static bool is_service_thread(Thread* thread); -+ // GC support -+ void oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf); -+ void nmethods_do(CodeBlobClosure* cf); - }; - - #endif // SHARE_VM_RUNTIME_SERVICETHREAD_HPP -diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp -index cc976182d..950c1b4fa 100644 ---- a/hotspot/src/share/vm/runtime/thread.hpp -+++ b/hotspot/src/share/vm/runtime/thread.hpp -@@ -313,6 +313,7 @@ class Thread: public ThreadShadow { - virtual bool is_VM_thread() const { return false; } - virtual bool is_Java_thread() const { return false; } - virtual bool is_Compiler_thread() const { return false; } -+ virtual bool is_service_thread() const { return false; } - virtual bool is_hidden_from_external_view() const { return false; } - virtual bool is_jvmti_agent_thread() const { return false; } - // True iff the thread can perform GC operations at a safepoint. --- -2.22.0 - diff --git a/8194154.patch b/8194154.patch deleted file mode 100644 index 0adbad3e0f5aa4cf01e72b87e0f1957539147602..0000000000000000000000000000000000000000 --- a/8194154.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 5547d1f77577ad8514136255eed16921e4d02845 Mon Sep 17 00:00:00 2001 -Date: Fri, 22 Jan 2021 15:23:47 +0800 -Subject: 8194154: System property user.dir should not be changed - -Summary: : System property user.dir should not be changed -LLT: jdk/test/java/io/File/UserDirChangedTest.java -Bug url: https://bugs.openjdk.java.net/browse/JDK-8194154 ---- - .../classes/java/io/UnixFileSystem.java | 11 +++- - .../classes/java/io/WinNTFileSystem.java | 11 +++- - jdk/test/java/io/File/UserDirChangedTest.java | 51 +++++++++++++++++++ - 3 files changed, 69 insertions(+), 4 deletions(-) - create mode 100644 jdk/test/java/io/File/UserDirChangedTest.java - -diff --git a/jdk/src/solaris/classes/java/io/UnixFileSystem.java b/jdk/src/solaris/classes/java/io/UnixFileSystem.java -index fb0fef636..a6ef2d3a6 100644 ---- a/jdk/src/solaris/classes/java/io/UnixFileSystem.java -+++ b/jdk/src/solaris/classes/java/io/UnixFileSystem.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -34,6 +34,7 @@ class UnixFileSystem extends FileSystem { - private final char slash; - private final char colon; - private final String javaHome; -+ private final String userDir; - - public UnixFileSystem() { - slash = AccessController.doPrivileged( -@@ -42,6 +43,8 @@ class UnixFileSystem extends FileSystem { - new GetPropertyAction("path.separator")).charAt(0); - javaHome = AccessController.doPrivileged( - new GetPropertyAction("java.home")); -+ userDir = AccessController.doPrivileged( -+ new GetPropertyAction("user.dir")); - } - - -@@ -130,7 +133,11 @@ class UnixFileSystem extends FileSystem { - - public String resolve(File f) { - if (isAbsolute(f)) return f.getPath(); -- return resolve(System.getProperty("user.dir"), f.getPath()); -+ SecurityManager sm = System.getSecurityManager(); -+ if (sm != null) { -+ sm.checkPropertyAccess("user.dir"); -+ } -+ return resolve(userDir, f.getPath()); - } - - // Caches for canonicalization results to improve startup performance. -diff --git a/jdk/src/windows/classes/java/io/WinNTFileSystem.java b/jdk/src/windows/classes/java/io/WinNTFileSystem.java -index caa47f80c..1844a662a 100644 ---- a/jdk/src/windows/classes/java/io/WinNTFileSystem.java -+++ b/jdk/src/windows/classes/java/io/WinNTFileSystem.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -40,6 +40,7 @@ class WinNTFileSystem extends FileSystem { - private final char slash; - private final char altSlash; - private final char semicolon; -+ private final String userDir; - - public WinNTFileSystem() { - slash = AccessController.doPrivileged( -@@ -47,6 +48,8 @@ class WinNTFileSystem extends FileSystem { - semicolon = AccessController.doPrivileged( - new GetPropertyAction("path.separator")).charAt(0); - altSlash = (this.slash == '\\') ? '/' : '\\'; -+ userDir = AccessController.doPrivileged( -+ new GetPropertyAction("user.dir")); - } - - private boolean isSlash(char c) { -@@ -343,7 +346,11 @@ class WinNTFileSystem extends FileSystem { - private String getUserPath() { - /* For both compatibility and security, - we must look this up every time */ -- return normalize(System.getProperty("user.dir")); -+ SecurityManager sm = System.getSecurityManager(); -+ if (sm != null) { -+ sm.checkPropertyAccess("user.dir"); -+ } -+ return normalize(userDir); - } - - private String getDrive(String path) { -diff --git a/jdk/test/java/io/File/UserDirChangedTest.java b/jdk/test/java/io/File/UserDirChangedTest.java -new file mode 100644 -index 000000000..9eccb768e ---- /dev/null -+++ b/jdk/test/java/io/File/UserDirChangedTest.java -@@ -0,0 +1,51 @@ -+/* -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -+ * -+ * This code is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 only, as -+ * published by the Free Software Foundation. -+ * -+ * This code is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * version 2 for more details (a copy is included in the LICENSE file that -+ * accompanied this code). -+ * -+ * You should have received a copy of the GNU General Public License version -+ * 2 along with this work; if not, write to the Free Software Foundation, -+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -+ * or visit www.oracle.com if you need additional information or have any -+ * questions. -+ */ -+ -+/* @test -+ @bug 8194154 -+ @summary Test changing property user.dir on impacting getCanonicalPath -+ @run main/othervm UserDirChangedTest -+ */ -+ -+import java.io.File; -+ -+public class UserDirChangedTest { -+ public static void main(String[] args) throws Exception { -+ String keyUserDir = "user.dir"; -+ String userDirNew = "/home/a/b/c/"; -+ String fileName = "./a"; -+ -+ String userDir = System.getProperty(keyUserDir); -+ File file = new File(fileName); -+ String canFilePath = file.getCanonicalPath(); -+ -+ // now reset user.dir, this will cause crash on linux without bug 8194154 fixed. -+ System.setProperty(keyUserDir, userDirNew); -+ String newCanFilePath = file.getCanonicalPath(); -+ System.out.format("%24s %48s%n", "Canonical Path = ", canFilePath); -+ System.out.format("%24s %48s%n", "new Canonical Path = ", newCanFilePath); -+ if (!canFilePath.equals(newCanFilePath)) { -+ throw new RuntimeException("Changing property user.dir should have no effect on getCanonicalPath"); -+ } -+ } -+} --- -2.19.0 - diff --git a/8200332-Improve-GCM-counting.patch b/8200332-Improve-GCM-counting.patch new file mode 100644 index 0000000000000000000000000000000000000000..5990053ab1c82aab9e0c5f2a4136cb5450bf1a52 --- /dev/null +++ b/8200332-Improve-GCM-counting.patch @@ -0,0 +1,68 @@ +From 30883daeac796c877a765cedee52f27f51444203 Mon Sep 17 00:00:00 2001 +Date: Thu, 8 Sep 2022 10:22:32 +0800 +Subject: 8200332: Improve GCM counting + +Bug url: https://bugs.openjdk.org/browse/JDK-8200332 +--- + .../classes/com/sun/crypto/provider/GCTR.java | 31 ++++++++++++++++++- + 1 file changed, 30 insertions(+), 1 deletion(-) + +diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java b/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java +index 6a394e448..1ab0f63db 100644 +--- a/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java ++++ b/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java +@@ -29,6 +29,8 @@ + + package com.sun.crypto.provider; + ++import java.nio.ByteBuffer; ++import java.nio.ByteOrder; + import javax.crypto.IllegalBlockSizeException; + import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; + +@@ -68,6 +70,15 @@ final class GCTR extends CounterMode { + return "GCTR"; + } + ++ // return the number of blocks until the lower 32 bits roll over ++ private long blocksUntilRollover() { ++ ByteBuffer buf = ByteBuffer.wrap(counter, counter.length - 4, 4); ++ buf.order(ByteOrder.BIG_ENDIAN); ++ long ctr32 = 0xFFFFFFFFL & buf.getInt(); ++ long blocksLeft = (1L << 32) - ctr32; ++ return blocksLeft; ++ } ++ + // input must be multiples of 128-bit blocks when calling update + int update(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) { + if (inLen - inOfs > in.length) { +@@ -80,7 +91,25 @@ final class GCTR extends CounterMode { + throw new RuntimeException("output buffer too small"); + } + +- return encrypt(in, inOfs, inLen, out, outOfs); ++ long blocksLeft = blocksUntilRollover(); ++ int numOfCompleteBlocks = inLen / AES_BLOCK_SIZE; ++ if (numOfCompleteBlocks >= blocksLeft) { ++ // Counter Mode encryption cannot be used because counter will ++ // roll over incorrectly. Use GCM-specific code instead. ++ byte[] encryptedCntr = new byte[AES_BLOCK_SIZE]; ++ for (int i = 0; i < numOfCompleteBlocks; i++) { ++ embeddedCipher.encryptBlock(counter, 0, encryptedCntr, 0); ++ for (int n = 0; n < AES_BLOCK_SIZE; n++) { ++ int index = (i * AES_BLOCK_SIZE + n); ++ out[outOfs + index] = ++ (byte) ((in[inOfs + index] ^ encryptedCntr[n])); ++ } ++ GaloisCounterMode.increment32(counter); ++ } ++ return inLen; ++ } else { ++ return encrypt(in, inOfs, inLen, out, outOfs); ++ } + } + + // input can be arbitrary size when calling doFinal +-- +2.22.0 + diff --git a/8202142-jfr-event-io-TestInstrumentation-is-unstable.patch b/8202142-jfr-event-io-TestInstrumentation-is-unstable.patch deleted file mode 100755 index 6c10c0a559d0a8d58e98c6330089d1f9e5b8a4f8..0000000000000000000000000000000000000000 --- a/8202142-jfr-event-io-TestInstrumentation-is-unstable.patch +++ /dev/null @@ -1,1185 +0,0 @@ -From baadf220d261a6c610920d749a2b9c19f864ba96 Mon Sep 17 00:00:00 2001 -From: wuyan -Date: Sat, 11 Sep 2021 10:07:53 +0800 -Subject: [PATCH 20/23] 8202142: jfr/event/io/TestInstrumentation is unstable - -Summary: : JDK-8202142: jfr/event/io/TestInstrumentation is unstable -LLT: jdk/test/jdk/jfr/event/io/TestInstrumentation.java -Patch Type: backport -Bug url: https://bugs.openjdk.java.net/browse/JDK-8202142 ---- - jdk/test/jdk/jfr/event/io/IOEvent.java | 9 +- - jdk/test/jdk/jfr/event/io/IOHelper.java | 8 +- - .../jdk/jfr/event/io/TestDisabledEvents.java | 33 +-- - .../jfr/event/io/TestFileChannelEvents.java | 138 +++++------ - .../jdk/jfr/event/io/TestFileReadOnly.java | 77 +++--- - .../jfr/event/io/TestFileStreamEvents.java | 69 +++--- - .../jdk/jfr/event/io/TestInstrumentation.java | 4 +- - .../event/io/TestRandomAccessFileEvents.java | 115 ++++----- - .../event/io/TestRandomAccessFileThread.java | 222 +++++++++--------- - .../jfr/event/io/TestSocketChannelEvents.java | 122 +++++----- - .../jdk/jfr/event/io/TestSocketEvents.java | 104 ++++---- - 11 files changed, 455 insertions(+), 446 deletions(-) - -diff --git a/jdk/test/jdk/jfr/event/io/IOEvent.java b/jdk/test/jdk/jfr/event/io/IOEvent.java -index e3939fbf8..dcf70ccc3 100644 ---- a/jdk/test/jdk/jfr/event/io/IOEvent.java -+++ b/jdk/test/jdk/jfr/event/io/IOEvent.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -197,14 +197,11 @@ public class IOEvent { - } - return canonical_path; - } else { -- return String.format("%s/%s:%d", -- event.getValue("host"), -- event.getValue("address"), -- event.getValue("port")); -+ return event.getValue("address") + ":" + event.getValue("port"); - } - } - - private static String getAddress(Socket s) { -- return s.getInetAddress().toString() + ":" + s.getPort(); -+ return s.getInetAddress().getHostAddress() + ":" + s.getPort(); - } - } -diff --git a/jdk/test/jdk/jfr/event/io/IOHelper.java b/jdk/test/jdk/jfr/event/io/IOHelper.java -index f1f205529..23e61f59a 100644 ---- a/jdk/test/jdk/jfr/event/io/IOHelper.java -+++ b/jdk/test/jdk/jfr/event/io/IOHelper.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -28,6 +28,8 @@ package jdk.jfr.event.io; - import static jdk.test.lib.Asserts.assertEquals; - import static jdk.test.lib.Asserts.assertTrue; - -+import java.util.Collections; -+import java.util.Comparator; - import java.util.List; - import java.util.stream.Collectors; - -@@ -41,6 +43,7 @@ import jdk.test.lib.jfr.Events; - public class IOHelper { - - public static void verifyEqualsInOrder(List events, List expectedEvents) throws Throwable { -+ Collections.sort(events, Comparator.comparing(RecordedEvent::getStartTime)); - List actualEvents = getTestEvents(events, expectedEvents); - try { - assertEquals(actualEvents.size(), expectedEvents.size(), "Wrong number of events."); -@@ -48,6 +51,9 @@ public class IOHelper { - assertEquals(actualEvents.get(i), expectedEvents.get(i), "Wrong event at pos " + i); - } - } catch (Throwable t) { -+ for (RecordedEvent e: events) { -+ System.out.println(e); -+ } - logEvents(actualEvents, expectedEvents); - throw t; - } -diff --git a/jdk/test/jdk/jfr/event/io/TestDisabledEvents.java b/jdk/test/jdk/jfr/event/io/TestDisabledEvents.java -index aad1b217f..d80304cf0 100644 ---- a/jdk/test/jdk/jfr/event/io/TestDisabledEvents.java -+++ b/jdk/test/jdk/jfr/event/io/TestDisabledEvents.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -57,21 +57,22 @@ public class TestDisabledEvents { - public static void main(String[] args) throws Throwable { - File tmp = File.createTempFile("TestDisabledEvents", ".tmp", new File(".")); - tmp.deleteOnExit(); -- Recording recording = new Recording(); -- recording.disable(IOEvent.EVENT_FILE_READ); -- recording.disable(IOEvent.EVENT_FILE_WRITE); -- recording.start(); -- -- useRandomAccessFile(tmp); -- useFileStreams(tmp); -- useFileChannel(tmp); -- -- recording.stop(); -- for (RecordedEvent event : Events.fromRecording(recording)) { -- final String eventName = event.getEventType().getName(); -- System.out.println("Got eventName:" + eventName); -- assertNotEquals(eventName, IOEvent.EVENT_FILE_READ, "Got disabled read event"); -- assertNotEquals(eventName, IOEvent.EVENT_FILE_WRITE, "Got disabled write event"); -+ try (Recording recording = new Recording()) { -+ recording.disable(IOEvent.EVENT_FILE_READ); -+ recording.disable(IOEvent.EVENT_FILE_WRITE); -+ recording.start(); -+ -+ useRandomAccessFile(tmp); -+ useFileStreams(tmp); -+ useFileChannel(tmp); -+ -+ recording.stop(); -+ for (RecordedEvent event : Events.fromRecording(recording)) { -+ final String eventName = event.getEventType().getName(); -+ System.out.println("Got eventName:" + eventName); -+ assertNotEquals(eventName, IOEvent.EVENT_FILE_READ, "Got disabled read event"); -+ assertNotEquals(eventName, IOEvent.EVENT_FILE_WRITE, "Got disabled write event"); -+ } - } - } - -diff --git a/jdk/test/jdk/jfr/event/io/TestFileChannelEvents.java b/jdk/test/jdk/jfr/event/io/TestFileChannelEvents.java -index cb90bc54f..632fcaba3 100644 ---- a/jdk/test/jdk/jfr/event/io/TestFileChannelEvents.java -+++ b/jdk/test/jdk/jfr/event/io/TestFileChannelEvents.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -50,74 +50,74 @@ public class TestFileChannelEvents { - public static void main(String[] args) throws Throwable { - File tmp = File.createTempFile("TestFileChannelEvents", ".tmp", new File(".")); - tmp.deleteOnExit(); -- Recording recording = new Recording(); -- List expectedEvents = new ArrayList<>(); -- -- try (RandomAccessFile rf = new RandomAccessFile(tmp, "rw"); FileChannel ch = rf.getChannel();) { -- recording.enable(IOEvent.EVENT_FILE_FORCE).withThreshold(Duration.ofMillis(0)); -- recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0)); -- recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0)); -- recording.start(); -- -- ByteBuffer bufA = ByteBuffer.allocateDirect(10); -- ByteBuffer bufB = ByteBuffer.allocateDirect(20); -- bufA.put("1234567890".getBytes()); -- bufB.put("1234567890".getBytes()); -- -- // test write(ByteBuffer) -- bufA.flip(); -- long size = ch.write(bufA); -- expectedEvents.add(IOEvent.createFileWriteEvent(size, tmp)); -- -- // test write(ByteBuffer, long) -- bufA.flip(); -- size = ch.write(bufA, bufA.capacity() / 2); -- expectedEvents.add(IOEvent.createFileWriteEvent(size, tmp)); -- -- // test write(ByteBuffer[]) -- bufA.flip(); -- bufA.limit(5); -- bufB.flip(); -- bufB.limit(5); -- size = ch.write(new ByteBuffer[] { bufA, bufB }); -- expectedEvents.add(IOEvent.createFileWriteEvent(size, tmp)); -- -- // test force(boolean) -- ch.force(true); -- expectedEvents.add(IOEvent.createFileForceEvent(tmp)); -- -- // reset file -- ch.position(0); -- -- // test read(ByteBuffer) -- bufA.clear(); -- size = ch.read(bufA); -- expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -- -- // test read(ByteBuffer, long) -- bufA.clear(); -- size = ch.read(bufA, bufA.capacity() / 2); -- expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -- -- // test read(ByteBuffer[]) -- bufA.clear(); -- bufA.limit(5); -- bufB.clear(); -- bufB.limit(5); -- size = ch.read(new ByteBuffer[] { bufA, bufB }); -- expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -- -- // Read at EOF. Should get size -1 in event. -- ch.position(ch.size()); -- bufA.clear(); -- size = ch.read(bufA); -- assertEquals(size, -1L, "Expected size -1 when read at EOF"); -- expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -- -- ch.close(); -- recording.stop(); -- List events = Events.fromRecording(recording); -- IOHelper.verifyEqualsInOrder(events, expectedEvents); -+ try (Recording recording = new Recording()) { -+ List expectedEvents = new ArrayList<>(); -+ try (RandomAccessFile rf = new RandomAccessFile(tmp, "rw"); FileChannel ch = rf.getChannel();) { -+ recording.enable(IOEvent.EVENT_FILE_FORCE).withThreshold(Duration.ofMillis(0)); -+ recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0)); -+ recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0)); -+ recording.start(); -+ -+ ByteBuffer bufA = ByteBuffer.allocateDirect(10); -+ ByteBuffer bufB = ByteBuffer.allocateDirect(20); -+ bufA.put("1234567890".getBytes()); -+ bufB.put("1234567890".getBytes()); -+ -+ // test write(ByteBuffer) -+ bufA.flip(); -+ long size = ch.write(bufA); -+ expectedEvents.add(IOEvent.createFileWriteEvent(size, tmp)); -+ -+ // test write(ByteBuffer, long) -+ bufA.flip(); -+ size = ch.write(bufA, bufA.capacity() / 2); -+ expectedEvents.add(IOEvent.createFileWriteEvent(size, tmp)); -+ -+ // test write(ByteBuffer[]) -+ bufA.flip(); -+ bufA.limit(5); -+ bufB.flip(); -+ bufB.limit(5); -+ size = ch.write(new ByteBuffer[] { bufA, bufB }); -+ expectedEvents.add(IOEvent.createFileWriteEvent(size, tmp)); -+ -+ // test force(boolean) -+ ch.force(true); -+ expectedEvents.add(IOEvent.createFileForceEvent(tmp)); -+ -+ // reset file -+ ch.position(0); -+ -+ // test read(ByteBuffer) -+ bufA.clear(); -+ size = ch.read(bufA); -+ expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -+ -+ // test read(ByteBuffer, long) -+ bufA.clear(); -+ size = ch.read(bufA, bufA.capacity() / 2); -+ expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -+ -+ // test read(ByteBuffer[]) -+ bufA.clear(); -+ bufA.limit(5); -+ bufB.clear(); -+ bufB.limit(5); -+ size = ch.read(new ByteBuffer[] { bufA, bufB }); -+ expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -+ -+ // Read at EOF. Should get size -1 in event. -+ ch.position(ch.size()); -+ bufA.clear(); -+ size = ch.read(bufA); -+ assertEquals(size, -1L, "Expected size -1 when read at EOF"); -+ expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -+ -+ ch.close(); -+ recording.stop(); -+ List events = Events.fromRecording(recording); -+ IOHelper.verifyEqualsInOrder(events, expectedEvents); -+ } - } - } - } -diff --git a/jdk/test/jdk/jfr/event/io/TestFileReadOnly.java b/jdk/test/jdk/jfr/event/io/TestFileReadOnly.java -index 065ebadc3..b7e20d0ef 100644 ---- a/jdk/test/jdk/jfr/event/io/TestFileReadOnly.java -+++ b/jdk/test/jdk/jfr/event/io/TestFileReadOnly.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -52,50 +52,51 @@ public class TestFileReadOnly { - public static void main(String[] args) throws Throwable { - File tmp = File.createTempFile("TestFileReadOnly", ".tmp", new File(".")); - tmp.deleteOnExit(); -- Recording recording = new Recording(); -- List expectedEvents = new ArrayList<>(); -+ try(Recording recording = new Recording()) { -+ List expectedEvents = new ArrayList<>(); - -- recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0)); -- recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0)); -- recording.start(); -+ recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0)); -+ recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0)); -+ recording.start(); - -- final byte[] buf = { 1, 2, 3 }; -+ final byte[] buf = { 1, 2, 3 }; - -- // Create the file. -- try (RandomAccessFile f = new RandomAccessFile(tmp, "rw")) { -- f.write(buf); -- expectedEvents.add(IOEvent.createFileWriteEvent(buf.length, tmp)); -- } -- -- // Reopen the file as ReadOnly and try to write to it. -- // Should generate an event with bytesWritten = -1. -- try (RandomAccessFile f = new RandomAccessFile(tmp, "r")) { -- try { -+ // Create the file. -+ try (RandomAccessFile f = new RandomAccessFile(tmp, "rw")) { - f.write(buf); -- fail("No exception for ReadOnly File"); -- } catch (IOException e) { -- // Expected exception -- expectedEvents.add(IOEvent.createFileWriteEvent(-1, tmp)); -+ expectedEvents.add(IOEvent.createFileWriteEvent(buf.length, tmp)); - } -- } - -- // Try to write to read-only FileChannel. -- try (RandomAccessFile f = new RandomAccessFile(tmp, "r"); FileChannel ch = f.getChannel()) { -- ByteBuffer writeBuf = ByteBuffer.allocateDirect(buf.length); -- writeBuf.put(buf); -- writeBuf.flip(); -- ch.position(0); -- try { -- ch.write(writeBuf); -- fail("No exception for ReadOnly FileChannel"); -- } catch (java.nio.channels.NonWritableChannelException e) { -- // Expected exception -- expectedEvents.add(IOEvent.createFileWriteEvent(-1, tmp)); -+ // Reopen the file as ReadOnly and try to write to it. -+ // Should generate an event with bytesWritten = -1. -+ try (RandomAccessFile f = new RandomAccessFile(tmp, "r")) { -+ try { -+ f.write(buf); -+ fail("No exception for ReadOnly File"); -+ } catch (IOException e) { -+ // Expected exception -+ expectedEvents.add(IOEvent.createFileWriteEvent(-1, tmp)); -+ } - } -- } - -- recording.stop(); -- List events = Events.fromRecording(recording); -- IOHelper.verifyEqualsInOrder(events, expectedEvents); -+ // Try to write to read-only FileChannel. -+ try (RandomAccessFile f = new RandomAccessFile(tmp, "r"); FileChannel ch = f.getChannel()) { -+ ByteBuffer writeBuf = ByteBuffer.allocateDirect(buf.length); -+ writeBuf.put(buf); -+ writeBuf.flip(); -+ ch.position(0); -+ try { -+ ch.write(writeBuf); -+ fail("No exception for ReadOnly FileChannel"); -+ } catch (java.nio.channels.NonWritableChannelException e) { -+ // Expected exception -+ expectedEvents.add(IOEvent.createFileWriteEvent(-1, tmp)); -+ } -+ } -+ -+ recording.stop(); -+ List events = Events.fromRecording(recording); -+ IOHelper.verifyEqualsInOrder(events, expectedEvents); -+ } - } - } -diff --git a/jdk/test/jdk/jfr/event/io/TestFileStreamEvents.java b/jdk/test/jdk/jfr/event/io/TestFileStreamEvents.java -index 46c7b80f3..0bddf5a6c 100644 ---- a/jdk/test/jdk/jfr/event/io/TestFileStreamEvents.java -+++ b/jdk/test/jdk/jfr/event/io/TestFileStreamEvents.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -50,47 +50,48 @@ public class TestFileStreamEvents { - public static void main(String[] args) throws Throwable { - File tmp = File.createTempFile("TestFileStreamEvents", ".tmp", new File(".")); - tmp.deleteOnExit(); -- Recording recording = new Recording(); -- List expectedEvents = new ArrayList<>(); -+ try (Recording recording = new Recording()) { -+ List expectedEvents = new ArrayList<>(); - -- try(FileOutputStream fos = new FileOutputStream(tmp); FileInputStream fis = new FileInputStream(tmp);) { -- recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0)); -- recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0)); -- recording.start(); -+ try(FileOutputStream fos = new FileOutputStream(tmp); FileInputStream fis = new FileInputStream(tmp);) { -+ recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0)); -+ recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0)); -+ recording.start(); - -- int writeByte = 47; -- byte[] writeBuf = {11, 12, 13, 14}; -+ int writeByte = 47; -+ byte[] writeBuf = {11, 12, 13, 14}; - -- // Write -- fos.write(writeByte); -- expectedEvents.add(IOEvent.createFileWriteEvent(1, tmp)); -- fos.write(writeBuf); -- expectedEvents.add(IOEvent.createFileWriteEvent(writeBuf.length, tmp)); -- fos.write(writeBuf, 0, 2); -- expectedEvents.add(IOEvent.createFileWriteEvent(2, tmp)); -+ // Write -+ fos.write(writeByte); -+ expectedEvents.add(IOEvent.createFileWriteEvent(1, tmp)); -+ fos.write(writeBuf); -+ expectedEvents.add(IOEvent.createFileWriteEvent(writeBuf.length, tmp)); -+ fos.write(writeBuf, 0, 2); -+ expectedEvents.add(IOEvent.createFileWriteEvent(2, tmp)); - -- // Read -- int readByte = fis.read(); -- assertEquals(readByte, writeByte, "Wrong byte read"); -- expectedEvents.add(IOEvent.createFileReadEvent(1, tmp)); -+ // Read -+ int readByte = fis.read(); -+ assertEquals(readByte, writeByte, "Wrong byte read"); -+ expectedEvents.add(IOEvent.createFileReadEvent(1, tmp)); - -- byte[] readBuf = new byte[writeBuf.length]; -- long size = fis.read(readBuf); -- assertEquals(size, (long)writeBuf.length, "Wrong size when reading byte[]"); -- expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -+ byte[] readBuf = new byte[writeBuf.length]; -+ long size = fis.read(readBuf); -+ assertEquals(size, (long)writeBuf.length, "Wrong size when reading byte[]"); -+ expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); - -- size = fis.read(readBuf, 0, 2); -- assertEquals(size, 2L, "Wrong size when reading 2 bytes"); -- expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -+ size = fis.read(readBuf, 0, 2); -+ assertEquals(size, 2L, "Wrong size when reading 2 bytes"); -+ expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); - -- // We are at EOF. Read more and verify we get size -1. -- size = fis.read(readBuf); -- assertEquals(size, -1L, "Size should be -1 at EOF"); -- expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -+ // We are at EOF. Read more and verify we get size -1. -+ size = fis.read(readBuf); -+ assertEquals(size, -1L, "Size should be -1 at EOF"); -+ expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); - -- recording.stop(); -- List events = Events.fromRecording(recording); -- IOHelper.verifyEqualsInOrder(events, expectedEvents); -+ recording.stop(); -+ List events = Events.fromRecording(recording); -+ IOHelper.verifyEqualsInOrder(events, expectedEvents); -+ } - } - } - } -diff --git a/jdk/test/jdk/jfr/event/io/TestInstrumentation.java b/jdk/test/jdk/jfr/event/io/TestInstrumentation.java -index d5430e6c6..19fe5a6da 100644 ---- a/jdk/test/jdk/jfr/event/io/TestInstrumentation.java -+++ b/jdk/test/jdk/jfr/event/io/TestInstrumentation.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -104,11 +104,9 @@ public class TestInstrumentation implements ClassFileTransformer { - "java/io/FileOutputStream::write::([B)V", - "java/io/FileOutputStream::write::([BII)V", - "java/net/SocketInputStream::read::()I", -- "java/net/SocketInputStream::read::([B)I", - "java/net/SocketInputStream::read::([BII)I", - "java/net/SocketInputStream::close::()V", - "java/net/SocketOutputStream::write::(I)V", -- "java/net/SocketOutputStream::write::([B)V", - "java/net/SocketOutputStream::write::([BII)V", - "java/net/SocketOutputStream::close::()V", - "java/nio/channels/FileChannel::read::([Ljava/nio/ByteBuffer;)J", -diff --git a/jdk/test/jdk/jfr/event/io/TestRandomAccessFileEvents.java b/jdk/test/jdk/jfr/event/io/TestRandomAccessFileEvents.java -index 959ed4d22..9c28231c5 100644 ---- a/jdk/test/jdk/jfr/event/io/TestRandomAccessFileEvents.java -+++ b/jdk/test/jdk/jfr/event/io/TestRandomAccessFileEvents.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -49,62 +49,63 @@ public class TestRandomAccessFileEvents { - public static void main(String[] args) throws Throwable { - File tmp = File.createTempFile("TestRandomAccessFileEvents", ".tmp", new File(".")); - tmp.deleteOnExit(); -- Recording recording = new Recording(); -- List expectedEvents = new ArrayList<>(); -- -- recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0)); -- recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0)); -- recording.start(); -- -- RandomAccessFile ras = new RandomAccessFile(tmp, "rw"); -- int writeInt = 47; -- byte[] writeBuffer = {10,11,12,13}; -- -- // Write an int and a buffer. -- ras.write(writeInt); -- expectedEvents.add(IOEvent.createFileWriteEvent(1, tmp)); -- ras.write(writeBuffer); -- expectedEvents.add(IOEvent.createFileWriteEvent(writeBuffer.length, tmp)); -- -- ras.seek(0); -- -- // Read int and buffer -- int readInt = ras.read(); -- assertEquals(readInt, writeInt, "wrong int read"); -- expectedEvents.add(IOEvent.createFileReadEvent(1, tmp)); -- byte[] readBuffer = new byte [writeBuffer.length]; -- int size = ras.read(readBuffer); -- verifyBufferEquals(readBuffer, writeBuffer); -- expectedEvents.add(IOEvent.createFileReadEvent(readBuffer.length, tmp)); -- -- // Read beyond EOF -- readInt = ras.read(); -- assertEquals(-1, readInt, "wrong read after EOF"); -- expectedEvents.add(IOEvent.createFileReadEvent(-1, tmp)); -- -- // Seek to beginning and verify we can read after EOF. -- ras.seek(0); -- readInt = ras.read(); -- assertEquals(readInt, writeInt, "wrong int read after seek(0)"); -- expectedEvents.add(IOEvent.createFileReadEvent(1, tmp)); -- -- // seek beyond EOF and verify we get EOF when reading. -- ras.seek(10); -- readInt = ras.read(); -- assertEquals(-1, readInt, "wrong read after seek beyond EOF"); -- expectedEvents.add(IOEvent.createFileReadEvent(-1, tmp)); -- -- // Read partial buffer. -- int partialSize = writeBuffer.length - 2; -- ras.seek(ras.length()-partialSize); -- size = ras.read(readBuffer); -- assertEquals(size, partialSize, "Wrong size partial buffer read"); -- expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -- -- ras.close(); -- recording.stop(); -- List events = Events.fromRecording(recording); -- IOHelper.verifyEqualsInOrder(events, expectedEvents); -+ try (Recording recording = new Recording()) { -+ List expectedEvents = new ArrayList<>(); -+ -+ recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0)); -+ recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0)); -+ recording.start(); -+ -+ RandomAccessFile ras = new RandomAccessFile(tmp, "rw"); -+ int writeInt = 47; -+ byte[] writeBuffer = {10,11,12,13}; -+ -+ // Write an int and a buffer. -+ ras.write(writeInt); -+ expectedEvents.add(IOEvent.createFileWriteEvent(1, tmp)); -+ ras.write(writeBuffer); -+ expectedEvents.add(IOEvent.createFileWriteEvent(writeBuffer.length, tmp)); -+ -+ ras.seek(0); -+ -+ // Read int and buffer -+ int readInt = ras.read(); -+ assertEquals(readInt, writeInt, "wrong int read"); -+ expectedEvents.add(IOEvent.createFileReadEvent(1, tmp)); -+ byte[] readBuffer = new byte [writeBuffer.length]; -+ int size = ras.read(readBuffer); -+ verifyBufferEquals(readBuffer, writeBuffer); -+ expectedEvents.add(IOEvent.createFileReadEvent(readBuffer.length, tmp)); -+ -+ // Read beyond EOF -+ readInt = ras.read(); -+ assertEquals(-1, readInt, "wrong read after EOF"); -+ expectedEvents.add(IOEvent.createFileReadEvent(-1, tmp)); -+ -+ // Seek to beginning and verify we can read after EOF. -+ ras.seek(0); -+ readInt = ras.read(); -+ assertEquals(readInt, writeInt, "wrong int read after seek(0)"); -+ expectedEvents.add(IOEvent.createFileReadEvent(1, tmp)); -+ -+ // seek beyond EOF and verify we get EOF when reading. -+ ras.seek(10); -+ readInt = ras.read(); -+ assertEquals(-1, readInt, "wrong read after seek beyond EOF"); -+ expectedEvents.add(IOEvent.createFileReadEvent(-1, tmp)); -+ -+ // Read partial buffer. -+ int partialSize = writeBuffer.length - 2; -+ ras.seek(ras.length()-partialSize); -+ size = ras.read(readBuffer); -+ assertEquals(size, partialSize, "Wrong size partial buffer read"); -+ expectedEvents.add(IOEvent.createFileReadEvent(size, tmp)); -+ -+ ras.close(); -+ recording.stop(); -+ List events = Events.fromRecording(recording); -+ IOHelper.verifyEqualsInOrder(events, expectedEvents); -+ } - } - - private static void verifyBufferEquals(byte[] a, byte[] b) { -diff --git a/jdk/test/jdk/jfr/event/io/TestRandomAccessFileThread.java b/jdk/test/jdk/jfr/event/io/TestRandomAccessFileThread.java -index b6200fd66..539759c6f 100644 ---- a/jdk/test/jdk/jfr/event/io/TestRandomAccessFileThread.java -+++ b/jdk/test/jdk/jfr/event/io/TestRandomAccessFileThread.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -64,43 +64,42 @@ public class TestRandomAccessFileThread { - public static void main(String[] args) throws Throwable { - File tmp = File.createTempFile("TestRandomAccessFileThread", ".tmp", new File(".")); - tmp.deleteOnExit(); -- -- Recording recording = new Recording(); -- recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0)); -- recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0)); -- recording.start(); -- -- TestThread writerThread = new TestThread(new XRun() { -- @Override -- public void xrun() throws IOException { -- final byte[] buf = new byte[OP_COUNT]; -- for (int i = 0; i < buf.length; ++i) { -- buf[i] = (byte)((i + 'a') % 255); -- } -- try (RandomAccessFile raf = new RandomAccessFile(tmp, "rwd")) { -- for(int i = 0; i < OP_COUNT; ++i) { -- raf.write(buf, 0, i + 1); -- writeCount++; -+ try (Recording recording = new Recording()) { -+ recording.enable(IOEvent.EVENT_FILE_READ).withThreshold(Duration.ofMillis(0)); -+ recording.enable(IOEvent.EVENT_FILE_WRITE).withThreshold(Duration.ofMillis(0)); -+ recording.start(); -+ -+ TestThread writerThread = new TestThread(new XRun() { -+ @Override -+ public void xrun() throws IOException { -+ final byte[] buf = new byte[OP_COUNT]; -+ for (int i = 0; i < buf.length; ++i) { -+ buf[i] = (byte)((i + 'a') % 255); - } -- } -- }}, "TestWriterThread"); -+ try (RandomAccessFile raf = new RandomAccessFile(tmp, "rwd")) { -+ for(int i = 0; i < OP_COUNT; ++i) { -+ raf.write(buf, 0, i + 1); -+ writeCount++; -+ } -+ } -+ }}, "TestWriterThread"); - - TestThread readerThread = new TestThread(new XRun() { -- @Override -- public void xrun() throws IOException { -- try (RandomAccessFile raf = new RandomAccessFile(tmp, "r")) { -- byte[] buf = new byte[OP_COUNT]; -- for(int i = 0; i < OP_COUNT; ++i) { -- while (writeCount <= i) { -- // No more data to read. Wait for writer thread. -- Thread.yield(); -+ @Override -+ public void xrun() throws IOException { -+ try (RandomAccessFile raf = new RandomAccessFile(tmp, "r")) { -+ byte[] buf = new byte[OP_COUNT]; -+ for(int i = 0; i < OP_COUNT; ++i) { -+ while (writeCount <= i) { -+ // No more data to read. Wait for writer thread. -+ Thread.yield(); -+ } -+ int expectedSize = i + 1; -+ int actualSize = raf.read(buf, 0, expectedSize); -+ Asserts.assertEquals(actualSize, expectedSize, "Wrong read size. Probably test error."); - } -- int expectedSize = i + 1; -- int actualSize = raf.read(buf, 0, expectedSize); -- Asserts.assertEquals(actualSize, expectedSize, "Wrong read size. Probably test error."); - } -- } -- }}, "TestReaderThread"); -+ }}, "TestReaderThread"); - - readerThread.start(); - writerThread.start(); -@@ -118,7 +117,7 @@ public class TestRandomAccessFileThread { - continue; - } - logEventSummary(event); -- if (Events.isEventType(event,IOEvent.EVENT_FILE_READ)) { -+ if (Events.isEventType(event, IOEvent.EVENT_FILE_READ)) { - readEvents.add(event); - } else { - writeEvents.add(event); -@@ -136,91 +135,92 @@ public class TestRandomAccessFileThread { - Asserts.assertEquals(readEvents.size(), OP_COUNT, "Wrong number of read events"); - Asserts.assertEquals(writeEvents.size(), OP_COUNT, "Wrong number of write events"); - } -- -- private static void logEventSummary(RecordedEvent event) { -- boolean isRead = Events.isEventType(event, IOEvent.EVENT_FILE_READ); -- String name = isRead ? "read " : "write"; -- String bytesField = isRead ? "bytesRead" : "bytesWritten"; -- long bytes = Events.assertField(event, bytesField).getValue(); -- long commit = Events.assertField(event, "startTime").getValue(); -- Instant start = event.getStartTime(); -- Instant end = event.getEndTime(); -- System.out.printf("%s: bytes=%d, commit=%d, start=%s, end=%s%n", name, bytes, commit, start, end); -- } -- -- private static void verifyThread(List events, Thread thread) { -- events.stream().forEach(e -> Events.assertEventThread(e, thread)); -- } -- -- private static void verifyBytes(List events, String fieldName) { -- long expectedBytes = 0; -- for (RecordedEvent event : events) { -- Events.assertField(event, fieldName).equal(++expectedBytes); -- } -+ } -+ -+ private static void logEventSummary(RecordedEvent event) { -+ boolean isRead = Events.isEventType(event, IOEvent.EVENT_FILE_READ); -+ String name = isRead ? "read " : "write"; -+ String bytesField = isRead ? "bytesRead" : "bytesWritten"; -+ long bytes = Events.assertField(event, bytesField).getValue(); -+ long commit = Events.assertField(event, "startTime").getValue(); -+ Instant start = event.getStartTime(); -+ Instant end = event.getEndTime(); -+ System.out.printf("%s: bytes=%d, commit=%d, start=%s, end=%s%n", name, bytes, commit, start, end); -+ } -+ -+ private static void verifyThread(List events, Thread thread) { -+ events.stream().forEach(e -> Events.assertEventThread(e, thread)); -+ } -+ -+ private static void verifyBytes(List events, String fieldName) { -+ long expectedBytes = 0; -+ for (RecordedEvent event : events) { -+ Events.assertField(event, fieldName).equal(++expectedBytes); - } -- -- // Verify that all times are increasing -- private static void verifyTimes(List events) { -- RecordedEvent prev = null; -- for (RecordedEvent curr : events) { -- if (prev != null) { -- try { -- Asserts.assertGreaterThanOrEqual(curr.getStartTime(), prev.getStartTime(), "Wrong startTime"); -- Asserts.assertGreaterThanOrEqual(curr.getEndTime(), prev.getEndTime(), "Wrong endTime"); -- long commitPrev = Events.assertField(prev, "startTime").getValue(); -- long commitCurr = Events.assertField(curr, "startTime").getValue(); -- Asserts.assertGreaterThanOrEqual(commitCurr, commitPrev, "Wrong commitTime"); -- } catch (Exception e) { -- System.out.println("Error: " + e.getMessage()); -- System.out.println("Prev Event: " + prev); -- System.out.println("Curr Event: " + curr); -- throw e; -- } -+ } -+ -+ // Verify that all times are increasing -+ private static void verifyTimes(List events) { -+ RecordedEvent prev = null; -+ for (RecordedEvent curr : events) { -+ if (prev != null) { -+ try { -+ Asserts.assertGreaterThanOrEqual(curr.getStartTime(), prev.getStartTime(), "Wrong startTime"); -+ Asserts.assertGreaterThanOrEqual(curr.getEndTime(), prev.getEndTime(), "Wrong endTime"); -+ long commitPrev = Events.assertField(prev, "startTime").getValue(); -+ long commitCurr = Events.assertField(curr, "startTime").getValue(); -+ Asserts.assertGreaterThanOrEqual(commitCurr, commitPrev, "Wrong commitTime"); -+ } catch (Exception e) { -+ System.out.println("Error: " + e.getMessage()); -+ System.out.println("Prev Event: " + prev); -+ System.out.println("Curr Event: " + curr); -+ throw e; - } -- prev = curr; - } -+ prev = curr; - } -- -- // Verify that all times are increasing -- private static void verifyReadWriteTimes(List readEvents, List writeEvents) { -- List events = new ArrayList<>(); -- events.addAll(readEvents); -- events.addAll(writeEvents); -- events.sort(new EventComparator()); -- -- int countRead = 0; -- int countWrite = 0; -- for (RecordedEvent event : events) { -- if (Events.isEventType(event, IOEvent.EVENT_FILE_READ)) { -- ++countRead; -- } else { -- ++countWrite; -- } -- // We can not read from the file before it has been written. -- // This check verifies that times of different threads are correct. -- // Since the read and write are from different threads, it is possible that the read -- // is committed before the same write. -- // But read operation may only be 1 step ahead of the write operation. -- Asserts.assertLessThanOrEqual(countRead, countWrite + 1, "read must be after write"); -+ } -+ -+ // Verify that all times are increasing -+ private static void verifyReadWriteTimes(List readEvents, List writeEvents) { -+ List events = new ArrayList<>(); -+ events.addAll(readEvents); -+ events.addAll(writeEvents); -+ events.sort(new EventComparator()); -+ -+ int countRead = 0; -+ int countWrite = 0; -+ for (RecordedEvent event : events) { -+ if (Events.isEventType(event, IOEvent.EVENT_FILE_READ)) { -+ ++countRead; -+ } else { -+ ++countWrite; - } -+ // We can not read from the file before it has been written. -+ // This check verifies that times of different threads are correct. -+ // Since the read and write are from different threads, it is possible that the read -+ // is committed before the same write. -+ // But read operation may only be 1 step ahead of the write operation. -+ Asserts.assertLessThanOrEqual(countRead, countWrite + 1, "read must be after write"); - } -+ } - -- private static boolean isOurEvent(RecordedEvent event, File file) { -- if (!Events.isEventType(event, IOEvent.EVENT_FILE_READ) && -- !Events.isEventType(event, IOEvent.EVENT_FILE_WRITE)) { -- return false; -- } -- String path = Events.assertField(event, "path").getValue(); -- return file.getPath().equals(path); -+ private static boolean isOurEvent(RecordedEvent event, File file) { -+ if (!Events.isEventType(event, IOEvent.EVENT_FILE_READ) && -+ !Events.isEventType(event, IOEvent.EVENT_FILE_WRITE)) { -+ return false; - } -- -- private static class EventComparator implements Comparator { -- @Override -- public int compare(RecordedEvent a, RecordedEvent b) { -- long commitA = Events.assertField(a, "startTime").getValue(); -- long commitB = Events.assertField(b, "startTime").getValue(); -- return Long.compare(commitA, commitB); -- } -+ String path = Events.assertField(event, "path").getValue(); -+ return file.getPath().equals(path); -+ } -+ -+ private static class EventComparator implements Comparator { -+ @Override -+ public int compare(RecordedEvent a, RecordedEvent b) { -+ long commitA = Events.assertField(a, "startTime").getValue(); -+ long commitB = Events.assertField(b, "startTime").getValue(); -+ return Long.compare(commitA, commitB); - } -+ } - - } -diff --git a/jdk/test/jdk/jfr/event/io/TestSocketChannelEvents.java b/jdk/test/jdk/jfr/event/io/TestSocketChannelEvents.java -index dbd43adbf..23b692a31 100644 ---- a/jdk/test/jdk/jfr/event/io/TestSocketChannelEvents.java -+++ b/jdk/test/jdk/jfr/event/io/TestSocketChannelEvents.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -53,6 +53,7 @@ public class TestSocketChannelEvents { - private static final int bufSizeB = 20; - - private List expectedEvents = new ArrayList<>(); -+ - private synchronized void addExpectedEvent(IOEvent event) { - expectedEvents.add(event); - } -@@ -62,69 +63,70 @@ public class TestSocketChannelEvents { - } - - public void test() throws Throwable { -- Recording recording = new Recording(); -- -- try (ServerSocketChannel ss = ServerSocketChannel.open()) { -- recording.enable(IOEvent.EVENT_SOCKET_READ).withThreshold(Duration.ofMillis(0)); -- recording.enable(IOEvent.EVENT_SOCKET_WRITE).withThreshold(Duration.ofMillis(0)); -- recording.start(); -- -- ss.socket().setReuseAddress(true); -- ss.socket().bind(null); -- -- TestThread readerThread = new TestThread(new XRun() { -- @Override -- public void xrun() throws IOException { -- ByteBuffer bufA = ByteBuffer.allocate(bufSizeA); -- ByteBuffer bufB = ByteBuffer.allocate(bufSizeB); -- try (SocketChannel sc = ss.accept()) { -- int readSize = sc.read(bufA); -- assertEquals(readSize, bufSizeA, "Wrong readSize bufA"); -- addExpectedEvent(IOEvent.createSocketReadEvent(bufSizeA, sc.socket())); -- -- bufA.clear(); -- bufA.limit(1); -- readSize = (int)sc.read(new ByteBuffer[] { bufA, bufB }); -- assertEquals(readSize, 1 + bufSizeB, "Wrong readSize 1+bufB"); -- addExpectedEvent(IOEvent.createSocketReadEvent(readSize, sc.socket())); -- -- // We try to read, but client have closed. Should get EOF. -- bufA.clear(); -- bufA.limit(1); -- readSize = sc.read(bufA); -- assertEquals(readSize, -1, "Wrong readSize at EOF"); -- addExpectedEvent(IOEvent.createSocketReadEvent(-1, sc.socket())); -+ try (Recording recording = new Recording()) { -+ try (ServerSocketChannel ss = ServerSocketChannel.open()) { -+ recording.enable(IOEvent.EVENT_SOCKET_READ).withThreshold(Duration.ofMillis(0)); -+ recording.enable(IOEvent.EVENT_SOCKET_WRITE).withThreshold(Duration.ofMillis(0)); -+ recording.start(); -+ -+ ss.socket().setReuseAddress(true); -+ ss.socket().bind(null); -+ -+ TestThread readerThread = new TestThread(new XRun() { -+ @Override -+ public void xrun() throws IOException { -+ ByteBuffer bufA = ByteBuffer.allocate(bufSizeA); -+ ByteBuffer bufB = ByteBuffer.allocate(bufSizeB); -+ try (SocketChannel sc = ss.accept()) { -+ int readSize = sc.read(bufA); -+ assertEquals(readSize, bufSizeA, "Wrong readSize bufA"); -+ addExpectedEvent(IOEvent.createSocketReadEvent(bufSizeA, sc.socket())); -+ -+ bufA.clear(); -+ bufA.limit(1); -+ readSize = (int) sc.read(new ByteBuffer[] { bufA, bufB }); -+ assertEquals(readSize, 1 + bufSizeB, "Wrong readSize 1+bufB"); -+ addExpectedEvent(IOEvent.createSocketReadEvent(readSize, sc.socket())); -+ -+ // We try to read, but client have closed. Should -+ // get EOF. -+ bufA.clear(); -+ bufA.limit(1); -+ readSize = sc.read(bufA); -+ assertEquals(readSize, -1, "Wrong readSize at EOF"); -+ addExpectedEvent(IOEvent.createSocketReadEvent(-1, sc.socket())); -+ } - } -- } -- }); -- readerThread.start(); -- -- try (SocketChannel sc = SocketChannel.open(ss.socket().getLocalSocketAddress())) { -- ByteBuffer bufA = ByteBuffer.allocateDirect(bufSizeA); -- ByteBuffer bufB = ByteBuffer.allocateDirect(bufSizeB); -- for (int i = 0; i < bufSizeA; ++i) { -- bufA.put((byte)('a' + (i % 20))); -- } -- for (int i = 0; i < bufSizeB; ++i) { -- bufB.put((byte)('A' + (i % 20))); -- } -- bufA.flip(); -- bufB.flip(); -+ }); -+ readerThread.start(); -+ -+ try (SocketChannel sc = SocketChannel.open(ss.socket().getLocalSocketAddress())) { -+ ByteBuffer bufA = ByteBuffer.allocateDirect(bufSizeA); -+ ByteBuffer bufB = ByteBuffer.allocateDirect(bufSizeB); -+ for (int i = 0; i < bufSizeA; ++i) { -+ bufA.put((byte) ('a' + (i % 20))); -+ } -+ for (int i = 0; i < bufSizeB; ++i) { -+ bufB.put((byte) ('A' + (i % 20))); -+ } -+ bufA.flip(); -+ bufB.flip(); - -- sc.write(bufA); -- addExpectedEvent(IOEvent.createSocketWriteEvent(bufSizeA, sc.socket())); -+ sc.write(bufA); -+ addExpectedEvent(IOEvent.createSocketWriteEvent(bufSizeA, sc.socket())); - -- bufA.clear(); -- bufA.limit(1); -- int bytesWritten = (int)sc.write(new ByteBuffer[] { bufA, bufB }); -- assertEquals(bytesWritten, 1 + bufSizeB, "Wrong bytesWritten 1+bufB"); -- addExpectedEvent(IOEvent.createSocketWriteEvent(bytesWritten, sc.socket())); -- } -+ bufA.clear(); -+ bufA.limit(1); -+ int bytesWritten = (int) sc.write(new ByteBuffer[] { bufA, bufB }); -+ assertEquals(bytesWritten, 1 + bufSizeB, "Wrong bytesWritten 1+bufB"); -+ addExpectedEvent(IOEvent.createSocketWriteEvent(bytesWritten, sc.socket())); -+ } - -- readerThread.joinAndThrow(); -- recording.stop(); -- List events= Events.fromRecording(recording); -- IOHelper.verifyEquals(events, expectedEvents); -+ readerThread.joinAndThrow(); -+ recording.stop(); -+ List events = Events.fromRecording(recording); -+ IOHelper.verifyEquals(events, expectedEvents); -+ } - } - } - } -diff --git a/jdk/test/jdk/jfr/event/io/TestSocketEvents.java b/jdk/test/jdk/jfr/event/io/TestSocketEvents.java -index c0b64aa7d..5b544cc7e 100644 ---- a/jdk/test/jdk/jfr/event/io/TestSocketEvents.java -+++ b/jdk/test/jdk/jfr/event/io/TestSocketEvents.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it -@@ -55,6 +55,7 @@ public class TestSocketEvents { - private static final byte[] writeBuf = { 'B', 'C', 'D', 'E' }; - - private List expectedEvents = new ArrayList<>(); -+ - private synchronized void addExpectedEvent(IOEvent event) { - expectedEvents.add(event); - } -@@ -64,58 +65,59 @@ public class TestSocketEvents { - } - - private void test() throws Throwable { -- Recording recording = new Recording(); -- -- try (ServerSocket ss = new ServerSocket()) { -- recording.enable(IOEvent.EVENT_SOCKET_READ).withThreshold(Duration.ofMillis(0)); -- recording.enable(IOEvent.EVENT_SOCKET_WRITE).withThreshold(Duration.ofMillis(0)); -- recording.start(); -- -- ss.setReuseAddress(true); -- ss.bind(null); -- -- TestThread readerThread = new TestThread(new XRun() { -- @Override -- public void xrun() throws IOException { -- byte[] bs = new byte[4]; -- try (Socket s = ss.accept(); InputStream is = s.getInputStream()) { -- int readInt = is.read(); -- assertEquals(readInt, writeInt, "Wrong readInt"); -- addExpectedEvent(IOEvent.createSocketReadEvent(1, s)); -- -- int bytesRead = is.read(bs, 0, 3); -- assertEquals(bytesRead, 3, "Wrong bytesRead partial buffer"); -- addExpectedEvent(IOEvent.createSocketReadEvent(bytesRead, s)); -- -- bytesRead = is.read(bs); -- assertEquals(bytesRead, writeBuf.length, "Wrong bytesRead full buffer"); -- addExpectedEvent(IOEvent.createSocketReadEvent(bytesRead, s)); -- -- // Try to read more, but writer have closed. Should get EOF. -- readInt = is.read(); -- assertEquals(readInt, -1, "Wrong readInt at EOF"); -- addExpectedEvent(IOEvent.createSocketReadEvent(-1, s)); -- } -- } -- }); -- readerThread.start(); -- -- try (Socket s = new Socket()) { -- s.connect(ss.getLocalSocketAddress()); -- try (OutputStream os = s.getOutputStream()) { -- os.write(writeInt); -- addExpectedEvent(IOEvent.createSocketWriteEvent(1, s)); -- os.write(writeBuf, 0, 3); -- addExpectedEvent(IOEvent.createSocketWriteEvent(3, s)); -- os.write(writeBuf); -- addExpectedEvent(IOEvent.createSocketWriteEvent(writeBuf.length, s)); -+ try (Recording recording = new Recording()) { -+ try (ServerSocket ss = new ServerSocket()) { -+ recording.enable(IOEvent.EVENT_SOCKET_READ).withThreshold(Duration.ofMillis(0)); -+ recording.enable(IOEvent.EVENT_SOCKET_WRITE).withThreshold(Duration.ofMillis(0)); -+ recording.start(); -+ -+ ss.setReuseAddress(true); -+ ss.bind(null); -+ -+ TestThread readerThread = new TestThread(new XRun() { -+ @Override -+ public void xrun() throws IOException { -+ byte[] bs = new byte[4]; -+ try (Socket s = ss.accept(); InputStream is = s.getInputStream()) { -+ int readInt = is.read(); -+ assertEquals(readInt, writeInt, "Wrong readInt"); -+ addExpectedEvent(IOEvent.createSocketReadEvent(1, s)); -+ -+ int bytesRead = is.read(bs, 0, 3); -+ assertEquals(bytesRead, 3, "Wrong bytesRead partial buffer"); -+ addExpectedEvent(IOEvent.createSocketReadEvent(bytesRead, s)); -+ -+ bytesRead = is.read(bs); -+ assertEquals(bytesRead, writeBuf.length, "Wrong bytesRead full buffer"); -+ addExpectedEvent(IOEvent.createSocketReadEvent(bytesRead, s)); -+ -+ // Try to read more, but writer have closed. Should -+ // get EOF. -+ readInt = is.read(); -+ assertEquals(readInt, -1, "Wrong readInt at EOF"); -+ addExpectedEvent(IOEvent.createSocketReadEvent(-1, s)); -+ } -+ } -+ }); -+ readerThread.start(); -+ -+ try (Socket s = new Socket()) { -+ s.connect(ss.getLocalSocketAddress()); -+ try (OutputStream os = s.getOutputStream()) { -+ os.write(writeInt); -+ addExpectedEvent(IOEvent.createSocketWriteEvent(1, s)); -+ os.write(writeBuf, 0, 3); -+ addExpectedEvent(IOEvent.createSocketWriteEvent(3, s)); -+ os.write(writeBuf); -+ addExpectedEvent(IOEvent.createSocketWriteEvent(writeBuf.length, s)); -+ } - } -- } - -- readerThread.joinAndThrow(); -- recording.stop(); -- List events = Events.fromRecording(recording); -- IOHelper.verifyEquals(events, expectedEvents); -+ readerThread.joinAndThrow(); -+ recording.stop(); -+ List events = Events.fromRecording(recording); -+ IOHelper.verifyEquals(events, expectedEvents); -+ } - } - } - } --- -2.22.0 - diff --git a/8202951-Support-default-jsa.patch b/8202951-Support-default-jsa.patch new file mode 100644 index 0000000000000000000000000000000000000000..0724ff1c97e131598afaf47223b5bafdff75b8fe --- /dev/null +++ b/8202951-Support-default-jsa.patch @@ -0,0 +1,1394 @@ +From 49f7ef8df4cade226de5754172e208975343967c Mon Sep 17 00:00:00 2001 +Date: Sat, 3 Sep 2022 14:25:50 +0000 +Subject: 8202951-Support-default-jsa + +--- + common/autoconf/configure.ac | 3 + + common/autoconf/generated-configure.sh | 40 +++++ + common/autoconf/jdk-options.m4 | 32 ++++ + common/autoconf/spec.gmk.in | 4 + + common/bin/compare.sh | 1 + + hotspot/src/share/vm/cds/archiveBuilder.cpp | 34 +++- + hotspot/src/share/vm/cds/archiveBuilder.hpp | 4 + + hotspot/src/share/vm/cds/dynamicArchive.cpp | 1 + + .../src/share/vm/classfile/classLoader.cpp | 152 +++++++++++++++++- + .../src/share/vm/classfile/classLoader.hpp | 15 +- + .../share/vm/classfile/classLoaderData.hpp | 1 + + hotspot/src/share/vm/classfile/dictionary.cpp | 2 +- + .../vm/classfile/sharedPathsMiscInfo.hpp | 13 +- + .../vm/classfile/systemDictionaryShared.cpp | 2 +- + hotspot/src/share/vm/memory/filemap.cpp | 34 +++- + hotspot/src/share/vm/memory/filemap.hpp | 7 + + hotspot/src/share/vm/memory/metachunk.hpp | 2 + + hotspot/src/share/vm/memory/metaspace.cpp | 14 ++ + hotspot/src/share/vm/memory/metaspace.hpp | 2 + + .../src/share/vm/memory/metaspaceShared.cpp | 22 +++ + .../src/share/vm/memory/metaspaceShared.hpp | 5 +- + hotspot/src/share/vm/oops/instanceKlass.cpp | 5 +- + hotspot/src/share/vm/runtime/arguments.cpp | 34 ++-- + hotspot/src/share/vm/runtime/arguments.hpp | 6 + + hotspot/src/share/vm/utilities/hashtable.cpp | 1 + + hotspot/test/runtime/appcds/TestCommon.java | 74 ++++++++- + .../appcds/dynamicArchive/DynamicFlag.java | 39 +++++ + .../dynamicArchive/DynamicHelloTest.java | 42 +++++ + .../VerifyWithDynamicArchive.java | 42 +++++ + jdk/make/BuildJdk.gmk | 7 + + 30 files changed, 603 insertions(+), 37 deletions(-) + create mode 100644 hotspot/test/runtime/appcds/dynamicArchive/DynamicFlag.java + create mode 100644 hotspot/test/runtime/appcds/dynamicArchive/DynamicHelloTest.java + create mode 100644 hotspot/test/runtime/appcds/dynamicArchive/VerifyWithDynamicArchive.java + +diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac +index 151e5a10..dbcdd59e 100644 +--- a/common/autoconf/configure.ac ++++ b/common/autoconf/configure.ac +@@ -98,6 +98,9 @@ JDKOPT_SETUP_JVM_INTERPRETER + JDKOPT_SETUP_JVM_VARIANTS + JDKOPT_SETUP_DEBUG_LEVEL + ++# Enable default CDS ARCHIVE ++JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE ++ + # With basic setup done, call the custom early hook. + CUSTOM_EARLY_HOOK + +diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh +index c41c4336..f0e49f50 100644 +--- a/common/autoconf/generated-configure.sh ++++ b/common/autoconf/generated-configure.sh +@@ -883,6 +883,7 @@ OUTPUT_ROOT + CONF_NAME + SPEC + DEVKIT_LIB_DIR ++BUILD_CDS_ARCHIVE + BUILD_VARIANT_RELEASE + DEBUG_CLASSFILES + FASTDEBUG +@@ -1047,6 +1048,7 @@ with_jvm_interpreter + with_jvm_variants + enable_debug + with_debug_level ++enable_cds_archive + with_devkit + with_sys_root + with_sysroot +@@ -1857,6 +1859,8 @@ Optional Features: + [disabled] + --enable-debug set the debug level to fastdebug (shorthand for + --with-debug-level=fastdebug) [disabled] ++ --disable-cds-archive Set to disable generation of a default CDS archive ++ in the product image [enabled] + --disable-headful disable building headful support (graphical UI + support) [enabled] + --enable-hotspot-test-in-build +@@ -14704,6 +14708,42 @@ fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEBUG_LEVEL" >&5 + $as_echo "$DEBUG_LEVEL" >&6; } + ++ ++ ++# Enable default CDS ARCHIVE ++ ++ # Check whether --enable-cds-archive was given. ++if test "${enable_cds_archive+set}" = set; then : ++ enableval=$enable_cds_archive; ++fi ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if a default CDS archive should be generated" >&5 ++$as_echo_n "checking if a default CDS archive should be generated... " >&6; } ++ if test "x$COMPILE_TYPE" = "xcross"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, not possible with cross compilation" >&5 ++$as_echo "no, not possible with cross compilation" >&6; } ++ BUILD_CDS_ARCHIVE="false" ++ elif test "x$enable_cds_archive" = "xyes"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, forced" >&5 ++$as_echo "yes, forced" >&6; } ++ BUILD_CDS_ARCHIVE="true" ++ elif test "x$enable_cds_archive" = "x"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++ BUILD_CDS_ARCHIVE="true" ++ elif test "x$enable_cds_archive" = "xno"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, forced" >&5 ++$as_echo "no, forced" >&6; } ++ BUILD_CDS_ARCHIVE="false" ++ else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ as_fn_error $? "--enable-cds_archive can only be yes/no or empty" "$LINENO" 5 ++ fi ++ ++ ++ + if test "x$DEBUG_LEVEL" != xrelease && \ + test "x$DEBUG_LEVEL" != xfastdebug && \ + test "x$DEBUG_LEVEL" != xslowdebug; then +diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 +index bca78afe..c506086d 100644 +--- a/common/autoconf/jdk-options.m4 ++++ b/common/autoconf/jdk-options.m4 +@@ -789,6 +789,38 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS], + AC_SUBST(ZIP_DEBUGINFO_FILES) + ]) + ++################################################################################ ++# ++# Disable the default CDS archive generation ++# cross compilation - disabled ++# ++AC_DEFUN_ONCE([JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE], ++[ ++ AC_ARG_ENABLE([cds-archive], [AS_HELP_STRING([--disable-cds-archive], ++ [Set to disable generation of a default CDS archive in the product image @<:@enabled@:>@])]) ++ ++ AC_MSG_CHECKING([if a default CDS archive should be generated]) ++ if test "x$COMPILE_TYPE" = "xcross"; then ++ AC_MSG_RESULT([no, not possible with cross compilation]) ++ BUILD_CDS_ARCHIVE="false" ++ elif test "x$enable_cds_archive" = "xyes"; then ++ AC_MSG_RESULT([yes, forced]) ++ BUILD_CDS_ARCHIVE="true" ++ elif test "x$enable_cds_archive" = "x"; then ++ AC_MSG_RESULT([yes]) ++ BUILD_CDS_ARCHIVE="true" ++ elif test "x$enable_cds_archive" = "xno"; then ++ AC_MSG_RESULT([no, forced]) ++ BUILD_CDS_ARCHIVE="false" ++ else ++ AC_MSG_RESULT([no]) ++ AC_MSG_ERROR([--enable-cds_archive can only be yes/no or empty]) ++ fi ++ ++ AC_SUBST(BUILD_CDS_ARCHIVE) ++]) ++ ++ + # Support for customization of the build process. Some build files + # will include counterparts from this location, if they exist. This allows + # for a degree of customization of the build targets and the rules/recipes +diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in +index 4c3a9f61..79248cbf 100644 +--- a/common/autoconf/spec.gmk.in ++++ b/common/autoconf/spec.gmk.in +@@ -611,6 +611,10 @@ LIBZIP_CAN_USE_MMAP:=@LIBZIP_CAN_USE_MMAP@ + MSVCR_DLL:=@MSVCR_DLL@ + MSVCP_DLL:=@MSVCP_DLL@ + UCRT_DLL_DIR:=@UCRT_DLL_DIR@ ++# CDS_ARCHIVE ++BUILD_CDS_ARCHIVE:=@BUILD_CDS_ARCHIVE@ ++ ++ + + + # ADD_SRCS takes a single argument with source roots +diff --git a/common/bin/compare.sh b/common/bin/compare.sh +index ff88bb1f..a36464a9 100644 +--- a/common/bin/compare.sh ++++ b/common/bin/compare.sh +@@ -290,6 +290,7 @@ compare_general_files() { + ! -name "ct.sym" ! -name "*.diz" ! -name "*.dll" \ + ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \ + ! -name "*.lib" ! -name "*.war" ! -name "JavaControlPanel" \ ++ ! -name "classes.jsa" \ + | $GREP -v "./bin/" | $SORT | $FILTER) + + echo General files... +diff --git a/hotspot/src/share/vm/cds/archiveBuilder.cpp b/hotspot/src/share/vm/cds/archiveBuilder.cpp +index 144dedfa..13a62002 100644 +--- a/hotspot/src/share/vm/cds/archiveBuilder.cpp ++++ b/hotspot/src/share/vm/cds/archiveBuilder.cpp +@@ -59,6 +59,18 @@ ArchiveBuilder::SourceObjList::~SourceObjList() { + delete _objs; + } + ++static void caculate_fingerprint(Klass * klass) { ++ if (klass->oop_is_instance()) { ++ InstanceKlass* ik = InstanceKlass::cast(klass); ++ for (int i = 0; i < ik->methods()->length(); i++) { ++ Method* m = ik->methods()->at(i); ++ Fingerprinter fp(m); ++ // The side effect of this call sets method's fingerprint field. ++ fp.fingerprint(); ++ } ++ } ++} ++ + void ArchiveBuilder::SourceObjList::append(MetaspaceClosure::Ref* enclosing_ref, SourceObjInfo* src_info) { + // Save this source object for copying + _objs->append(src_info); +@@ -166,6 +178,7 @@ ArchiveBuilder::ArchiveBuilder() : + _buffer_to_requested_delta(0), + _rw_region("rw", MAX_SHARED_DELTA), + _ro_region("ro", MAX_SHARED_DELTA), ++ _md_region("md", MAX_SHARED_DELTA), + _rw_src_objs(), + _ro_src_objs(), + _src_obj_table(INITIAL_TABLE_SIZE), +@@ -384,6 +397,7 @@ bool ArchiveBuilder::gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool re + Klass* klass = (Klass*)ref->obj(); + assert(klass->is_klass(), "must be"); + if (!is_excluded(klass)) { ++ caculate_fingerprint(klass); + _klasses->append(klass); + if (klass->oop_is_instance()) { + _num_instance_klasses ++; +@@ -434,7 +448,8 @@ size_t ArchiveBuilder::estimate_archive_size() { + + address ArchiveBuilder::reserve_buffer() { + size_t buffer_size = estimate_archive_size(); +- ReservedSpace rs(buffer_size, os::vm_allocation_granularity(), false); ++ size_t package_hash_table_est = align_up(ClassLoader::estimate_size_for_archive(), (size_t)os::vm_allocation_granularity()); ++ ReservedSpace rs(buffer_size + package_hash_table_est, os::vm_allocation_granularity(), false); + if (!rs.is_reserved()) { + tty->print_cr("Failed to reserve " SIZE_FORMAT " bytes of output buffer.", buffer_size); + vm_direct_exit(0); +@@ -443,7 +458,8 @@ address ArchiveBuilder::reserve_buffer() { + // buffer_bottom is the lowest address of the 2 core regions (rw, ro) when + // we are copying the class metadata into the buffer. + address buffer_bottom = (address)rs.base(); +- _shared_rs = rs; ++ _shared_rs = rs.first_part(buffer_size); ++ _md_rs = rs.last_part(buffer_size); + + _buffer_bottom = buffer_bottom; + _last_verified_top = buffer_bottom; +@@ -508,6 +524,19 @@ void ArchiveBuilder::dump_ro_metadata() { + make_shallow_copies(&_ro_region, &_ro_src_objs); + } + ++void ArchiveBuilder::dump_md_metadata() { ++ ResourceMark rm; ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Allocating MD objects ... "); ++ } ++ _current_dump_space = &_md_region; ++ _md_region.init(&_md_rs, &_md_vs); ++ char* md_top = _md_vs.low(); ++ char* md_end = _md_vs.high_boundary(); ++ _md_region.allocate(md_end - md_top); ++ ClassLoader::serialize_package_hash_table(&md_top, md_end); ++} ++ + void ArchiveBuilder::start_dump_space(DumpRegion* next) { + address bottom = _last_verified_top; + address top = (address)(_current_dump_space->top()); +@@ -749,6 +778,7 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo) { + + write_region(mapinfo, MetaspaceShared::d_rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false); + write_region(mapinfo, MetaspaceShared::d_ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false); ++ write_region(mapinfo, MetaspaceShared::d_md, &_md_region, /*read_only=*/true, /*allow_exec=*/false); + + char* bitmap = mapinfo->write_bitmap_region(ArchivePtrMarker::ptrmap()); + +diff --git a/hotspot/src/share/vm/cds/archiveBuilder.hpp b/hotspot/src/share/vm/cds/archiveBuilder.hpp +index 18cd3c62..f7a5c107 100644 +--- a/hotspot/src/share/vm/cds/archiveBuilder.hpp ++++ b/hotspot/src/share/vm/cds/archiveBuilder.hpp +@@ -163,10 +163,13 @@ private: + static const int MAX_TABLE_SIZE = 1000000; + + ReservedSpace _shared_rs; ++ ReservedSpace _md_rs; + VirtualSpace _shared_vs; ++ VirtualSpace _md_vs; + + DumpRegion _rw_region; + DumpRegion _ro_region; ++ DumpRegion _md_region; + BitMap _ptrmap; + + SourceObjList _rw_src_objs; // objs to put in rw region +@@ -327,6 +330,7 @@ public: + + void dump_rw_metadata(); + void dump_ro_metadata(); ++ void dump_md_metadata(); + void relocate_metaspaceobj_embedded_pointers(); + void relocate_roots(); + void make_klasses_shareable(); +diff --git a/hotspot/src/share/vm/cds/dynamicArchive.cpp b/hotspot/src/share/vm/cds/dynamicArchive.cpp +index efed275c..a623c5b0 100644 +--- a/hotspot/src/share/vm/cds/dynamicArchive.cpp ++++ b/hotspot/src/share/vm/cds/dynamicArchive.cpp +@@ -149,6 +149,7 @@ public: + + relocate_to_requested(); + ++ dump_md_metadata(); + write_archive(serialized_data); + release_header(); + +diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp +index e3470ca8..04fa84d4 100644 +--- a/hotspot/src/share/vm/classfile/classLoader.cpp ++++ b/hotspot/src/share/vm/classfile/classLoader.cpp +@@ -219,6 +219,30 @@ const char* ClassLoader::package_from_name(const char* const class_name, bool* b + return (const char *)pkg_name; + } + ++const char* ClassLoader::get_file_name_from_path(const char* path) { ++ const char* pos = strrchr(path, '/'); ++ if (pos == NULL) { ++ return path; ++ } else { ++ return pos + 1; ++ } ++} ++ ++const char* ClassLoader::get_boot_class_path(const char* shared_path) { ++ const char* shared_name = get_file_name_from_path(shared_path); ++ ClassPathEntry* e = _first_entry; ++ while (e != NULL) { ++ if (e->sys_class()) { ++ const char* name = get_file_name_from_path(e->name()); ++ if (strcmp(name, shared_name) == 0) { ++ return e->name(); ++ } ++ } ++ e = e->next(); ++ } ++ return NULL; ++} ++ + MetaIndex::MetaIndex(char** meta_package_names, int num_meta_package_names) { + if (num_meta_package_names == 0) { + _meta_package_names = NULL; +@@ -512,6 +536,8 @@ void ClassLoader::setup_meta_index(const char* meta_index_path, const char* meta + int line_no = 0; + #if INCLUDE_CDS + if (DumpSharedSpaces) { ++ meta_index_path = Arguments::get_is_default_jsa() ? ++ get_file_name_from_path(meta_index_path) : meta_index_path; + if (file != NULL) { + _shared_paths_misc_info->add_required_file(meta_index_path); + } else { +@@ -644,7 +670,9 @@ void ClassLoader::setup_bootstrap_search_path() { + } + #if INCLUDE_CDS + if (DumpSharedSpaces) { +- _shared_paths_misc_info->add_boot_classpath(sys_class_path); ++ const char* new_sys_class_path = Arguments::get_is_default_jsa() ? ++ get_file_name_from_path(sys_class_path) : sys_class_path; ++ _shared_paths_misc_info->add_boot_classpath(new_sys_class_path); + } + #endif + setup_search_path(sys_class_path); +@@ -688,7 +716,7 @@ void ClassLoader::setup_search_path(const char *class_path, bool canonicalize) { + path = canonical_path; + } + } +- update_class_path_entry_list(path, /*check_for_duplicates=*/canonicalize); ++ update_class_path_entry_list(path, /*check_for_duplicates=*/canonicalize, true, true); + #if INCLUDE_CDS + if (DumpSharedSpaces) { + check_shared_classpath(path); +@@ -816,7 +844,9 @@ void ClassLoader::add_to_list(ClassPathEntry *new_entry) { + // Returns true IFF the file/dir exists and the entry was successfully created. + bool ClassLoader::update_class_path_entry_list(const char *path, + bool check_for_duplicates, +- bool throw_exception) { ++ bool throw_exception, ++ bool sys_class_type) { ++ // sys_class_type indicates whether *path is a system path. The default value is false. + struct stat st; + if (os::stat(path, &st) == 0) { + // File or directory found +@@ -826,6 +856,11 @@ bool ClassLoader::update_class_path_entry_list(const char *path, + if (new_entry == NULL) { + return false; + } ++ // If the path is a system path, set sys_class of the newly created ++ // linked list node to true. The default value is false. ++ if (sys_class_type) { ++ new_entry->set_sys_class(true); ++ } + // The kernel VM adds dynamically to the end of the classloader path and + // doesn't reorder the bootclasspath which would break java.lang.Package + // (see PackageInfo). +@@ -837,6 +872,8 @@ bool ClassLoader::update_class_path_entry_list(const char *path, + } else { + #if INCLUDE_CDS + if (DumpSharedSpaces) { ++ path = Arguments::get_is_default_jsa() ? ++ get_file_name_from_path(path) : path; + _shared_paths_misc_info->add_nonexist_path(path); + } + #endif +@@ -918,6 +955,7 @@ int ClassLoader::crc32(int crc, const char* buf, int len) { + class PackageInfo: public BasicHashtableEntry { + public: + const char* _pkgname; // Package name ++ const char* _filename; // File name + int _classpath_index; // Index of directory or JAR file loaded from + + PackageInfo* next() { +@@ -926,9 +964,10 @@ public: + + const char* pkgname() { return _pkgname; } + void set_pkgname(char* pkgname) { _pkgname = pkgname; } ++ void set_filename(char* filename) { _filename = filename; } + + const char* filename() { +- return ClassLoader::classpath_entry(_classpath_index)->name(); ++ return _filename == NULL ? ClassLoader::classpath_entry(_classpath_index)->name() : _filename; + } + + void set_index(int index) { +@@ -975,11 +1014,12 @@ public: + return get_entry(hash_to_index(hash), hash, pkgname, n); + } + +- PackageInfo* new_entry(char* pkgname, int n) { ++ PackageInfo* new_entry(char* pkgname, int n, char* filename = NULL) { + unsigned int hash = compute_hash(pkgname, n); + PackageInfo* pp; + pp = (PackageInfo*)BasicHashtable::new_entry(hash); + pp->set_pkgname(pkgname); ++ pp->set_filename(filename); + return pp; + } + +@@ -999,6 +1039,9 @@ public: + } + + CDS_ONLY(void copy_table(char** top, char* end, PackageHashtable* table);) ++ CDS_ONLY(void serialize(char** top, char* end);) ++ CDS_ONLY(void deserialize(char* start);) ++ CDS_ONLY(size_t estimate_size();) + }; + + #if INCLUDE_CDS +@@ -1035,6 +1078,93 @@ void PackageHashtable::copy_table(char** top, char* end, + *tableSize = len; + } + ++size_t PackageHashtable::estimate_size() { ++ int size = sizeof(int); ++ ClassPathEntry* e = ClassLoader::_first_entry; ++ while (e != NULL) { ++ int length = (int)(strlen(e->name()) + 1); ++ size += length; ++ e = e->next(); ++ } ++ size = align_size_up(size, sizeof(int)); ++ ++ size += sizeof(int); ++ for (int i = 0; i < table_size(); ++i) { ++ for (PackageInfo* pp = bucket(i); ++ pp != NULL; ++ pp = pp->next()) { ++ size += sizeof(int); ++ int n1 = (int)(strlen(pp->pkgname()) + 1); ++ n1 = align_size_up(n1, sizeof(int)); ++ size += n1; ++ } ++ } ++ return align_size_up(size, sizeof(int)); ++} ++ ++void PackageHashtable::serialize(char** top, char* end) { ++ *(int*)(*top) = ClassLoader::_num_entries; ++ *top += sizeof(int); ++ ++ ClassPathEntry* e = ClassLoader::_first_entry; ++ while (e != NULL) { ++ int length = (int)(strlen(e->name()) + 1); ++ memcpy(*top, e->name(), length); ++ *top += length; ++ e = e->next(); ++ } ++ *top = (char*)align_size_up((intptr_t)*top, sizeof(int)); ++ *(int*)(*top) = number_of_entries(); ++ *top += sizeof(int); ++ ++ for (int i = 0; i < table_size(); ++i) { ++ for (PackageInfo* pp = bucket(i); ++ pp != NULL; ++ pp = pp->next()) { ++ *(int*)(*top) = pp->_classpath_index; ++ *top += sizeof(int); ++ int n1 = (int)(strlen(pp->pkgname()) + 1); ++ memcpy(*top, pp->pkgname(), n1); ++ n1 = align_size_up(n1, sizeof(int)); ++ *top += n1; ++ } ++ } ++} ++ ++void PackageHashtable::deserialize(char* start) { ++ int num_entries = *(int*)start; ++ char** class_loader_entries = NEW_C_HEAP_ARRAY(char*, num_entries, mtClass); ++ start += sizeof(int); ++ int entries_len = 0; ++ for (int i = 0, index = 0; i < num_entries; i++) { ++ class_loader_entries[index++] = start + entries_len; ++ entries_len += (int)(strlen(start + entries_len) + 1); ++ } ++ start += align_size_up(entries_len, sizeof(int)); ++ int number_of_entries = *(int*)start; ++ start += sizeof(int); ++ for (int i = 0; i < number_of_entries; i++) { ++ int classpath_index = *(int*)start; ++ start += sizeof(int); ++ char* pkgname = start; ++ const char *cp = strrchr(pkgname, '/'); ++ if (cp != NULL) { ++ int n = cp - pkgname + 1; ++ if (get_entry(pkgname, n) == NULL) { ++ PackageInfo* info = new_entry(pkgname, n, class_loader_entries[classpath_index]); ++ add_entry(info); ++ } ++ } ++ int n1 = (int)(strlen(start) + 1); ++ start += align_size_up(n1, sizeof(int)); ++ } ++ FREE_C_HEAP_ARRAY(char*, class_loader_entries, mtClass); ++} ++ ++void ClassLoader::deserialize_package_hash_table(char* start) { ++ assert(_package_hash_table != NULL, "should have one yet"); ++ _package_hash_table->deserialize(start); ++} + + void ClassLoader::copy_package_info_buckets(char** top, char* end) { + _package_hash_table->copy_buckets(top, end); +@@ -1043,6 +1173,14 @@ void ClassLoader::copy_package_info_buckets(char** top, char* end) { + void ClassLoader::copy_package_info_table(char** top, char* end) { + _package_hash_table->copy_table(top, end, _package_hash_table); + } ++ ++size_t ClassLoader::estimate_size_for_archive() { ++ return _package_hash_table->estimate_size(); ++} ++ ++void ClassLoader::serialize_package_hash_table(char** top, char* end) { ++ return _package_hash_table->serialize(top, end); ++} + #endif + + PackageInfo* ClassLoader::lookup_package(const char *pkgname) { +@@ -1226,8 +1364,8 @@ void ClassLoader::create_package_info_table(HashtableBucket *t, int len + + + void ClassLoader::create_package_info_table() { +- assert(_package_hash_table == NULL, "shouldn't have one yet"); +- _package_hash_table = new PackageHashtable(package_hash_table_size); ++ assert(_package_hash_table == NULL, "shouldn't have one yet"); ++ _package_hash_table = new PackageHashtable(package_hash_table_size); + } + + +diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp +index 9514d3bb..cf39ce99 100644 +--- a/hotspot/src/share/vm/classfile/classLoader.hpp ++++ b/hotspot/src/share/vm/classfile/classLoader.hpp +@@ -49,13 +49,18 @@ class MetaIndex: public CHeapObj { + class ClassPathEntry: public CHeapObj { + private: + ClassPathEntry* _next; ++ bool _sys_class; + public: + // Next entry in class path + ClassPathEntry* next() { return _next; } ++ bool sys_class() const { return _sys_class; } + void set_next(ClassPathEntry* next) { + // may have unlocked readers, so write atomically. + OrderAccess::release_store_ptr(&_next, next); + } ++ void set_sys_class(bool isSysClass) { ++ _sys_class = isSysClass; ++ } + virtual bool is_jar_file() = 0; + virtual const char* name() = 0; + virtual bool is_lazy(); +@@ -158,6 +163,7 @@ class ClassLoader: AllStatic { + }; + protected: + friend class LazyClassPathEntry; ++ friend class PackageHashtable; + + // Performance counters + static PerfCounter* _perf_accumulated_time; +@@ -234,7 +240,8 @@ class ClassLoader: AllStatic { + static int crc32(int crc, const char* buf, int len); + static bool update_class_path_entry_list(const char *path, + bool check_for_duplicates, +- bool throw_exception=true); ++ bool throw_exception=true, ++ bool sys_class=false); + static void print_bootclasspath(); + + // Timing +@@ -318,6 +325,9 @@ class ClassLoader: AllStatic { + // Initialization + static void initialize(); + CDS_ONLY(static void initialize_shared_path();) ++ static const char* get_file_name_from_path(const char* path); ++ static const char* get_boot_class_path(const char* shared_path); ++ + static void create_package_info_table(); + static void create_package_info_table(HashtableBucket *t, int length, + int number_of_entries); +@@ -340,6 +350,9 @@ class ClassLoader: AllStatic { + // Sharing dump and restore + static void copy_package_info_buckets(char** top, char* end); + static void copy_package_info_table(char** top, char* end); ++ static size_t estimate_size_for_archive(); ++ static void serialize_package_hash_table(char** top, char* end); ++ static void deserialize_package_hash_table(char* start); + + static void check_shared_classpath(const char *path); + static void finalize_shared_paths_misc_info(); +diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp +index 9b901303..7155257e 100644 +--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp ++++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp +@@ -168,6 +168,7 @@ class ClassLoaderData : public CHeapObj { + friend class ClassLoaderDataGraphMetaspaceIterator; + friend class MetaDataFactory; + friend class Method; ++ friend class VM_PopulateDumpSharedSpace; + + static ClassLoaderData * _the_null_class_loader_data; + +diff --git a/hotspot/src/share/vm/classfile/dictionary.cpp b/hotspot/src/share/vm/classfile/dictionary.cpp +index b9d473b0..d41372ec 100644 +--- a/hotspot/src/share/vm/classfile/dictionary.cpp ++++ b/hotspot/src/share/vm/classfile/dictionary.cpp +@@ -197,7 +197,7 @@ void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) { + } + + void Dictionary::remove_classes_in_error_state() { +- assert(DumpSharedSpaces, "supported only when dumping"); ++ assert(DynamicDumpSharedSpaces || DumpSharedSpaces, "supported only when dumping"); + DictionaryEntry* probe = NULL; + for (int index = 0; index < table_size(); index++) { + for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) { +diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp +index 882fed01..b1609e46 100644 +--- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp ++++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp +@@ -26,6 +26,7 @@ + #define SHARE_VM_CLASSFILE_SHAREDPATHSMISCINFO_HPP + + #include "runtime/os.hpp" ++#include "runtime/arguments.hpp" + + // During dumping time, when processing class paths, we build up the dump-time + // classpath. The JAR files that exist are stored in the list ClassLoader::_first_entry. +@@ -111,12 +112,18 @@ public: + add_path(path, REQUIRED); + + struct stat st; +- if (os::stat(path, &st) != 0) { ++ if (!Arguments::get_is_default_jsa() && os::stat(path, &st) != 0) { + assert(0, "sanity"); + ClassLoader::exit_with_path_failure("failed to os::stat(%s)", path); // should not happen + } +- write_time(st.st_mtime); +- write_long(st.st_size); ++ ++ if (Arguments::get_is_default_jsa()) { ++ write_time(0); ++ write_long(0); ++ } else { ++ write_time(st.st_mtime); ++ write_long(st.st_size); ++ } + } + + // The path must exist, and must contain exactly files/dirs +diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp +index 99354cd4..3a601ee3 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp ++++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp +@@ -659,7 +659,7 @@ bool SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) + + bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) { + while (k) { +- if (k->name()->equals("jdk/jfr/Event")) { ++ if (k->name()->equals("jdk/jfr/Event") || k->name()->starts_with("jdk/jfr/event")) { + return true; + } + k = k->java_super(); +diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp +index 3f410647..5fd62a74 100644 +--- a/hotspot/src/share/vm/memory/filemap.cpp ++++ b/hotspot/src/share/vm/memory/filemap.cpp +@@ -263,7 +263,12 @@ void FileMapInfo::allocate_classpath_entry_table() { + + for (int cur_entry = 0 ; cpe != NULL; cpe = cpe->next(), cur_entry++) { + const char *name = cpe->name(); +- int name_bytes = (int)(strlen(name) + 1); ++ int name_bytes; ++ if (cpe->sys_class()) { ++ name_bytes = (int)(strlen(ClassLoader::get_file_name_from_path(name)) + 1); ++ } else { ++ name_bytes = (int)(strlen(name) + 1); ++ } + + if (pass == 0) { + count ++; +@@ -286,7 +291,13 @@ void FileMapInfo::allocate_classpath_entry_table() { + } + + EXCEPTION_MARK; // The following call should never throw, but would exit VM on error. +- SharedClassUtil::update_shared_classpath(cpe, ent, st.st_mtime, st.st_size, THREAD); ++ if (cpe->sys_class()) { ++ // Jdk boot jar not need validate timestamp for we may copy whole jdk. ++ SharedClassUtil::update_shared_classpath(cpe, ent, 0, st.st_size, THREAD); ++ ent->set_sys_class(true); ++ } else { ++ SharedClassUtil::update_shared_classpath(cpe, ent, st.st_mtime, st.st_size, THREAD); ++ } + } else { + ent->_filesize = -1; + if (!os::dir_is_empty(name)) { +@@ -295,7 +306,11 @@ void FileMapInfo::allocate_classpath_entry_table() { + } + ent->_name = strptr; + if (strptr + name_bytes <= strptr_max) { +- strncpy(strptr, name, (size_t)name_bytes); // name_bytes includes trailing 0. ++ if (cpe->sys_class()) { ++ strncpy(strptr, ClassLoader::get_file_name_from_path(name), (size_t)name_bytes); ++ } else { ++ strncpy(strptr, name, (size_t)name_bytes); // name_bytes includes trailing 0. ++ } + strptr += name_bytes; + } else { + assert(0, "miscalculated buffer size"); +@@ -334,6 +349,14 @@ bool FileMapInfo::validate_classpath_entry_table() { + if (TraceClassPaths || (TraceClassLoading && Verbose)) { + tty->print_cr("[Checking shared classpath entry: %s]", name); + } ++ if (ent->_sys_class) { ++ name = ClassLoader::get_boot_class_path(name); ++ if (name == NULL) { ++ fail_continue("Required classpath entry of system class does not exist"); ++ continue; ++ } ++ } ++ + if (os::stat(name, &st) != 0) { + fail_continue("Required classpath entry does not exist: %s", name); + ok = false; +@@ -343,7 +366,7 @@ bool FileMapInfo::validate_classpath_entry_table() { + ok = false; + } + } else { +- if (ent->_timestamp != st.st_mtime || ++ if ((ent->_timestamp != 0 && ent->_timestamp != st.st_mtime) || + ent->_filesize != st.st_size) { + ok = false; + if (PrintSharedArchiveAndExit) { +@@ -640,6 +663,7 @@ void FileMapInfo::write_space(int i, Metaspace* space, bool read_only) { + size_t used = space->used_bytes_slow(Metaspace::NonClassType); + size_t capacity = space->capacity_bytes_slow(Metaspace::NonClassType); + struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; ++ space->reset_metachunks(); + write_region(i, (char*)space->bottom(), used, capacity, read_only, false); + } + +@@ -967,7 +991,7 @@ bool FileMapInfo::validate_header() { + return DynamicArchive::validate(this); + } + +- if (status) { ++ if (status && !_header->_is_default_jsa) { + if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) { + if (!PrintSharedArchiveAndExit) { + fail_continue("shared class paths mismatch (hint: enable -XX:+TraceClassPaths to diagnose the failure)"); +diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp +index eab9ebcf..36b27f13 100644 +--- a/hotspot/src/share/vm/memory/filemap.hpp ++++ b/hotspot/src/share/vm/memory/filemap.hpp +@@ -52,9 +52,13 @@ public: + const char *_name; + time_t _timestamp; // jar timestamp, 0 if is directory + long _filesize; // jar file size, -1 if is directory ++ bool _sys_class; + bool is_dir() { + return _filesize == -1; + } ++ void set_sys_class(bool isSysClass) { ++ _sys_class = isSysClass; ++ } + }; + + class FileMapInfo : public CHeapObj { +@@ -100,6 +104,7 @@ public: + int _version; // (from enum, above.) + size_t _alignment; // how shared archive should be aligned + int _obj_alignment; // value of ObjectAlignmentInBytes ++ bool _is_default_jsa; // indicates whether is the default jsa file + + struct space_info { + int _crc; // crc checksum of the current space +@@ -264,6 +269,8 @@ public: + bool is_open() { return _file_open; } + bool is_static() const { return _is_static; } + bool is_mapped() const { return _is_mapped; } ++ bool is_default_jsa() const { return _header->_is_default_jsa; } ++ void set_is_default_jsa(bool v) { _header->_is_default_jsa = v; } + void set_is_mapped(bool v) { _is_mapped = v; } + ReservedSpace reserve_shared_memory(); + void set_requested_base(char* b) { dynamic_header()->set_requested_base(b); } +diff --git a/hotspot/src/share/vm/memory/metachunk.hpp b/hotspot/src/share/vm/memory/metachunk.hpp +index e873dc6a..7889b622 100644 +--- a/hotspot/src/share/vm/memory/metachunk.hpp ++++ b/hotspot/src/share/vm/memory/metachunk.hpp +@@ -126,6 +126,8 @@ class Metachunk : public Metabase { + + VirtualSpaceNode* container() const { return _container; } + ++ void reset_container() { _container = NULL; } ++ + MetaWord* bottom() const { return (MetaWord*) this; } + + // Reset top to bottom so chunk can be reused. +diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp +index 7e95b5c0..6c4654b2 100644 +--- a/hotspot/src/share/vm/memory/metaspace.cpp ++++ b/hotspot/src/share/vm/memory/metaspace.cpp +@@ -775,6 +775,7 @@ class SpaceManager : public CHeapObj { + // Notify memory usage to MemoryService. + void track_metaspace_memory_usage(); + ++ void reset_metachunks(); + // debugging support. + + void dump(outputStream* const out) const; +@@ -1923,6 +1924,15 @@ void ChunkManager::print_on(outputStream* out) const { + + // SpaceManager methods + ++void SpaceManager::reset_metachunks() { ++ for (ChunkIndex i = ZeroIndex; i <= HumongousIndex; i = next_chunk_index(i)) { ++ Metachunk* chunks = chunks_in_use(i); ++ if (chunks != NULL) { ++ chunks->reset_container(); ++ } ++ } ++} ++ + size_t SpaceManager::adjust_initial_chunk_size(size_t requested, bool is_class_space) { + size_t chunk_sizes[] = { + specialized_chunk_size(is_class_space), +@@ -3002,6 +3012,10 @@ Metaspace::~Metaspace() { + } + } + ++void Metaspace::reset_metachunks() { ++ vsm()->reset_metachunks(); ++} ++ + VirtualSpaceList* Metaspace::_space_list = NULL; + VirtualSpaceList* Metaspace::_class_space_list = NULL; + +diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp +index 2b06cb62..122dd4bf 100644 +--- a/hotspot/src/share/vm/memory/metaspace.hpp ++++ b/hotspot/src/share/vm/memory/metaspace.hpp +@@ -243,6 +243,8 @@ class Metaspace : public CHeapObj { + MetaWord* expand_and_allocate(size_t size, + MetadataType mdtype); + ++ void reset_metachunks(); ++ + static bool contains(const void* ptr); + + void dump(outputStream* const out) const; +diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp +index 00fb9fe9..b31d0a3f 100644 +--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp ++++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp +@@ -205,6 +205,21 @@ static void patch_klass_vtables(void** vtbl_list, void* new_vtable_start) { + } + } + ++static void patch_deallocate_meta_vtables(void** vtbl_list, void* new_vtable_start, GrowableArray* deallocate_list) { ++ if (deallocate_list == NULL) { ++ return; ++ } ++ for (int i = deallocate_list->length() - 1; i >= 0; i--) { ++ Metadata* m = deallocate_list->at(i); ++ if (!m->on_stack()) { ++ if (m->is_constantPool()) { ++ ((ConstantPool*)m)->remove_unshareable_info(); ++ *(void**)m = find_matching_vtbl_ptr(vtbl_list, new_vtable_start, m); ++ } ++ } ++ } ++} ++ + // Closure for serializing initialization data out to a data area to be + // written to the shared file. + +@@ -591,6 +606,7 @@ void VM_PopulateDumpSharedSpace::doit() { + // Update the vtable pointers in all of the Klass objects in the + // heap. They should point to newly generated vtable. + patch_klass_vtables(vtbl_list, vtable); ++ patch_deallocate_meta_vtables(vtbl_list, vtable, _loader_data->_deallocate_list); + + // dunno what this is for. + char* saved_vtbl = (char*)os::malloc(vtbl_list_size * sizeof(void*), mtClass); +@@ -602,6 +618,9 @@ void VM_PopulateDumpSharedSpace::doit() { + FileMapInfo* mapinfo = new FileMapInfo(); + mapinfo->populate_header(MetaspaceShared::max_alignment()); + ++ if (Arguments::get_is_default_jsa()) { ++ mapinfo->set_is_default_jsa(true); ++ } + // Pass 1 - update file offsets in header. + mapinfo->write_header(); + mapinfo->write_space(MetaspaceShared::ro, _loader_data->ro_metaspace(), true); +@@ -997,6 +1016,8 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { + mapinfo->verify_region_checksum(d_rw) && + (_ro_base = mapinfo->map_region(d_ro)) != NULL && + mapinfo->verify_region_checksum(d_ro) && ++ (_ro_base = mapinfo->map_region(d_md)) != NULL && ++ mapinfo->verify_region_checksum(d_md) && + (image_alignment == (size_t)max_alignment())) { + mapinfo->set_is_mapped(true); + return true; +@@ -1153,6 +1174,7 @@ void MetaspaceShared::initialize_shared_spaces() { + ReadClosure rc(&buffer); + SymbolTable::serialize_shared_table_header(&rc); + SystemDictionaryShared::serialize_dictionary_headers(&rc); ++ ClassLoader::deserialize_package_hash_table(dynamic_mapinfo->region_base(d_md)); + dynamic_mapinfo->close(); + } + +diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp +index a9dadfbb..3eb8b12c 100644 +--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp ++++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp +@@ -90,8 +90,9 @@ class MetaspaceShared : AllStatic { + // core dynamic archive spaces + d_rw = 0, // read-write shared space in the heap + d_ro = 1, // read-only shared space in the heap +- d_bm = 2, // relocation bitmaps (freed after file mapping is finished) +- d_n_regions = 2 // d_rw and d_ro ++ d_md = 2, // miscellaneous data ++ d_bm = 3, // relocation bitmaps (freed after file mapping is finished) ++ d_n_regions = 3 // d_rw, d_ro, d_md + }; + + // Accessor functions to save shared space created for metadata, which has +diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp +index 0d1b1a8d..9276b895 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.cpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.cpp +@@ -2633,7 +2633,7 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl + + // returns true IFF is_in_error_state() has been changed as a result of this call. + bool InstanceKlass::check_sharing_error_state() { +- assert(DumpSharedSpaces, "should only be called during dumping"); ++ assert(DynamicDumpSharedSpaces || DumpSharedSpaces, "should only be called during dumping"); + bool old_state = is_in_error_state(); + + if (!is_in_error_state()) { +@@ -3573,6 +3573,9 @@ void InstanceKlass::verify_on(outputStream* st) { + // Avoid redundant verifies, this really should be in product. + if (_verify_count == Universe::verify_count()) return; + _verify_count = Universe::verify_count(); ++ if (is_in_error_state()) { ++ return; ++ } + #endif + + // Verify Klass +diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp +index 1f603021..5a79ab7e 100644 +--- a/hotspot/src/share/vm/runtime/arguments.cpp ++++ b/hotspot/src/share/vm/runtime/arguments.cpp +@@ -100,6 +100,7 @@ do { \ + } \ + } while(0) + ++bool Arguments::_is_default_jsa = false; + char** Arguments::_jvm_flags_array = NULL; + int Arguments::_num_jvm_flags = 0; + char** Arguments::_jvm_args_array = NULL; +@@ -4041,23 +4042,32 @@ static void force_serial_gc() { + } + #endif // INCLUDE_ALL_GCS + ++char* Arguments::get_default_shared_archive_path() { ++ char *default_archive_path; ++ char jvm_path[JVM_MAXPATHLEN]; ++ os::jvm_path(jvm_path, sizeof(jvm_path)); ++ char *end = strrchr(jvm_path, *os::file_separator()); ++ if (end != NULL) { ++ *end = '\0'; ++ } ++ size_t jvm_path_len = strlen(jvm_path); ++ size_t file_sep_len = strlen(os::file_separator()); ++ const size_t len = jvm_path_len + file_sep_len + 20; ++ default_archive_path = NEW_C_HEAP_ARRAY(char, len, mtInternal); ++ if (default_archive_path != NULL) { ++ jio_snprintf(default_archive_path, len, "%s%sclasses.jsa", ++ jvm_path, os::file_separator()); ++ } ++ Arguments::set_is_default_jsa(true); ++ return default_archive_path; ++} ++ + // Sharing support + // Construct the path to the archive + static char* get_shared_archive_path() { + char *shared_archive_path; + if (SharedArchiveFile == NULL) { +- char jvm_path[JVM_MAXPATHLEN]; +- os::jvm_path(jvm_path, sizeof(jvm_path)); +- char *end = strrchr(jvm_path, *os::file_separator()); +- if (end != NULL) *end = '\0'; +- size_t jvm_path_len = strlen(jvm_path); +- size_t file_sep_len = strlen(os::file_separator()); +- const size_t len = jvm_path_len + file_sep_len + 20; +- shared_archive_path = NEW_C_HEAP_ARRAY(char, len, mtInternal); +- if (shared_archive_path != NULL) { +- jio_snprintf(shared_archive_path, len, "%s%sclasses.jsa", +- jvm_path, os::file_separator()); +- } ++ shared_archive_path = Arguments::get_default_shared_archive_path(); + } else { + shared_archive_path = os::strdup(SharedArchiveFile, mtInternal); + } +diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp +index 19f5cb60..65907eb4 100644 +--- a/hotspot/src/share/vm/runtime/arguments.hpp ++++ b/hotspot/src/share/vm/runtime/arguments.hpp +@@ -240,6 +240,8 @@ class Arguments : AllStatic { + + private: + ++ // Indicates whether the JSA file is the default jsa file. ++ static bool _is_default_jsa; + // an array containing all flags specified in the .hotspotrc file + static char** _jvm_flags_array; + static int _num_jvm_flags; +@@ -487,6 +489,9 @@ class Arguments : AllStatic { + // Return the maximum size a heap with compressed oops can take + static size_t max_heap_for_compressed_oops(); + ++ static void set_is_default_jsa(bool is_default) { _is_default_jsa = is_default; } ++ static bool get_is_default_jsa() { return _is_default_jsa; } ++ + // return a char* array containing all options + static char** jvm_flags_array() { return _jvm_flags_array; } + static char** jvm_args_array() { return _jvm_args_array; } +@@ -622,6 +627,7 @@ class Arguments : AllStatic { + static char* get_ext_dirs() { return _java_ext_dirs->value(); } + static char* get_appclasspath() { return _java_class_path->value(); } + static void fix_appclasspath(); ++ static char* get_default_shared_archive_path(); + + // Operation modi + static Mode mode() { return _mode; } +diff --git a/hotspot/src/share/vm/utilities/hashtable.cpp b/hotspot/src/share/vm/utilities/hashtable.cpp +index 66df8f1f..df290d99 100644 +--- a/hotspot/src/share/vm/utilities/hashtable.cpp ++++ b/hotspot/src/share/vm/utilities/hashtable.cpp +@@ -58,6 +58,7 @@ template BasicHashtableEntry* BasicHashtable::new_entry(unsig + len = 1 << log2_int(len); // round down to power of 2 + assert(len >= _entry_size, ""); + _first_free_entry = NEW_C_HEAP_ARRAY2(char, len, F, CURRENT_PC); ++ memset(_first_free_entry, 0, len); + _end_block = _first_free_entry + len; + } + entry = (BasicHashtableEntry*)_first_free_entry; +diff --git a/hotspot/test/runtime/appcds/TestCommon.java b/hotspot/test/runtime/appcds/TestCommon.java +index 22eef4ed..6a61dc31 100644 +--- a/hotspot/test/runtime/appcds/TestCommon.java ++++ b/hotspot/test/runtime/appcds/TestCommon.java +@@ -54,6 +54,7 @@ public class TestCommon extends CDSTestUtils { + System.getProperty("test.timeout.factor", "1.0"); + + private static String currentArchiveName; ++ private static String topArchiveName; + + // Call this method to start new archive with new unique name + public static void startNewArchiveName() { +@@ -62,6 +63,13 @@ public class TestCommon extends CDSTestUtils { + timeStampFormat.format(new Date()) + ".jsa"; + } + ++ public static String getTopArchiveName() { ++ topArchiveName = System.getProperty("user.dir") + ++ File.separator + "d-appcds-" + timeStampFormat.format(new Date()) + ".jsa"; ++ currentArchiveName = topArchiveName; ++ return topArchiveName; ++ } ++ + // Call this method to get current archive name + public static String getCurrentArchiveName() { + return currentArchiveName; +@@ -90,6 +98,16 @@ public class TestCommon extends CDSTestUtils { + } + } + ++ public static void deletePriorTopArchives() { ++ File dir = new File(System.getProperty("user.dir")); ++ String files[] = dir.list(); ++ for (String name : files) { ++ if (name.startsWith("d-appcds-") && name.endsWith(".jsa")) { ++ if (!(new File(dir, name)).delete()) ++ System.out.println("deletePriorArchives(): delete failed for file " + name); ++ } ++ } ++ } + + // Create AppCDS archive using most common args - convenience method + // Legacy name preserved for compatibility +@@ -132,7 +150,6 @@ public class TestCommon extends CDSTestUtils { + + cmd.add("-Xshare:dump"); + cmd.add("-XX:+UseAppCDS"); +-// cmd.add("-Xlog:cds,cds+hashtables"); comment out because it will be run by jdk1.8 + cmd.add("-XX:ExtraSharedClassListFile=" + classList.getPath()); + + if (opts.archiveName == null) +@@ -147,6 +164,36 @@ public class TestCommon extends CDSTestUtils { + return executeAndLog(pb, "dump"); + } + ++ public static OutputAnalyzer createBaseArchive(String appJar, String appClasses[], String... suffix) ++ throws Exception { ++ return createArchive(appJar, appClasses, suffix); ++ } ++ ++ public static OutputAnalyzer createTopArchive(String appJar, String...suffix) ++ throws Exception { ++ AppCDSOptions opts = new AppCDSOptions(); ++ opts.setAppJar(appJar); ++ opts.addSuffix(suffix); ++ ++ ArrayList cmd = new ArrayList(); ++ cmd.add("-cp"); ++ cmd.add(opts.appJar); ++ ++ String baseArchiveName = getCurrentArchiveName(); ++ deletePriorTopArchives(); ++ String topArchiveNmae = getTopArchiveName(); ++ cmd.add("-XX:+UnlockExperimentalVMOptions"); ++ cmd.add("-Xshare:on"); ++ cmd.add("-XX:SharedArchiveFile=" + baseArchiveName); ++ cmd.add("-XX:ArchiveClassesAtExit=" + topArchiveNmae); ++ cmd.add("-XX:+InfoDynamicCDS"); ++ ++ for (String s : opts.suffix) cmd.add(s); ++ ++ String[] cmdLine = cmd.toArray(new String[cmd.size()]); ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, makeCommandLineForAppCDS(cmdLine)); ++ return executeAndLog(pb, "dump"); ++ } + + // Execute JVM using AppCDS archive with specified AppCDSOptions + public static OutputAnalyzer runWithArchive(AppCDSOptions opts) +@@ -156,6 +203,9 @@ public class TestCommon extends CDSTestUtils { + + for (String p : opts.prefix) cmd.add(p); + ++ if (topArchiveName != null) { ++ cmd.add("-XX:+InfoDynamicCDS"); ++ } + cmd.add("-Xshare:" + opts.xShareMode); + cmd.add("-XX:+UseAppCDS"); + cmd.add("-showversion"); +@@ -174,7 +224,6 @@ public class TestCommon extends CDSTestUtils { + return executeAndLog(pb, "exec"); + } + +- + public static OutputAnalyzer execCommon(String... suffix) throws Exception { + AppCDSOptions opts = (new AppCDSOptions()); + opts.addSuffix(suffix); +@@ -261,6 +310,27 @@ public class TestCommon extends CDSTestUtils { + } + + ++ public static OutputAnalyzer testDynamicCDS(String appJar, String appClasses[], String... args) ++ throws Exception { ++ // Create base archive ++ OutputAnalyzer output = createBaseArchive(appJar, appClasses, args); ++ output.shouldContain("Loading classes to share"); ++ output.shouldHaveExitValue(0); ++ ++ // Create top archive ++ output = createTopArchive(appJar, args); ++ output.shouldContain("Written dynamic archive"); ++ output.shouldHaveExitValue(0); ++ ++ // Exec with top archive ++ output = exec(appJar, args); ++ ++ // Check exec result ++ checkMatches(output, "SharedArchivePath", "SharedDynamicArchivePath"); ++ output.shouldHaveExitValue(0); ++ return output; ++ } ++ + public static OutputAnalyzer checkExecReturn(OutputAnalyzer output, int ret, + boolean checkContain, String... matches) throws Exception { + try { +diff --git a/hotspot/test/runtime/appcds/dynamicArchive/DynamicFlag.java b/hotspot/test/runtime/appcds/dynamicArchive/DynamicFlag.java +new file mode 100644 +index 00000000..79f30759 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/dynamicArchive/DynamicFlag.java +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary The DynamicDumpShareSpaces flag is internal, setting it at the command line should have no effect. ++ * @library /testlibrary /runtime/appcds /runtime/appcds/test-classes ++ * @compile ../test-classes/Hello.java ++ * @run driver DynamicFlag ++ */ ++ ++public class DynamicFlag { ++ public static void main(String[] args) throws Exception { ++ TestCommon.testDynamicCDS(JarBuilder.getOrCreateHelloJar(), ++ TestCommon.list("Hello"), "-XX:+DynamicDumpSharedSpaces", "Hello"); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/dynamicArchive/DynamicHelloTest.java b/hotspot/test/runtime/appcds/dynamicArchive/DynamicHelloTest.java +new file mode 100644 +index 00000000..48e97cb2 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/dynamicArchive/DynamicHelloTest.java +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary Hello World test for dynamic cds ++ * @library /testlibrary /runtime/appcds /runtime/appcds/test-classes ++ * @compile ../test-classes/Hello.java ++ * @run main DynamicHelloTest ++ */ ++ ++public class DynamicHelloTest { ++ public static void main(String[] args) throws Exception { ++ TestCommon.testDynamicCDS(JarBuilder.getOrCreateHelloJar(), ++ null, "Hello"); ++ ++ TestCommon.testDynamicCDS(JarBuilder.getOrCreateHelloJar(), ++ TestCommon.list("Hello"), "Hello"); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/dynamicArchive/VerifyWithDynamicArchive.java b/hotspot/test/runtime/appcds/dynamicArchive/VerifyWithDynamicArchive.java +new file mode 100644 +index 00000000..eacc1aff +--- /dev/null ++++ b/hotspot/test/runtime/appcds/dynamicArchive/VerifyWithDynamicArchive.java +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary Hello World test for dynamic cds ++ * @library /testlibrary /runtime/appcds /runtime/appcds/test-classes ++ * @compile ../test-classes/Hello.java ++ * @run main VerifyWithDynamicArchive ++ */ ++ ++public class VerifyWithDynamicArchive { ++ public static void main(String[] args) throws Exception { ++ TestCommon.testDynamicCDS(JarBuilder.getOrCreateHelloJar(), ++ null, "-XX:+VerifySharedSpaces", "Hello"); ++ ++ TestCommon.testDynamicCDS(JarBuilder.getOrCreateHelloJar(), ++ TestCommon.list("Hello"), "-XX:+VerifySharedSpaces", "Hello"); ++ } ++} +diff --git a/jdk/make/BuildJdk.gmk b/jdk/make/BuildJdk.gmk +index 467792fa..bb8ea8a9 100644 +--- a/jdk/make/BuildJdk.gmk ++++ b/jdk/make/BuildJdk.gmk +@@ -103,6 +103,13 @@ images: + ifeq ($(OPENJDK_TARGET_OS), macosx) + +$(MAKE) -f Bundles.gmk + endif ++ ifeq ($(BUILD_CDS_ARCHIVE), true) ++ echo Creating CDS archive for jdk image ++ $(JDK_IMAGE_DIR)/bin/java -Xshare:dump -Xmx128M -Xms128M -XX:ParallelGCThreads=1 -Xint $(LOG_INFO) ++ echo Creating CDS archive for jre image ++ $(JRE_IMAGE_DIR)/bin/java -Xshare:dump -Xmx128M -Xms128M -XX:ParallelGCThreads=1 -Xint $(LOG_INFO) ++ endif ++ + + overlay-images: + +$(MAKE) -f CompileLaunchers.gmk OVERLAY_IMAGES=true diff --git a/8268819-SA-Remove-libthread_db-dependency-on-Linux.patch b/8268819-SA-Remove-libthread_db-dependency-on-Linux.patch index 77849a111712c40620012c1e4fca2ec31eafca85..d2d7530d28640879516f4cf7dfdc1ccc288f1855 100644 --- a/8268819-SA-Remove-libthread_db-dependency-on-Linux.patch +++ b/8268819-SA-Remove-libthread_db-dependency-on-Linux.patch @@ -3,11 +3,6 @@ From: d30023828 Date: Wed, 9 Feb 2022 18:32:05 +0800 Subject: [PATCH 3/8] 8268819: SA: Remove libthread_db dependency on Linux -DTS/AR: DTS2022020914784 -Summary:hotspot:SA: Remove libthread_db dependency on Linux -LLT:NA -Patch Type:backport -Bug url:https://bugs.openjdk.java.net/browse/JDK-8268819 --- .../agent/src/os/linux/LinuxDebuggerLocal.c | 3 +- hotspot/agent/src/os/linux/Makefile | 6 +- @@ -319,23 +314,16 @@ index 802e5b0bb..a8e0c2a5c 100644 - #endif /* _PROC_SERVICE_H_ */ diff --git a/hotspot/agent/src/os/linux/ps_core.c b/hotspot/agent/src/os/linux/ps_core.c -index b7fe4c095..6da43f195 100644 +index 6fb8c940..5728bcc4 100644 --- a/hotspot/agent/src/os/linux/ps_core.c +++ b/hotspot/agent/src/os/linux/ps_core.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2003, 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 @@ -31,6 +31,7 @@ #include #include #include "libproc_impl.h" +#include "proc_service.h" #include "salibelf.h" - + // This file has the libproc implementation to read core files. @@ -546,8 +547,7 @@ static bool core_handle_prstatus(struct ps_prochandle* ph, const char* buf, size prstatus_t* prstat = (prstatus_t*) buf; @@ -343,9 +331,9 @@ index b7fe4c095..6da43f195 100644 print_debug("got integer regset for lwp %d\n", prstat->pr_pid); - // we set pthread_t to -1 for core dump - if((newthr = add_thread_info(ph, (pthread_t) -1, prstat->pr_pid)) == NULL) -+ if((newthr = add_thread_info(ph, prstat->pr_pid)) == NULL) ++ if((newthr = add_thread_info(ph, prstat->pr_pid)) == NULL) return false; - + // copy regs diff --git a/hotspot/agent/src/os/linux/ps_proc.c b/hotspot/agent/src/os/linux/ps_proc.c index c4d6a9ecc..748cc1397 100644 diff --git a/8287109-Distrust-failed-with-CertificateExpired.patch b/8287109-Distrust-failed-with-CertificateExpired.patch new file mode 100644 index 0000000000000000000000000000000000000000..11a8755508584eac643789f7ab155d4fba5a59b2 --- /dev/null +++ b/8287109-Distrust-failed-with-CertificateExpired.patch @@ -0,0 +1,237 @@ +From d2d3408154beb52370ee8784767375a7cc8d325d Mon Sep 17 00:00:00 2001 +Date: Wed, 21 Sep 2022 10:31:17 +0800 +Subject: 8287109: Distrust.java failed with CertificateExpiredException + +--- + .../Symantec/Distrust.java | 26 +++++- + .../Symantec/appleistca2g1-chain.pem | 80 ------------------- + .../Symantec/geotrustglobalca-chain.pem | 66 --------------- + 3 files changed, 23 insertions(+), 149 deletions(-) + delete mode 100644 jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/appleistca2g1-chain.pem + delete mode 100644 jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustglobalca-chain.pem + +diff --git a/jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java b/jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java +index d394f417..22266255 100644 +--- a/jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java ++++ b/jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java +@@ -51,15 +51,14 @@ public class Distrust { + // Each of the roots have a test certificate chain stored in a file + // named "-chain.pem". + private static String[] rootsToTest = new String[] { +- "geotrustglobalca", "geotrustprimarycag2", "geotrustprimarycag3", ++ "geotrustprimarycag2", "geotrustprimarycag3", + "geotrustuniversalca", "thawteprimaryrootca", "thawteprimaryrootcag2", + "thawteprimaryrootcag3", "verisignclass3g3ca", "verisignclass3g4ca", + "verisignclass3g5ca", "verisignuniversalrootca" }; + + // Each of the subCAs with a delayed distrust date have a test certificate + // chain stored in a file named "-chain.pem". +- private static String[] subCAsToTest = new String[] { +- "appleistca2g1", "appleistca8g1" }; ++ private static String[] subCAsToTest = new String[] {"appleistca8g1"}; + + // A date that is after the restrictions take affect + private static final Date APRIL_17_2019 = +@@ -177,6 +176,11 @@ public class Distrust { + throw new Exception("chain should be invalid"); + } + } catch (CertificateException ce) { ++ // expired TLS certificates should not be treated as failure ++ if (expired(ce)) { ++ System.err.println("Test is N/A, chain is expired"); ++ return; ++ } + if (valid) { + throw new Exception("Unexpected exception, chain " + + "should be valid", ce); +@@ -184,6 +188,7 @@ public class Distrust { + if (ce instanceof ValidatorException) { + ValidatorException ve = (ValidatorException)ce; + if (ve.getErrorType() != ValidatorException.T_UNTRUSTED_CERT) { ++ ce.printStackTrace(System.err); + throw new Exception("Unexpected exception: " + ce); + } + } else { +@@ -192,6 +197,21 @@ public class Distrust { + } + } + ++ // check if a cause of exception is an expired cert ++ private static boolean expired(CertificateException ce) { ++ if (ce instanceof CertificateExpiredException) { ++ return true; ++ } ++ Throwable t = ce.getCause(); ++ while (t != null) { ++ if (t instanceof CertificateExpiredException) { ++ return true; ++ } ++ t = t.getCause(); ++ } ++ return false; ++ } ++ + private static X509Certificate[] loadCertificateChain(String name) + throws Exception { + try (InputStream in = new FileInputStream(TEST_SRC + File.separator + +diff --git a/jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/appleistca2g1-chain.pem b/jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/appleistca2g1-chain.pem +deleted file mode 100644 +index 0235631d..00000000 +--- a/jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/appleistca2g1-chain.pem ++++ /dev/null +@@ -1,80 +0,0 @@ +------BEGIN CERTIFICATE----- +-MIIGGzCCBQOgAwIBAgIITJltLCqcD0gwDQYJKoZIhvcNAQELBQAwYjEcMBoGA1UE +-AxMTQXBwbGUgSVNUIENBIDIgLSBHMTEgMB4GA1UECxMXQ2VydGlmaWNhdGlvbiBB +-dXRob3JpdHkxEzARBgNVBAoTCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMB4XDTE5 +-MDEwODIxMTcxNFoXDTIwMDgwODIxMjcwMFowgaoxSjBIBgNVBAMMQWFjdGl2ZS5n +-ZW90cnVzdC1nbG9iYWwtY2EudGVzdC1wYWdlcy5jZXJ0aWZpY2F0ZW1hbmFnZXIu +-YXBwbGUuY29tMSUwIwYDVQQLDBxtYW5hZ2VtZW50OmlkbXMuZ3JvdXAuODY0ODU5 +-MRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMQswCQYD +-VQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMCjFUrVHTEX +-0aVU6x9LiGa6oVr9blaCsMFrLicPQguc43Vs/pN+g4jzRXsTSMe9XefezBQb6tzZ +-SMRXVB4kWMr4K1BVgQDkXeyoh4KrXRkdEF9ZIJPNxwTmmYUOc5M6NOYwkLelYz+t +-7n1iNIGylbjwU4qwauElk2alFVqYTEPDLzwvqVDb9jMAJ8MPSDjfUlXW0XD9oXZM +-hC+8LU9JBgJ3YBdzRHa4WnrudUbWjspqaNfAYpVIX0cfCJKnMsKqaSKjS4pIRtWm +-L6NlCTCoIMyOh+wmbWPPX24H2D3+ump5FA35fRYbVznmosl5n1AK34S9tD4XZ7lO +-WZKfaFi1liMCAwEAAaOCAoowggKGMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU +-2HqURHyQcJAWnt0XnAFEA4bWKikwfgYIKwYBBQUHAQEEcjBwMDQGCCsGAQUFBzAC +-hihodHRwOi8vY2VydHMuYXBwbGUuY29tL2FwcGxlaXN0Y2EyZzEuZGVyMDgGCCsG +-AQUFBzABhixodHRwOi8vb2NzcC5hcHBsZS5jb20vb2NzcDAzLWFwcGxlaXN0Y2Ey +-ZzEwMTBMBgNVHREERTBDgkFhY3RpdmUuZ2VvdHJ1c3QtZ2xvYmFsLWNhLnRlc3Qt +-cGFnZXMuY2VydGlmaWNhdGVtYW5hZ2VyLmFwcGxlLmNvbTCB/wYDVR0gBIH3MIH0 +-MIHxBgoqhkiG92NkBQsEMIHiMIGkBggrBgEFBQcCAjCBlwyBlFJlbGlhbmNlIG9u +-IHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5j +-ZSBvZiBhbnkgYXBwbGljYWJsZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2Ug +-YW5kL29yIGNlcnRpZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wOQYIKwYB +-BQUHAgEWLWh0dHA6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5 +-L3JwYTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwNwYDVR0fBDAwLjAs +-oCqgKIYmaHR0cDovL2NybC5hcHBsZS5jb20vYXBwbGVpc3RjYTJnMS5jcmwwHQYD +-VR0OBBYEFP0qkmFJhArI0MsfW0V+/wY9x4GSMA4GA1UdDwEB/wQEAwIFoDANBgkq +-hkiG9w0BAQsFAAOCAQEATjT8M0bIq+mFc8k5cd4KDjCMBjYl/l3/8zKlWYGP+nl1 +-KRogXcGRa3LcfpdJcqgMrx8e9Xohduvl8MBzwv671rYkppzZdsmZdLVorAdbL5GL +-suhTjAS5yL3NBWNMRpeOgFsVr7YtPDEvo3CFsnzjg7THe0S6Y35oYukJtUzGUvSY +-kC3ApBTdjj0vAeow+dbt+AHKnQiEnon4ToSFmtnkru08Uxe7uyHCQ2sLUg0EPYc9 +-t9I8lviaHfK/mQoCzlme2O/H5Rher8dXCv8hVT1NKbsi28EpgpqcTLS+hn/Edc/q +-4dPDoO1Ozs+ixRzFeMpA+JrnAyARb6qbSrAPBgtIbQ== +------END CERTIFICATE----- +------BEGIN CERTIFICATE----- +-MIIEQDCCAyigAwIBAgIDAjp0MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +-MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +-YWwgQ0EwHhcNMTQwNjE2MTU0MjAyWhcNMjIwNTIwMTU0MjAyWjBiMRwwGgYDVQQD +-ExNBcHBsZSBJU1QgQ0EgMiAtIEcxMSAwHgYDVQQLExdDZXJ0aWZpY2F0aW9uIEF1 +-dGhvcml0eTETMBEGA1UEChMKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwggEiMA0G +-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQk6EdR0MgFrILa+vD1bTox5jN896/ +-6E3p4zaAB/xFG2p8RYauVtOkCX9hDWtdflJrfbTIOcT0Zzr3g84Zb4YvfkV+Rxxn +-UsqVBV3iNlGFwNRngDVvFd0+/R3S/Y80UNjsdiq+49Pa5P3I6ygClhGXF2Ec6cRZ +-O0LcMtEJHdqm0UOG/16yvIzPZtsBiwKulEjzOI/96jKoCOyGl1GUJD5JSZZT6Hmh +-QIHpBbuTlVH84/18EUv3ngizFUkVB/nRN6CbSzL2tcTcatH8Cu324MUpoKiLcf4N +-krz+VHAYCm3H7Qz7yS0Gw4yF/MuGXNY2jhKLCX/7GRo41fCUMHoPpozzAgMBAAGj +-ggEdMIIBGTAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjAdBgNVHQ4E +-FgQU2HqURHyQcJAWnt0XnAFEA4bWKikwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNV +-HQ8BAf8EBAMCAQYwNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2cuc3ltY2IuY29t +-L2NybHMvZ3RnbG9iYWwuY3JsMC4GCCsGAQUFBwEBBCIwIDAeBggrBgEFBQcwAYYS +-aHR0cDovL2cuc3ltY2QuY29tMEwGA1UdIARFMEMwQQYKYIZIAYb4RQEHNjAzMDEG +-CCsGAQUFBwIBFiVodHRwOi8vd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvY3Bz +-MA0GCSqGSIb3DQEBCwUAA4IBAQAWR3NvhaJi4ecqdruJlUIml7xKrKxwUzo/MYM9 +-PByrmuKxXRx2GqA8DHJXvtOeUODImdZY1wLqzg0pVHzN9cLGkClVo28UqAtCDTqY +-bQZ4nvBqox0CCqIopI3CgUY+bWfa3j/+hQ5CKhLetbf7uBunlux3n+zUU5V6/wf0 +-8goUwFFSsdaOUAsamVy8C8m97e34XsFW201+I6QRoSzUGwWa5BtS9nw4mQVLunKN +-QolgBGYq9P1o12v3mUEo1mwkq+YlUy7Igpnioo8jvjCDsSeL+mh/AUnoxphrEC6Y +-XorXykuxx8lYmtA225aV7LaB5PLNbxt5h0wQPInkTfpU3Kqm +------END CERTIFICATE----- +------BEGIN CERTIFICATE----- +-MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +-MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +-YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +-EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +-R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +-9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +-fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +-iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +-1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +-bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +-MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +-ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +-uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +-Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +-tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +-PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +-hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +-5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +------END CERTIFICATE----- +diff --git a/jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustglobalca-chain.pem b/jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustglobalca-chain.pem +deleted file mode 100644 +index 3249716b..00000000 +--- a/jdk/test/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustglobalca-chain.pem ++++ /dev/null +@@ -1,66 +0,0 @@ +------BEGIN CERTIFICATE----- +-MIIHBjCCBe6gAwIBAgIQanINWwJAuap0V7lFjnfUwTANBgkqhkiG9w0BAQsFADBE +-MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMU +-R2VvVHJ1c3QgU1NMIENBIC0gRzMwHhcNMTcwNTAzMDAwMDAwWhcNMjAwNTAyMjM1 +-OTU5WjCBkTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNV +-BAcMDU1vdW50YWluIFZpZXcxFzAVBgNVBAoMDkdlb1RydXN0LCBJbmMuMRgwFgYD +-VQQLDA9Sb290IDEwIC0gVkFMSUQxIjAgBgNVBAMMGXZhbGlkLXJvb3QxMC5nZW90 +-cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTegUYhAh0 +-P7aF6jzk8dit4Vzddo3hM+J7Eak/+N1sqVUS2HpNd7VO50FrbEWKIRusv7QNtlpY +-1Cgrla8M4RAhCB0wkkHXZ1Evz6E1AEFQqNSjyuRQxeEXl+xCL+MF+yAMhDRnHh+E +-eSJ3ie0T66saOyaLM9fPpr3xomAQ/IRlP1atJ/Z8XbPo25HuxwzxiWFW+RjwVIfI +-gxHz4Okwc1uImDUIDlEu9Uaqqb4jHhxU1EkKMmgEncpqwCROcZMujUkogfB49Z7+ +-K17r6ARIrUuxqfNPrPwe+O88WgIeDSWffPM67UlvtomZOwuTNdv9OoCX1wUCLS7m +-/gZ3rqqqeJvfAgMBAAGjggOkMIIDoDAkBgNVHREEHTAbghl2YWxpZC1yb290MTAu +-Z2VvdHJ1c3QuY29tMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgWgMCsGA1UdHwQk +-MCIwIKAeoByGGmh0dHA6Ly9nbi5zeW1jYi5jb20vZ24uY3JsMIGdBgNVHSAEgZUw +-gZIwgY8GBmeBDAECAjCBhDA/BggrBgEFBQcCARYzaHR0cHM6Ly93d3cuZ2VvdHJ1 +-c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5L2xlZ2FsMEEGCCsGAQUFBwICMDUM +-M2h0dHBzOi8vd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvcmVwb3NpdG9yeS9s +-ZWdhbDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHwYDVR0jBBgwFoAU +-0m/3lvSFP3I8MH0j2oV4m6N8WnwwVwYIKwYBBQUHAQEESzBJMB8GCCsGAQUFBzAB +-hhNodHRwOi8vZ24uc3ltY2QuY29tMCYGCCsGAQUFBzAChhpodHRwOi8vZ24uc3lt +-Y2IuY29tL2duLmNydDCCAfUGCisGAQQB1nkCBAIEggHlBIIB4QHfAHUA3esdK3oN +-T6Ygi4GtgWhwfi6OnQHVXIiNPRHEzbbsvswAAAFbz9h5vQAABAMARjBEAiAx/C0U +-5NdHxK4v2oHnstYksb1Vny8PcQkSvgpx9PsZEwIgNTOU70Zc5szG23xdbvtoH5lN +-SAoVswiF5gFQS5MGu1sAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3c +-EAAAAVvP2HnZAAAEAwBHMEUCIFGjB8r2H0VDwTUE/aY/Mv+M97sqAvEP1doOcHpg +-0qyfAiEArw/S2F7OEcmKGUY1WRBuApfAx5d7hzrTSV/jZv95qJwAdgDuS723dc5g +-uuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAVvP2HoDAAAEAwBHMEUCIQCH6MFZ +-tZF3Cqukt3/69fkU0Y5ePXXx8+xkOXRsIG3EGgIgSmCBWrnmPiiGA3x5QP8I8m4r +-Uee0y7s4NQNwjMgHrjwAdgC8eOHfxfY8aEZJM02hD6FfCXlpIAnAgbTz9pF/Ptm4 +-pQAAAVvP2HqcAAAEAwBHMEUCIA8e2kAVYYuQCtn4PqK98BuHnLm9rC40DboFLCle +-SmQsAiEApbCJR05hr9VkNWmjaaUUGGZdVyUu9XX504LHVWyXZDUwDQYJKoZIhvcN +-AQELBQADggEBAEtfBfZ2y5uTohvW3h00Kcuop6Nq7Y59GU3MeizPKtx48DB8qHyd +-y5bLFwXzsGA1WkwpKzPbROsTGcAAXJHh03bj24AemUr/J/eQcjkfSoNBdHDpiSsk +-VZkQK2fGJDiYJ/r9mxKZcgd2pyN3l2OtVtNMv2dnFGF35UkkeqO3jqImwbypAmRX +-HdQV9dvW2YDRjzkebNNey6UwY9+YTSzr4da2hcaMHrj588Eqa4DDgNcY9QnE2RzN +-giArA+4RlM4AZ3jC2A756I67hrlvH+lhumHLp06hGfMiQJF1aaauFVSa36HKc3C/ +-ty+sLdJbemEJLAr8uNXggFD+U8TKw1S4LSw= +------END CERTIFICATE----- +------BEGIN CERTIFICATE----- +-MIIETzCCAzegAwIBAgIDAjpvMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +-MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +-YWwgQ0EwHhcNMTMxMTA1MjEzNjUwWhcNMjIwNTIwMjEzNjUwWjBEMQswCQYDVQQG +-EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +-U1NMIENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDjvn4K +-hqPPa209K6GXrUkkTdd3uTR5CKWeop7eRxKSPX7qGYax6E89X/fQp3eaWx8KA7UZ +-U9ulIZRpY51qTJEMEEe+EfpshiW3qwRoQjgJZfAU2hme+msLq2LvjafvY3AjqK+B +-89FuiGdT7BKkKXWKp/JXPaKDmJfyCn3U50NuMHhiIllZuHEnRaoPZsZVP/oyFysx +-j0ag+mkUfJ2fWuLrM04QprPtd2PYw5703d95mnrU7t7dmszDt6ldzBE6B7tvl6QB +-I0eVH6N3+liSxsfQvc+TGEK3fveeZerVO8rtrMVwof7UEJrwEgRErBpbeFBFV0xv +-vYDLgVwts7x2oR5lAgMBAAGjggFKMIIBRjAfBgNVHSMEGDAWgBTAephojYn7qwVk +-DBF9qn1luMrMTjAdBgNVHQ4EFgQU0m/3lvSFP3I8MH0j2oV4m6N8WnwwEgYDVR0T +-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNgYDVR0fBC8wLTAroCmgJ4Yl +-aHR0cDovL2cxLnN5bWNiLmNvbS9jcmxzL2d0Z2xvYmFsLmNybDAvBggrBgEFBQcB +-AQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9nMi5zeW1jYi5jb20wTAYDVR0gBEUw +-QzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1 +-c3QuY29tL3Jlc291cmNlcy9jcHMwKQYDVR0RBCIwIKQeMBwxGjAYBgNVBAMTEVN5 +-bWFudGVjUEtJLTEtNTM5MA0GCSqGSIb3DQEBCwUAA4IBAQCg1Pcs+3QLf2TxzUNq +-n2JTHAJ8mJCi7k9o1CAacxI+d7NQ63K87oi+fxfqd4+DYZVPhKHLMk9sIb7SaZZ9 +-Y73cK6gf0BOEcP72NZWJ+aZ3sEbIu7cT9clgadZM/tKO79NgwYCA4ef7i28heUrg +-3Kkbwbf7w0lZXLV3B0TUl/xJAIlvBk4BcBmsLxHA4uYPL4ZLjXvDuacu9PGsFj45 +-SVGeF0tPEDpbpaiSb/361gsDTUdWVxnzy2v189bPsPX1oxHSIFMTNDcFLENaY9+N +-QNaFHlHpURceA1bJ8TCt55sRornQMYGbaLHZ6PPmlH7HrhMvh+3QJbBo+d4IWvMp +-zNSS +------END CERTIFICATE----- +-- +2.22.0 + diff --git a/8290705_fix_StringConcat_validate_mem_flow_asserts_with_unexpected_userStoreI.patch b/8290705_fix_StringConcat_validate_mem_flow_asserts_with_unexpected_userStoreI.patch new file mode 100644 index 0000000000000000000000000000000000000000..ae487e7ae7f18fe43d60b64919ba7516ba8ba78f --- /dev/null +++ b/8290705_fix_StringConcat_validate_mem_flow_asserts_with_unexpected_userStoreI.patch @@ -0,0 +1,145 @@ +diff --git a/hotspot/src/share/vm/opto/stringopts.cpp b/hotspot/src/share/vm/opto/stringopts.cpp +index d92a3d7a3..2d11b2257 100644 +--- a/hotspot/src/share/vm/opto/stringopts.cpp ++++ b/hotspot/src/share/vm/opto/stringopts.cpp +@@ -968,6 +968,21 @@ bool StringConcat::validate_control_flow() { + fail = true; + break; + } else if (ptr->is_Proj() && ptr->in(0)->is_Initialize()) { ++ // Check for side effect between Initialize and the constructor ++ for (SimpleDUIterator iter(ptr); iter.has_next(); iter.next()) { ++ Node* use = iter.get(); ++ if (!use->is_CFG() && !use->is_CheckCastPP() && !use->is_Load()) { ++#ifndef PRODUCT ++ if (PrintOptimizeStringConcat) { ++ tty->print_cr("unexpected control use of Initialize"); ++ ptr->in(0)->dump(); // Initialize node ++ use->dump(1); ++ } ++#endif ++ fail = true; ++ break; ++ } ++ } + ptr = ptr->in(0)->in(0); + } else if (ptr->is_Region()) { + Node* copy = ptr->as_Region()->is_copy(); +diff --git a/hotspot/test/compiler/stringopts/SideEffectBeforeConstructor.jasm b/hotspot/test/compiler/stringopts/SideEffectBeforeConstructor.jasm +new file mode 100644 +index 000000000..cbc6d754b +--- /dev/null ++++ b/hotspot/test/compiler/stringopts/SideEffectBeforeConstructor.jasm +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++super public class compiler/stringopts/SideEffectBeforeConstructor ++ version 51:0 ++{ ++ public static Field result:I; ++ ++ static Method "":"()V" ++ stack 2 locals 0 ++ { ++ iconst_0; ++ putstatic Field result:"I"; ++ return; ++ } ++ public Method "":"()V" ++ stack 1 locals 1 ++ { ++ aload_0; ++ invokespecial Method java/lang/Object."":"()V"; ++ return; ++ } ++ ++ public static Method test:"(Ljava/lang/String;)V" ++ stack 4 locals 1 ++ { ++ new class java/lang/StringBuffer; ++ dup; ++ getstatic Field result:"I"; ++ iconst_1; ++ iadd; ++ putstatic Field result:"I"; ++ aload_0; ++ invokespecial Method java/lang/StringBuffer."":"(Ljava/lang/String;)V"; ++ invokevirtual Method java/lang/StringBuffer.toString:"()Ljava/lang/String;"; ++ return; ++ } ++} +diff --git a/hotspot/test/compiler/stringopts/TestSideEffectBeforeConstructor.java b/hotspot/test/compiler/stringopts/TestSideEffectBeforeConstructor.java +new file mode 100644 +index 000000000..86c5eca1d +--- /dev/null ++++ b/hotspot/test/compiler/stringopts/TestSideEffectBeforeConstructor.java +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++/* ++ * @test ++ * @bug 8290705 ++ * @summary Test correctness of the string concatenation optimization with ++ * a store between StringBuffer allocation and constructor invocation. ++ * @compile SideEffectBeforeConstructor.jasm ++ * @run main/othervm -Xbatch compiler.stringopts.TestSideEffectBeforeConstructor ++ */ ++ ++package compiler.stringopts; ++ ++public class TestSideEffectBeforeConstructor { ++ ++ public static void main(String[] args) { ++ for (int i = 0; i < 100_000; ++i) { ++ try { ++ SideEffectBeforeConstructor.test(null); ++ } catch (NullPointerException npe) { ++ // Expected ++ } ++ } ++ if (SideEffectBeforeConstructor.result != 100_000) { ++ throw new RuntimeException("Unexpected result: " + SideEffectBeforeConstructor.result); ++ } ++ } ++} diff --git a/Dynamic-CDS-Archive.patch b/Dynamic-CDS-Archive.patch new file mode 100644 index 0000000000000000000000000000000000000000..edccdea2d34992af8b341928e6630b677a2897e3 --- /dev/null +++ b/Dynamic-CDS-Archive.patch @@ -0,0 +1,8657 @@ +From f1cba2dd8fe526f4ad5ea4913154a174bd19a080 Mon Sep 17 00:00:00 2001 +Date: Sat, 3 Sep 2022 14:25:11 +0000 +Subject: Dynamic-CDS-Archive + +--- + hotspot/src/os/linux/vm/os_linux.cpp | 3 +- + hotspot/src/share/vm/cds/archiveBuilder.cpp | 807 ++++++++++++++++ + hotspot/src/share/vm/cds/archiveBuilder.hpp | 368 +++++++ + hotspot/src/share/vm/cds/archiveUtils.cpp | 247 +++++ + hotspot/src/share/vm/cds/archiveUtils.hpp | 141 +++ + hotspot/src/share/vm/cds/dumpAllocStats.cpp | 109 +++ + hotspot/src/share/vm/cds/dumpAllocStats.hpp | 88 ++ + hotspot/src/share/vm/cds/dynamicArchive.cpp | 412 ++++++++ + hotspot/src/share/vm/cds/dynamicArchive.hpp | 54 ++ + .../share/vm/classfile/classFileParser.cpp | 7 + + .../src/share/vm/classfile/classLoaderExt.hpp | 2 +- + .../share/vm/classfile/compactHashtable.cpp | 216 +++++ + .../share/vm/classfile/compactHashtable.hpp | 349 +++++++ + .../share/vm/classfile/sharedClassUtil.hpp | 4 + + .../src/share/vm/classfile/symbolTable.cpp | 102 +- + .../src/share/vm/classfile/symbolTable.hpp | 12 + + .../share/vm/classfile/systemDictionary.cpp | 159 +-- + .../share/vm/classfile/systemDictionary.hpp | 1 + + .../vm/classfile/systemDictionaryShared.cpp | 911 ++++++++++++++++++ + .../vm/classfile/systemDictionaryShared.hpp | 167 +++- + hotspot/src/share/vm/memory/allocation.hpp | 12 + + .../src/share/vm/memory/allocation.inline.hpp | 53 +- + hotspot/src/share/vm/memory/filemap.cpp | 352 +++++-- + hotspot/src/share/vm/memory/filemap.hpp | 104 +- + hotspot/src/share/vm/memory/iterator.hpp | 7 + + hotspot/src/share/vm/memory/metaspace.cpp | 80 +- + hotspot/src/share/vm/memory/metaspace.hpp | 1 + + .../src/share/vm/memory/metaspaceClosure.cpp | 87 ++ + .../src/share/vm/memory/metaspaceClosure.hpp | 381 ++++++++ + .../src/share/vm/memory/metaspaceShared.cpp | 148 ++- + .../src/share/vm/memory/metaspaceShared.hpp | 51 +- + hotspot/src/share/vm/oops/annotations.cpp | 12 + + hotspot/src/share/vm/oops/annotations.hpp | 9 + + hotspot/src/share/vm/oops/arrayKlass.cpp | 22 + + hotspot/src/share/vm/oops/arrayKlass.hpp | 3 +- + hotspot/src/share/vm/oops/constMethod.cpp | 26 + + hotspot/src/share/vm/oops/constMethod.hpp | 8 +- + hotspot/src/share/vm/oops/constantPool.cpp | 93 +- + hotspot/src/share/vm/oops/constantPool.hpp | 12 + + hotspot/src/share/vm/oops/cpCache.cpp | 69 ++ + hotspot/src/share/vm/oops/cpCache.hpp | 25 +- + hotspot/src/share/vm/oops/instanceKlass.cpp | 131 ++- + hotspot/src/share/vm/oops/instanceKlass.hpp | 12 +- + hotspot/src/share/vm/oops/klass.cpp | 83 +- + hotspot/src/share/vm/oops/klass.hpp | 10 +- + hotspot/src/share/vm/oops/klassVtable.hpp | 3 + + hotspot/src/share/vm/oops/metadata.hpp | 4 +- + hotspot/src/share/vm/oops/method.cpp | 22 +- + hotspot/src/share/vm/oops/method.hpp | 7 +- + hotspot/src/share/vm/oops/methodCounters.hpp | 7 + + hotspot/src/share/vm/oops/methodData.cpp | 9 + + hotspot/src/share/vm/oops/methodData.hpp | 5 +- + hotspot/src/share/vm/oops/objArrayKlass.cpp | 7 + + hotspot/src/share/vm/oops/objArrayKlass.hpp | 3 +- + hotspot/src/share/vm/oops/symbol.hpp | 22 +- + hotspot/src/share/vm/runtime/arguments.cpp | 142 +++ + hotspot/src/share/vm/runtime/arguments.hpp | 19 +- + hotspot/src/share/vm/runtime/globals.hpp | 21 + + hotspot/src/share/vm/runtime/java.cpp | 8 + + hotspot/src/share/vm/runtime/mutexLocker.cpp | 5 +- + hotspot/src/share/vm/runtime/mutexLocker.hpp | 3 + + hotspot/src/share/vm/runtime/os.cpp | 9 +- + hotspot/src/share/vm/runtime/os.hpp | 2 + + hotspot/src/share/vm/runtime/thread.cpp | 10 + + .../share/vm/services/diagnosticCommand.cpp | 13 + + .../share/vm/services/diagnosticCommand.hpp | 23 + + hotspot/src/share/vm/utilities/array.hpp | 1 + + hotspot/src/share/vm/utilities/bitMap.cpp | 17 +- + hotspot/src/share/vm/utilities/bitMap.hpp | 1 + + .../src/share/vm/utilities/constantTag.hpp | 5 +- + .../share/vm/utilities/globalDefinitions.hpp | 11 +- + hotspot/src/share/vm/utilities/hashtable.cpp | 60 +- + hotspot/src/share/vm/utilities/hashtable.hpp | 98 +- + .../share/vm/utilities/hashtable.inline.hpp | 2 +- + hotspot/src/share/vm/utilities/ostream.cpp | 11 + + hotspot/src/share/vm/utilities/ostream.hpp | 2 +- + .../src/share/vm/utilities/resourceHash.hpp | 27 +- + 77 files changed, 6234 insertions(+), 295 deletions(-) + create mode 100644 hotspot/src/share/vm/cds/archiveBuilder.cpp + create mode 100644 hotspot/src/share/vm/cds/archiveBuilder.hpp + create mode 100644 hotspot/src/share/vm/cds/archiveUtils.cpp + create mode 100644 hotspot/src/share/vm/cds/archiveUtils.hpp + create mode 100644 hotspot/src/share/vm/cds/dumpAllocStats.cpp + create mode 100644 hotspot/src/share/vm/cds/dumpAllocStats.hpp + create mode 100644 hotspot/src/share/vm/cds/dynamicArchive.cpp + create mode 100644 hotspot/src/share/vm/cds/dynamicArchive.hpp + create mode 100644 hotspot/src/share/vm/classfile/compactHashtable.cpp + create mode 100644 hotspot/src/share/vm/classfile/compactHashtable.hpp + create mode 100644 hotspot/src/share/vm/classfile/systemDictionaryShared.cpp + create mode 100644 hotspot/src/share/vm/memory/metaspaceClosure.cpp + create mode 100644 hotspot/src/share/vm/memory/metaspaceClosure.hpp + +diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp +index f700335a3..6dbedf5c2 100644 +--- a/hotspot/src/os/linux/vm/os_linux.cpp ++++ b/hotspot/src/os/linux/vm/os_linux.cpp +@@ -2370,8 +2370,7 @@ void os::print_siginfo(outputStream* st, void* siginfo) { + #if INCLUDE_CDS + if (si && (si->si_signo == SIGBUS || si->si_signo == SIGSEGV) && + UseSharedSpaces) { +- FileMapInfo* mapinfo = FileMapInfo::current_info(); +- if (mapinfo->is_in_shared_space(si->si_addr)) { ++ if (MetaspaceShared::is_in_shared_space(si->si_addr)) { + st->print("\n\nError accessing class data sharing archive." \ + " Mapped file inaccessible during execution, " \ + " possible disk/network problem."); +diff --git a/hotspot/src/share/vm/cds/archiveBuilder.cpp b/hotspot/src/share/vm/cds/archiveBuilder.cpp +new file mode 100644 +index 000000000..144dedfa9 +--- /dev/null ++++ b/hotspot/src/share/vm/cds/archiveBuilder.cpp +@@ -0,0 +1,807 @@ ++/* ++ * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "cds/archiveBuilder.hpp" ++#include "cds/archiveUtils.hpp" ++#include "classfile/symbolTable.hpp" ++#include "classfile/systemDictionaryShared.hpp" ++#include "interpreter/abstractInterpreter.hpp" ++#include "memory/filemap.hpp" ++#include "memory/memRegion.hpp" ++#include "memory/metaspaceShared.hpp" ++#include "memory/resourceArea.hpp" ++#include "oops/instanceKlass.hpp" ++#include "oops/objArrayKlass.hpp" ++#include "runtime/arguments.hpp" ++#include "runtime/globals_extension.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "runtime/thread.hpp" ++#include "utilities/align.hpp" ++#include "utilities/bitMap.inline.hpp" ++#include "utilities/hashtable.inline.hpp" ++ ++ArchiveBuilder* ArchiveBuilder::_current = NULL; ++ ++ArchiveBuilder::OtherROAllocMark::~OtherROAllocMark() { ++ char* newtop = ArchiveBuilder::current()->_ro_region.top(); ++ ArchiveBuilder::alloc_stats()->record_other_type(int(newtop - _oldtop), true); ++} ++ ++ArchiveBuilder::SourceObjList::SourceObjList() : _ptrmap(16 * K, false) { ++ _total_bytes = 0; ++ _objs = new (ResourceObj::C_HEAP, mtClassShared) GrowableArray(128 * K, mtClassShared); ++} ++ ++ArchiveBuilder::SourceObjList::~SourceObjList() { ++ delete _objs; ++} ++ ++void ArchiveBuilder::SourceObjList::append(MetaspaceClosure::Ref* enclosing_ref, SourceObjInfo* src_info) { ++ // Save this source object for copying ++ _objs->append(src_info); ++ ++ // Prepare for marking the pointers in this source object ++ assert(is_aligned(_total_bytes, sizeof(address)), "must be"); ++ src_info->set_ptrmap_start(_total_bytes / sizeof(address)); ++ _total_bytes = align_up(_total_bytes + (uintx)src_info->size_in_bytes(), sizeof(address)); ++ src_info->set_ptrmap_end(_total_bytes / sizeof(address)); ++ ++ BitMap::idx_t bitmap_size_needed = BitMap::idx_t(src_info->ptrmap_end()); ++ if (_ptrmap.size() <= bitmap_size_needed) { ++ _ptrmap.resize((bitmap_size_needed + 1) * 2, false); ++ } ++} ++ ++class PrintBitMap : public BitMapClosure { ++ public: ++ bool do_bit(BitMap::idx_t bit_offset) { ++ tty->print_cr("PrintBitMap : " SIZE_FORMAT, bit_offset); ++ return true; ++ } ++}; ++ ++void ArchiveBuilder::SourceObjList::remember_embedded_pointer(SourceObjInfo* src_info, MetaspaceClosure::Ref* ref) { ++ // src_obj contains a pointer. Remember the location of this pointer in _ptrmap, ++ // so that we can copy/relocate it later. E.g., if we have ++ // class Foo { intx scala; Bar* ptr; } ++ // Foo *f = 0x100; ++ // To mark the f->ptr pointer on 64-bit platform, this function is called with ++ // src_info()->obj() == 0x100 ++ // ref->addr() == 0x108 ++ address src_obj = src_info->obj(); ++ address* field_addr = ref->addr(); ++ assert(src_info->ptrmap_start() < _total_bytes, "sanity"); ++ assert(src_info->ptrmap_end() <= _total_bytes, "sanity"); ++ assert(*field_addr != NULL, "should have checked"); ++ ++ intx field_offset_in_bytes = ((address)field_addr) - src_obj; ++ DEBUG_ONLY(int src_obj_size = src_info->size_in_bytes();) ++ assert(field_offset_in_bytes >= 0, "must be"); ++ assert(field_offset_in_bytes + intx(sizeof(intptr_t)) <= intx(src_obj_size), "must be"); ++ assert(is_aligned(field_offset_in_bytes, sizeof(address)), "must be"); ++ ++ BitMap::idx_t idx = BitMap::idx_t(src_info->ptrmap_start() + (uintx)(field_offset_in_bytes / sizeof(address))); ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("remember_embedded_pointer: _ptrmap_start: " SIZE_FORMAT ++ "_ptrmap_end: " SIZE_FORMAT ++ " field: " PTR_FORMAT" -> " PTR_FORMAT ++ " bit_index: " SIZE_FORMAT " ", ++ src_info->ptrmap_start(), src_info->ptrmap_end(), p2i(src_obj), p2i(field_addr), idx); ++ } ++ _ptrmap.set_bit(BitMap::idx_t(idx)); ++} ++ ++class RelocateEmbeddedPointers : public BitMapClosure { ++ ArchiveBuilder* _builder; ++ address _dumped_obj; ++ BitMap::idx_t _start_idx; ++public: ++ RelocateEmbeddedPointers(ArchiveBuilder* builder, address dumped_obj, BitMap::idx_t start_idx) : ++ _builder(builder), _dumped_obj(dumped_obj), _start_idx(start_idx) {} ++ ++ bool do_bit(BitMap::idx_t bit_offset) { ++ uintx FLAG_MASK = 0x03; // See comments around MetaspaceClosure::FLAG_MASK ++ size_t field_offset = size_t(bit_offset - _start_idx) * sizeof(address); ++ address* ptr_loc = (address*)(_dumped_obj + field_offset); ++ uintx old_p_and_bits = (uintx)(*ptr_loc); ++ uintx flag_bits = (old_p_and_bits & FLAG_MASK); ++ address old_p = (address)(old_p_and_bits & (~FLAG_MASK)); ++ address new_p = _builder->get_dumped_addr(old_p); ++ uintx new_p_and_bits = ((uintx)new_p) | flag_bits; ++ ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Ref: [" PTR_FORMAT "] -> " PTR_FORMAT " => " PTR_FORMAT, ++ p2i(ptr_loc), p2i(old_p), p2i(new_p)); ++ } ++ ArchivePtrMarker::set_and_mark_pointer(ptr_loc, (address)(new_p_and_bits)); ++ return true; // keep iterating the bitmap ++ } ++}; ++ ++void ArchiveBuilder::SourceObjList::relocate(int i, ArchiveBuilder* builder) { ++ SourceObjInfo* src_info = objs()->at(i); ++ assert(src_info->should_copy(), "must be"); ++ BitMap::idx_t start = BitMap::idx_t(src_info->ptrmap_start()); // inclusive ++ BitMap::idx_t end = BitMap::idx_t(src_info->ptrmap_end()); // exclusive ++ ++ RelocateEmbeddedPointers relocator(builder, src_info->dumped_addr(), start); ++ _ptrmap.iterate(&relocator, start, end); ++} ++ ++ArchiveBuilder::ArchiveBuilder() : ++ _current_dump_space(NULL), ++ _buffer_bottom(NULL), ++ _last_verified_top(NULL), ++ _num_dump_regions_used(0), ++ _other_region_used_bytes(0), ++ _requested_static_archive_bottom(NULL), ++ _requested_static_archive_top(NULL), ++ _requested_dynamic_archive_bottom(NULL), ++ _requested_dynamic_archive_top(NULL), ++ _mapped_static_archive_bottom(NULL), ++ _mapped_static_archive_top(NULL), ++ _buffer_to_requested_delta(0), ++ _rw_region("rw", MAX_SHARED_DELTA), ++ _ro_region("ro", MAX_SHARED_DELTA), ++ _rw_src_objs(), ++ _ro_src_objs(), ++ _src_obj_table(INITIAL_TABLE_SIZE), ++ _num_instance_klasses(0), ++ _num_obj_array_klasses(0), ++ _num_type_array_klasses(0), ++ _estimated_metaspaceobj_bytes(0), ++ _estimated_hashtable_bytes(0) { ++ _klasses = new (ResourceObj::C_HEAP, mtClassShared) GrowableArray(4 * K, mtClassShared); ++ _symbols = new (ResourceObj::C_HEAP, mtClassShared) GrowableArray(256 * K, mtClassShared); ++ ++ assert(_current == NULL, "must be"); ++ _current = this; ++} ++ ++ArchiveBuilder::~ArchiveBuilder() { ++ assert(_current == this, "must be"); ++ _current = NULL; ++ ++ clean_up_src_obj_table(); ++ ++ for (int i = 0; i < _symbols->length(); i++) { ++ _symbols->at(i)->decrement_refcount(); ++ } ++ ++ delete _klasses; ++ delete _symbols; ++ if (_shared_rs.is_reserved()) { ++ _shared_rs.release(); ++ } ++} ++ ++bool ArchiveBuilder::gather_one_source_obj(MetaspaceClosure::Ref* enclosing_ref, ++ MetaspaceClosure::Ref* ref, bool read_only) { ++ address src_obj = ref->obj(); ++ if (src_obj == NULL) { ++ return false; ++ } ++ ref->set_keep_after_pushing(); ++ remember_embedded_pointer_in_copied_obj(enclosing_ref, ref); ++ ++ FollowMode follow_mode = get_follow_mode(ref); ++ SourceObjInfo src_info(ref, read_only, follow_mode); ++ bool created; ++ SourceObjInfo* p = _src_obj_table.add_if_absent(src_obj, src_info, &created); ++ if (created) { ++ if (_src_obj_table.maybe_grow(MAX_TABLE_SIZE)) { ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Expanded _src_obj_table table to %d", _src_obj_table.table_size()); ++ } ++ } ++ } ++ ++ assert(p->read_only() == src_info.read_only(), "must be"); ++ ++ if (created && src_info.should_copy()) { ++ ref->set_user_data((void*)p); ++ if (read_only) { ++ _ro_src_objs.append(enclosing_ref, p); ++ } else { ++ _rw_src_objs.append(enclosing_ref, p); ++ } ++ return true; // Need to recurse into this ref only if we are copying it ++ } else { ++ return false; ++ } ++} ++ ++void ArchiveBuilder::iterate_sorted_roots(MetaspaceClosure* it, bool is_relocating_pointers) { ++ int i; ++ ++ if (!is_relocating_pointers) { ++ // Don't relocate _symbol, so we can safely call decrement_refcount on the ++ // original symbols. ++ int num_symbols = _symbols->length(); ++ for (i = 0; i < num_symbols; i++) { ++ it->push(_symbols->adr_at(i)); ++ } ++ } ++ ++ int num_klasses = _klasses->length(); ++ for (i = 0; i < num_klasses; i++) { ++ it->push(_klasses->adr_at(i)); ++ } ++ ++ iterate_roots(it, is_relocating_pointers); ++} ++ ++class GatherSortedSourceObjs : public MetaspaceClosure { ++ ArchiveBuilder* _builder; ++ ++public: ++ GatherSortedSourceObjs(ArchiveBuilder* builder) : _builder(builder) {} ++ ++ virtual bool do_ref(Ref* ref, bool read_only) { ++ return _builder->gather_one_source_obj(enclosing_ref(), ref, read_only); ++ } ++ ++ virtual void do_pending_ref(Ref* ref) { ++ if (ref->obj() != NULL) { ++ _builder->remember_embedded_pointer_in_copied_obj(enclosing_ref(), ref); ++ } ++ } ++}; ++ ++void ArchiveBuilder::gather_source_objs() { ++ ResourceMark rm; ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Gathering all archivable objects ... "); ++ } ++ gather_klasses_and_symbols(); ++ GatherSortedSourceObjs doit(this); ++ iterate_sorted_roots(&doit, /*is_relocating_pointers=*/false); ++ doit.finish(); ++} ++ ++bool ArchiveBuilder::is_excluded(Klass* klass) { ++ if (klass->oop_is_instance()) { ++ InstanceKlass* ik = InstanceKlass::cast(klass); ++ return SystemDictionaryShared::is_excluded_class(ik); ++ } else if (klass->oop_is_objArray()) { ++ if (DynamicDumpSharedSpaces) { ++ // Don't support archiving of array klasses for now (WHY???) ++ return true; ++ } ++ Klass* bottom = ObjArrayKlass::cast(klass)->bottom_klass(); ++ if (bottom->oop_is_instance()) { ++ return SystemDictionaryShared::is_excluded_class(InstanceKlass::cast(bottom)); ++ } ++ } ++ ++ return false; ++} ++ ++ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref *ref) { ++ address obj = ref->obj(); ++ if (MetaspaceShared::is_in_shared_space(obj)) { ++ // Don't dump existing shared metadata again. ++ return point_to_it; ++ } else if (ref->msotype() == MetaspaceObj::MethodDataType) { ++ return set_to_null; ++ } else { ++ if (ref->msotype() == MetaspaceObj::ClassType) { ++ Klass* klass = (Klass*)ref->obj(); ++ assert(klass->is_klass(), "must be"); ++ if (is_excluded(klass)) { ++ if (TraceDynamicCDS) { ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("Skipping class (excluded): %s", klass->external_name()); ++ } ++ return set_to_null; ++ } ++ } ++ ++ return make_a_copy; ++ } ++} ++ ++int ArchiveBuilder::compare_symbols_by_address(Symbol** a, Symbol** b) { ++ if (a[0] < b[0]) { ++ return -1; ++ } else { ++ assert(a[0] > b[0], "Duplicated symbol unexpected"); ++ return 1; ++ } ++} ++ ++int ArchiveBuilder::compare_klass_by_name(Klass** a, Klass** b) { ++ return a[0]->name()->fast_compare(b[0]->name()); ++} ++ ++void ArchiveBuilder::sort_klasses() { ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Sorting classes ... "); ++ } ++ _klasses->sort(compare_klass_by_name); ++} ++ ++class GatherKlassesAndSymbols : public UniqueMetaspaceClosure { ++ ArchiveBuilder* _builder; ++ ++public: ++ GatherKlassesAndSymbols(ArchiveBuilder* builder) : _builder(builder) { } ++ ++ virtual bool do_unique_ref(Ref* ref, bool read_only) { ++ return _builder->gather_klass_and_symbol(ref, read_only); ++ } ++}; ++ ++void ArchiveBuilder::gather_klasses_and_symbols() { ++ ResourceMark rm; ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Gathering classes and symbols ... "); ++ } ++ GatherKlassesAndSymbols doit(this); ++ iterate_roots(&doit, false); ++ doit.finish(); ++ ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Number of classes %d", _num_instance_klasses + _num_obj_array_klasses + _num_type_array_klasses); ++ dynamic_cds_log->print_cr(" instance classes = %5d", _num_instance_klasses); ++ dynamic_cds_log->print_cr(" obj array classes = %5d", _num_obj_array_klasses); ++ dynamic_cds_log->print_cr(" type array classes = %5d", _num_type_array_klasses); ++ dynamic_cds_log->print_cr(" symbols = %5d", _symbols->length()); ++ } ++} ++ ++bool ArchiveBuilder::gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool read_only) { ++ if (ref->obj() == NULL) { ++ return false; ++ } ++ if (get_follow_mode(ref) != make_a_copy) { ++ return false; ++ } ++ if (ref->msotype() == MetaspaceObj::ClassType) { ++ Klass* klass = (Klass*)ref->obj(); ++ assert(klass->is_klass(), "must be"); ++ if (!is_excluded(klass)) { ++ _klasses->append(klass); ++ if (klass->oop_is_instance()) { ++ _num_instance_klasses ++; ++ } else if (klass->oop_is_objArray()) { ++ _num_obj_array_klasses ++; ++ } else { ++ assert(klass->oop_is_typeArray(), "sanity"); ++ _num_type_array_klasses ++; ++ } ++ } ++ // See RunTimeSharedClassInfo::get_for() ++ _estimated_metaspaceobj_bytes += align_up(BytesPerWord, KlassAlignmentInBytes); ++ } else if (ref->msotype() == MetaspaceObj::SymbolType) { ++ // Make sure the symbol won't be GC'ed while we are dumping the archive. ++ Symbol* sym = (Symbol*)ref->obj(); ++ sym->increment_refcount(); ++ _symbols->append(sym); ++ } ++ ++ int bytes = ref->size() * BytesPerWord; ++ _estimated_metaspaceobj_bytes += align_up(bytes, KlassAlignmentInBytes); ++ return true; // recurse ++} ++ ++size_t ArchiveBuilder::estimate_archive_size() { ++ // size of the symbol table and two dictionaries, plus the RunTimeSharedClassInfo's ++ size_t symbol_table_est = SymbolTable::estimate_size_for_archive(); ++ size_t dictionary_est = SystemDictionaryShared::estimate_size_for_archive(); ++ _estimated_hashtable_bytes = symbol_table_est + dictionary_est; ++ ++ size_t total = 0; ++ ++ total += _estimated_metaspaceobj_bytes; ++ total += _estimated_hashtable_bytes; ++ ++ // allow fragmentation at the end of each dump region ++ total += _total_dump_regions * ((size_t)os::vm_allocation_granularity()); ++ ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("_estimated_hashtable_bytes = " SIZE_FORMAT " + " SIZE_FORMAT " = " SIZE_FORMAT, ++ symbol_table_est, dictionary_est, _estimated_hashtable_bytes); ++ dynamic_cds_log->print_cr("_estimated_metaspaceobj_bytes = " SIZE_FORMAT, _estimated_metaspaceobj_bytes); ++ dynamic_cds_log->print_cr("total estimate bytes = " SIZE_FORMAT, total); ++ } ++ ++ return align_up(total, (size_t)os::vm_allocation_granularity()); ++} ++ ++address ArchiveBuilder::reserve_buffer() { ++ size_t buffer_size = estimate_archive_size(); ++ ReservedSpace rs(buffer_size, os::vm_allocation_granularity(), false); ++ if (!rs.is_reserved()) { ++ tty->print_cr("Failed to reserve " SIZE_FORMAT " bytes of output buffer.", buffer_size); ++ vm_direct_exit(0); ++ } ++ ++ // buffer_bottom is the lowest address of the 2 core regions (rw, ro) when ++ // we are copying the class metadata into the buffer. ++ address buffer_bottom = (address)rs.base(); ++ _shared_rs = rs; ++ ++ _buffer_bottom = buffer_bottom; ++ _last_verified_top = buffer_bottom; ++ _current_dump_space = &_rw_region; ++ _num_dump_regions_used = 1; ++ _other_region_used_bytes = 0; ++ _current_dump_space->init(&_shared_rs, &_shared_vs); ++ ++ ArchivePtrMarker::initialize(&_ptrmap, &_shared_vs); ++ ++ // The bottom of the static archive should be mapped at this address by default. ++ _requested_static_archive_bottom = (address)MetaspaceShared::requested_base_address(); ++ ++ size_t static_archive_size = FileMapInfo::shared_spaces_size(); ++ _requested_static_archive_top = _requested_static_archive_bottom + static_archive_size; ++ ++ _mapped_static_archive_bottom = (address)MetaspaceShared::shared_metaspace_static_bottom(); ++ _mapped_static_archive_top = _mapped_static_archive_bottom + static_archive_size; ++ ++ _requested_dynamic_archive_bottom = align_up(_requested_static_archive_top, (size_t)os::vm_allocation_granularity()); ++ ++ _buffer_to_requested_delta = _requested_dynamic_archive_bottom - _buffer_bottom; ++ ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Reserved output buffer space at " PTR_FORMAT " [" SIZE_FORMAT " bytes]", ++ p2i(buffer_bottom), buffer_size); ++ dynamic_cds_log->print_cr("Dynamic archive mapped space at " PTR_FORMAT, p2i(_requested_dynamic_archive_bottom)); ++ } ++ ++ return buffer_bottom; ++} ++ ++void ArchiveBuilder::verify_estimate_size(size_t estimate, const char* which) { ++ address bottom = _last_verified_top; ++ address top = (address)(current_dump_space()->top()); ++ size_t used = size_t(top - bottom) + _other_region_used_bytes; ++ int diff = int(estimate) - int(used); ++ ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("%s estimate = " SIZE_FORMAT " used = " SIZE_FORMAT "; diff = %d bytes", which, estimate, used, diff); ++ } ++ assert(diff >= 0, "Estimate is too small"); ++ ++ _last_verified_top = top; ++ _other_region_used_bytes = 0; ++} ++ ++void ArchiveBuilder::dump_rw_metadata() { ++ ResourceMark rm; ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Allocating RW objects ... "); ++ } ++ make_shallow_copies(&_rw_region, &_rw_src_objs); ++} ++ ++void ArchiveBuilder::dump_ro_metadata() { ++ ResourceMark rm; ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Allocating RO objects ... "); ++ } ++ start_dump_space(&_ro_region); ++ make_shallow_copies(&_ro_region, &_ro_src_objs); ++} ++ ++void ArchiveBuilder::start_dump_space(DumpRegion* next) { ++ address bottom = _last_verified_top; ++ address top = (address)(_current_dump_space->top()); ++ _other_region_used_bytes += size_t(top - bottom); ++ _current_dump_space->pack(next); ++ _current_dump_space = next; ++ _num_dump_regions_used ++; ++ _last_verified_top = (address)(_current_dump_space->top()); ++} ++ ++void ArchiveBuilder::patch_shared_obj_vtable() { ++ SourceObjList* objs = &_rw_src_objs; ++ ++ for (int i = 0; i < objs->objs()->length(); i++) { ++ SourceObjInfo* src_info = objs->objs()->at(i); ++ address dest = src_info->dumped_addr(); ++ MetaspaceClosure::Ref* ref = src_info->ref(); ++ intptr_t* archived_vtable = MetaspaceShared::get_archived_vtable(ref->msotype(), dest); ++ if (archived_vtable != NULL) { ++ // When we copy archived vtable from base archive into dynamic archive's objs, we can't call ++ // virtual function before restore dynamic archive. ++ *(intptr_t**)dest = archived_vtable; ++ ArchivePtrMarker::mark_pointer((address*)dest); ++ } ++ } ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("patch vtable done (%d objects)", objs->objs()->length()); ++ } ++} ++ ++void ArchiveBuilder::remember_embedded_pointer_in_copied_obj(MetaspaceClosure::Ref* enclosing_ref, ++ MetaspaceClosure::Ref* ref) { ++ assert(ref->obj() != NULL, "should have checked"); ++ ++ if (enclosing_ref != NULL) { ++ SourceObjInfo* src_info = (SourceObjInfo*)enclosing_ref->user_data(); ++ if (src_info == NULL) { ++ // source objects of point_to_it/set_to_null types are not copied ++ // so we don't need to remember their pointers. ++ } else { ++ if (src_info->read_only()) { ++ _ro_src_objs.remember_embedded_pointer(src_info, ref); ++ } else { ++ _rw_src_objs.remember_embedded_pointer(src_info, ref); ++ } ++ } ++ } ++} ++ ++void ArchiveBuilder::make_shallow_copies(DumpRegion *dump_region, ++ const ArchiveBuilder::SourceObjList* src_objs) { ++ for (int i = 0; i < src_objs->objs()->length(); i++) { ++ make_shallow_copy(dump_region, src_objs->objs()->at(i)); ++ } ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("done (%d objects)", src_objs->objs()->length()); ++ } ++} ++ ++void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* src_info) { ++ MetaspaceClosure::Ref* ref = src_info->ref(); ++ address src = ref->obj(); ++ int bytes = src_info->size_in_bytes(); ++ char* dest; ++ char* oldtop; ++ char* newtop; ++ ++ oldtop = dump_region->top(); ++ if (ref->msotype() == MetaspaceObj::ClassType) { ++ // Save a pointer immediate in front of an InstanceKlass, so ++ // we can do a quick lookup from InstanceKlass* -> RunTimeSharedClassInfo* ++ // without building another hashtable. See RunTimeSharedClassInfo::get_for() ++ // in systemDictionaryShared.cpp. ++ Klass* klass = (Klass*)src; ++ if (klass->oop_is_instance()) { ++ dump_region->allocate(sizeof(address)); ++ } ++ } ++ dest = dump_region->allocate(bytes); ++ newtop = dump_region->top(); ++ ++ memcpy(dest, src, bytes); ++ ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(src), p2i(dest), bytes); ++ } ++ src_info->set_dumped_addr((address)dest); ++ ++ _alloc_stats.record(ref->msotype(), int(newtop - oldtop), src_info->read_only()); ++} ++ ++address ArchiveBuilder::get_dumped_addr(address src_obj) { ++ SourceObjInfo* p = _src_obj_table.lookup(src_obj); ++ assert(p != NULL, "must be"); ++ ++ return p->dumped_addr(); ++} ++ ++void ArchiveBuilder::relocate_embedded_pointers(ArchiveBuilder::SourceObjList* src_objs) { ++ for (int i = 0; i < src_objs->objs()->length(); i++) { ++ src_objs->relocate(i, this); ++ } ++} ++ ++void ArchiveBuilder::print_stats() { ++ _alloc_stats.print_stats(int(_ro_region.used()), int(_rw_region.used())); ++} ++ ++void ArchiveBuilder::make_klasses_shareable() { ++ for (int i = 0; i < klasses()->length(); i++) { ++ Klass* k = klasses()->at(i); ++ k->remove_java_mirror(); ++ if (k->oop_is_objArray()) { ++ // InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info ++ // on their array classes. ++ } else if (k->oop_is_typeArray()) { ++ k->remove_unshareable_info(); ++ } else { ++ assert(k->oop_is_instance(), " must be"); ++ InstanceKlass* ik = InstanceKlass::cast(k); ++ // High version introduce fast bytecode, jdk8 no need do it. ++ // MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik); ++ ik->remove_unshareable_info(); // assign_class_loader_type is in Klass::remove_unshareable_info ++ ++ if (DebugDynamicCDS) { ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("klasses[%4d] = " PTR_FORMAT " => " PTR_FORMAT " %s", i, p2i(ik), p2i(to_requested(ik)), ik->external_name()); ++ } ++ } ++ } ++} ++ ++uintx ArchiveBuilder::buffer_to_offset(address p) const { ++ address requested_p = to_requested(p); ++ assert(requested_p >= _requested_static_archive_bottom, "must be"); ++ return requested_p - _requested_static_archive_bottom; ++} ++ ++uintx ArchiveBuilder::any_to_offset(address p) const { ++ if (is_in_mapped_static_archive(p)) { ++ assert(DynamicDumpSharedSpaces, "must be"); ++ return p - _mapped_static_archive_bottom; ++ } ++ return buffer_to_offset(p); ++} ++ ++// RelocateBufferToRequested --- Relocate all the pointers in rw/ro, ++// so that the archive can be mapped to the "requested" location without runtime relocation. ++// ++// - See ArchiveBuilder header for the definition of "buffer", "mapped" and "requested" ++// - ArchivePtrMarker::ptrmap() marks all the pointers in the rw/ro regions ++// - Every pointer must have one of the following values: ++// [a] NULL: ++// No relocation is needed. Remove this pointer from ptrmap so we don't need to ++// consider it at runtime. ++// [b] Points into an object X which is inside the buffer: ++// Adjust this pointer by _buffer_to_requested_delta, so it points to X ++// when the archive is mapped at the requested location. ++// [c] Points into an object Y which is inside mapped static archive: ++// - This happens only during dynamic dump ++// - Adjust this pointer by _mapped_to_requested_static_archive_delta, ++// so it points to Y when the static archive is mapped at the requested location. ++class RelocateBufferToRequested : public BitMapClosure { ++ ArchiveBuilder* _builder; ++ address _buffer_bottom; ++ intx _buffer_to_requested_delta; ++ intx _mapped_to_requested_static_archive_delta; ++ size_t _max_non_null_offset; ++ ++ public: ++ RelocateBufferToRequested(ArchiveBuilder* builder) { ++ _builder = builder; ++ _buffer_bottom = _builder->buffer_bottom(); ++ _buffer_to_requested_delta = builder->buffer_to_requested_delta(); ++ _mapped_to_requested_static_archive_delta = builder->requested_static_archive_bottom() - builder->mapped_static_archive_bottom(); ++ _max_non_null_offset = 0; ++ ++ address bottom = _builder->buffer_bottom(); ++ address top = _builder->buffer_top(); ++ address new_bottom = bottom + _buffer_to_requested_delta; ++ address new_top = top + _buffer_to_requested_delta; ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Relocating archive from [" INTPTR_FORMAT " - " INTPTR_FORMAT "] to " ++ "[" INTPTR_FORMAT " - " INTPTR_FORMAT "]", ++ p2i(bottom), p2i(top), ++ p2i(new_bottom), p2i(new_top)); ++ } ++ } ++ ++ bool do_bit(size_t offset) { ++ address* p = (address*)_buffer_bottom + offset; ++ assert(_builder->is_in_buffer_space(p), "pointer must live in buffer space"); ++ ++ if (*p == NULL) { ++ // todo -- clear bit, etc ++ ArchivePtrMarker::ptrmap()->clear_bit(offset); ++ } else { ++ if (_builder->is_in_buffer_space(*p)) { ++ *p += _buffer_to_requested_delta; ++ // assert is in requested dynamic archive ++ } else { ++ assert(_builder->is_in_mapped_static_archive(*p), "old pointer must point inside buffer space or mapped static archive"); ++ *p += _mapped_to_requested_static_archive_delta; ++ assert(_builder->is_in_requested_static_archive(*p), "new pointer must point inside requested archive"); ++ } ++ ++ _max_non_null_offset = offset; ++ } ++ ++ return true; // keep iterating ++ } ++ ++ void doit() { ++ ArchivePtrMarker::ptrmap()->iterate(this); ++ ArchivePtrMarker::compact(_max_non_null_offset); ++ } ++}; ++ ++void ArchiveBuilder::relocate_to_requested() { ++ ro_region()->pack(); ++ ++ size_t my_archive_size = buffer_top() - buffer_bottom(); ++ ++ assert(DynamicDumpSharedSpaces, "must be"); ++ _requested_dynamic_archive_top = _requested_dynamic_archive_bottom + my_archive_size; ++ RelocateBufferToRequested patcher(this); ++ patcher.doit(); ++} ++ ++void ArchiveBuilder::clean_up_src_obj_table() { ++ SrcObjTableCleaner cleaner; ++ _src_obj_table.iterate(&cleaner); ++} ++ ++void ArchiveBuilder::write_archive(FileMapInfo* mapinfo) { ++ assert(mapinfo->header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC, "Dynamic CDS calls only"); ++ ++ mapinfo->write_dynamic_header(); ++ ++ write_region(mapinfo, MetaspaceShared::d_rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false); ++ write_region(mapinfo, MetaspaceShared::d_ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false); ++ ++ char* bitmap = mapinfo->write_bitmap_region(ArchivePtrMarker::ptrmap()); ++ ++ if (InfoDynamicCDS && mapinfo->is_open()) { ++ print_stats(); ++ } ++ ++ mapinfo->close(); ++ FREE_C_HEAP_ARRAY(char, bitmap, mtClassShared); ++} ++ ++void ArchiveBuilder::write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region, bool read_only, bool allow_exec) { ++ mapinfo->write_region(region_idx, dump_region->base(), dump_region->used(), dump_region->used(), read_only, allow_exec); ++} ++ ++class RefRelocator: public MetaspaceClosure { ++ ArchiveBuilder* _builder; ++ ++public: ++ RefRelocator(ArchiveBuilder* builder) : _builder(builder) {} ++ ++ virtual bool do_ref(Ref* ref, bool read_only) { ++ if (ref->not_null()) { ++ ref->update(_builder->get_dumped_addr(ref->obj())); ++ ArchivePtrMarker::mark_pointer(ref->addr()); ++ } ++ return false; // Do not recurse. ++ } ++}; ++ ++void ArchiveBuilder::relocate_roots() { ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Relocating external roots ... "); ++ } ++ ResourceMark rm; ++ RefRelocator doit(this); ++ iterate_sorted_roots(&doit, /*is_relocating_pointers=*/true); ++ doit.finish(); ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("done"); ++ } ++} ++ ++void ArchiveBuilder::relocate_metaspaceobj_embedded_pointers() { ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Relocating embedded pointers in core regions ... "); ++ } ++ relocate_embedded_pointers(&_rw_src_objs); ++ relocate_embedded_pointers(&_ro_src_objs); ++} ++ ++#ifndef PRODUCT ++void ArchiveBuilder::assert_is_vm_thread() { ++ assert(Thread::current()->is_VM_thread(), "ArchiveBuilder should be used only inside the VMThread"); ++} ++#endif +diff --git a/hotspot/src/share/vm/cds/archiveBuilder.hpp b/hotspot/src/share/vm/cds/archiveBuilder.hpp +new file mode 100644 +index 000000000..18cd3c622 +--- /dev/null ++++ b/hotspot/src/share/vm/cds/archiveBuilder.hpp +@@ -0,0 +1,368 @@ ++/* ++ * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef SHARE_VM_CDS_ARCHIVEBUILDER_HPP ++#define SHARE_VM_CDS_ARCHIVEBUILDER_HPP ++ ++#include "cds/archiveUtils.hpp" ++#include "cds/dumpAllocStats.hpp" ++#include "memory/metaspaceClosure.hpp" ++//#include "oops/array.hpp" ++#include "oops/klass.hpp" ++#include "runtime/os.hpp" ++#include "utilities/align.hpp" ++#include "utilities/bitMap.hpp" ++#include "utilities/growableArray.hpp" ++#include "utilities/hashtable.hpp" ++#include "utilities/resourceHash.hpp" ++ ++class FileMapInfo; ++// Overview of CDS archive creation (for both static??? and dynamic dump): ++// ++// [1] Load all classes (static dump: from the classlist, dynamic dump: as part of app execution) ++// [2] Allocate "output buffer" ++// [3] Copy contents of the 2 "core" regions (rw/ro) into the output buffer. ++// - allocate the cpp vtables in rw (static dump only) ++// - memcpy the MetaspaceObjs into rw/ro: ++// dump_rw_region(); ++// dump_ro_region(); ++// - fix all the pointers in the MetaspaceObjs to point to the copies ++// relocate_metaspaceobj_embedded_pointers() ++// [4] Copy symbol table, dictionary, etc, into the ro region ++// [5] Relocate all the pointers in rw/ro, so that the archive can be mapped to ++// the "requested" location without runtime relocation. See relocate_to_requested() ++class ArchiveBuilder : public StackObj { ++protected: ++ DumpRegion* _current_dump_space; ++ address _buffer_bottom; // for writing the contents of rw/ro regions ++ address _last_verified_top; ++ int _num_dump_regions_used; ++ size_t _other_region_used_bytes; ++ ++ // These are the addresses where we will request the static and dynamic archives to be ++ // mapped at run time. If the request fails (due to ASLR), we will map the archives at ++ // os-selected addresses. ++ address _requested_static_archive_bottom; // This is determined solely by the value of ++ // SharedBaseAddress during -Xshare:dump. ++ address _requested_static_archive_top; ++ address _requested_dynamic_archive_bottom; // Used only during dynamic dump. It's placed ++ // immediately above _requested_static_archive_top. ++ address _requested_dynamic_archive_top; ++ ++ // (Used only during dynamic dump) where the static archive is actually mapped. This ++ // may be different than _requested_static_archive_{bottom,top} due to ASLR ++ address _mapped_static_archive_bottom; ++ address _mapped_static_archive_top; ++ ++ intx _buffer_to_requested_delta; ++ ++ DumpRegion* current_dump_space() const { return _current_dump_space; } ++ ++public: ++ enum FollowMode { ++ make_a_copy, point_to_it, set_to_null ++ }; ++ ++private: ++ class SourceObjInfo { ++ MetaspaceClosure::Ref* _ref; ++ uintx _ptrmap_start; // The bit-offset of the start of this object (inclusive) ++ uintx _ptrmap_end; // The bit-offset of the end of this object (exclusive) ++ bool _read_only; ++ FollowMode _follow_mode; ++ int _size_in_bytes; ++ MetaspaceObj::Type _msotype; ++ address _dumped_addr; // Address this->obj(), as used by the dumped archive. ++ address _orig_obj; // The value of the original object (_ref->obj()) when this ++ // SourceObjInfo was created. Note that _ref->obj() may change ++ // later if _ref is relocated. ++ ++ public: ++ SourceObjInfo(MetaspaceClosure::Ref* ref, bool read_only, FollowMode follow_mode) : ++ _ref(ref), _ptrmap_start(0), _ptrmap_end(0), _read_only(read_only), _follow_mode(follow_mode), ++ _size_in_bytes(ref->size() * BytesPerWord), _msotype(ref->msotype()), ++ _orig_obj(ref->obj()) { ++ if (follow_mode == point_to_it) { ++ _dumped_addr = ref->obj(); ++ } else { ++ _dumped_addr = NULL; ++ } ++ } ++ ++ bool should_copy() const { return _follow_mode == make_a_copy; } ++ MetaspaceClosure::Ref* ref() const { return _ref; } ++ void set_dumped_addr(address dumped_addr) { ++ assert(should_copy(), "must be"); ++ assert(_dumped_addr == NULL, "cannot be copied twice"); ++ assert(dumped_addr != NULL, "must be a valid copy"); ++ _dumped_addr = dumped_addr; ++ } ++ void set_ptrmap_start(uintx v) { _ptrmap_start = v; } ++ void set_ptrmap_end(uintx v) { _ptrmap_end = v; } ++ uintx ptrmap_start() const { return _ptrmap_start; } // inclusive ++ uintx ptrmap_end() const { return _ptrmap_end; } // exclusive ++ bool read_only() const { return _read_only; } ++ int size_in_bytes() const { return _size_in_bytes; } ++ address orig_obj() const { return _orig_obj; } ++ address dumped_addr() const { return _dumped_addr; } ++ MetaspaceObj::Type msotype() const { return _msotype; } ++ ++ // convenience accessor ++ address obj() const { return ref()->obj(); } ++ }; ++ ++ class SourceObjList { ++ uintx _total_bytes; ++ GrowableArray* _objs; // Source objects to be archived ++ BitMap _ptrmap; // Marks the addresses of the pointer fields ++ // in the source objects ++ public: ++ SourceObjList(); ++ ~SourceObjList(); ++ GrowableArray* objs() const { return _objs; } ++ ++ void append(MetaspaceClosure::Ref* enclosing_ref, SourceObjInfo* src_info); ++ void remember_embedded_pointer(SourceObjInfo* pointing_obj, MetaspaceClosure::Ref* ref); ++ void relocate(int i, ArchiveBuilder* builder); ++ ++ // convenience accessor ++ SourceObjInfo* at(int i) const { return objs()->at(i); } ++ }; ++ ++ class SrcObjTableCleaner { ++ public: ++ bool do_entry(address key, const SourceObjInfo* value) { ++ delete value->ref(); ++ return true; ++ } ++ }; ++ ++ static const int INITIAL_TABLE_SIZE = 15889; ++ static const int MAX_TABLE_SIZE = 1000000; ++ ++ ReservedSpace _shared_rs; ++ VirtualSpace _shared_vs; ++ ++ DumpRegion _rw_region; ++ DumpRegion _ro_region; ++ BitMap _ptrmap; ++ ++ SourceObjList _rw_src_objs; // objs to put in rw region ++ SourceObjList _ro_src_objs; // objs to put in ro region ++ KVHashtable _src_obj_table; ++ GrowableArray* _klasses; ++ GrowableArray* _symbols; ++ ++ // statistics ++ int _num_instance_klasses; ++ int _num_obj_array_klasses; ++ int _num_type_array_klasses; ++ DumpAllocStats _alloc_stats; ++ ++ // For global access. ++ static ArchiveBuilder* _current; ++ ++public: ++ // Use this when you allocate space outside of ArchiveBuilder::dump_{rw,ro}_region. ++ // These are usually for misc tables that are allocated in the RO space. ++ class OtherROAllocMark { ++ char* _oldtop; ++ public: ++ OtherROAllocMark() { ++ _oldtop = _current->_ro_region.top(); ++ } ++ ~OtherROAllocMark(); ++ }; ++ ++private: ++ FollowMode get_follow_mode(MetaspaceClosure::Ref *ref); ++ ++ void iterate_sorted_roots(MetaspaceClosure* it, bool is_relocating_pointers); ++ void sort_klasses(); ++ static int compare_symbols_by_address(Symbol** a, Symbol** b); ++ static int compare_klass_by_name(Klass** a, Klass** b); ++ ++ bool is_excluded(Klass* k); ++ void clean_up_src_obj_table(); ++ ++ void make_shallow_copies(DumpRegion *dump_region, const SourceObjList* src_objs); ++ void make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* src_info); ++ void relocate_embedded_pointers(SourceObjList* src_objs); ++ ++protected: ++ virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) = 0; ++ ++ // Conservative estimate for number of bytes needed for: ++ size_t _estimated_metaspaceobj_bytes; // all archived MetaspaceObj's. ++ size_t _estimated_hashtable_bytes; // symbol table and dictionaries ++ ++ size_t estimate_archive_size(); ++ ++ static const int _total_dump_regions = 2; ++ ++ void start_dump_space(DumpRegion* next); ++ void verify_estimate_size(size_t estimate, const char* which); ++ ++public: ++ address reserve_buffer(); ++ ++ address buffer_bottom() const { return _buffer_bottom; } ++ address buffer_top() const { return (address)current_dump_space()->top(); } ++ address requested_static_archive_bottom() const { return _requested_static_archive_bottom; } ++ address mapped_static_archive_bottom() const { return _mapped_static_archive_bottom; } ++ intx buffer_to_requested_delta() const { return _buffer_to_requested_delta; } ++ ++ bool is_in_buffer_space(address p) const { ++ return (buffer_bottom() <= p && p < buffer_top()); ++ } ++ ++ template bool is_in_buffer_space(T obj) const { ++ return is_in_buffer_space(address(obj)); ++ } ++ ++ template bool is_in_requested_static_archive(T p) const { ++ return _requested_static_archive_bottom <= (address)p && (address)p < _requested_static_archive_top; ++ } ++ ++ template bool is_in_mapped_static_archive(T p) const { ++ return _mapped_static_archive_bottom <= (address)p && (address)p < _mapped_static_archive_top; ++ } ++ ++ template T to_requested(T obj) const { ++ assert(is_in_buffer_space(obj), "must be"); ++ return (T)(address(obj) + _buffer_to_requested_delta); ++ } ++ ++public: ++ static const uintx MAX_SHARED_DELTA = 0x7FFFFFFF; ++ ++ // The address p points to an object inside the output buffer. When the archive is mapped ++ // at the requested address, what's the offset of this object from _requested_static_archive_bottom? ++ uintx buffer_to_offset(address p) const; ++ ++ // Same as buffer_to_offset, except that the address p points to either (a) an object ++ // inside the output buffer, or (b), an object in the currently mapped static archive. ++ uintx any_to_offset(address p) const; ++ ++ template ++ u4 buffer_to_offset_u4(T p) const { ++ uintx offset = buffer_to_offset((address)p); ++ guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset"); ++ return (u4)offset; ++ } ++ ++ template ++ u4 any_to_offset_u4(T p) const { ++ uintx offset = any_to_offset((address)p); ++ guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset"); ++ return (u4)offset; ++ } ++ ++ static void assert_is_vm_thread() PRODUCT_RETURN; ++ ++public: ++ ArchiveBuilder(); ++ ~ArchiveBuilder(); ++ ++ void gather_klasses_and_symbols(); ++ void replace_klass_in_constanPool(); ++ void gather_source_objs(); ++ bool gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool read_only); ++ bool gather_one_source_obj(MetaspaceClosure::Ref* enclosing_ref, MetaspaceClosure::Ref* ref, bool read_only); ++ void remember_embedded_pointer_in_copied_obj(MetaspaceClosure::Ref* enclosing_ref, MetaspaceClosure::Ref* ref); ++ ++ DumpRegion* rw_region() { return &_rw_region; } ++ DumpRegion* ro_region() { return &_ro_region; } ++ ++ static char* rw_region_alloc(size_t num_bytes) { ++ return current()->rw_region()->allocate(num_bytes); ++ } ++ static char* ro_region_alloc(size_t num_bytes) { ++ return current()->ro_region()->allocate(num_bytes); ++ } ++ ++ template ++ static Array* new_ro_array(int length) { ++ size_t byte_size = Array::byte_sizeof(length); ++ Array* array = (Array*)ro_region_alloc(byte_size); ++ array->initialize(length); ++ return array; ++ } ++ ++ template ++ static Array* new_rw_array(int length) { ++ size_t byte_size = Array::byte_sizeof(length); ++ Array* array = (Array*)rw_region_alloc(byte_size); ++ array->initialize(length); ++ return array; ++ } ++ ++ template ++ static size_t ro_array_bytesize(int length) { ++ size_t byte_size = Array::byte_sizeof(length); ++ return align_up(byte_size, KlassAlignmentInBytes); ++ } ++ ++ void dump_rw_metadata(); ++ void dump_ro_metadata(); ++ void relocate_metaspaceobj_embedded_pointers(); ++ void relocate_roots(); ++ void make_klasses_shareable(); ++ void relocate_to_requested(); ++ void write_archive(FileMapInfo* mapinfo); ++ void write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region, bool read_only, bool allow_exec); ++ address get_dumped_addr(address src_obj); ++ void patch_shared_obj_vtable(); ++ ++ // All klasses and symbols that will be copied into the archive ++ GrowableArray* klasses() const { return _klasses; } ++ GrowableArray* symbols() const { return _symbols; } ++ ++ static bool is_active() { ++ return (_current != NULL); ++ } ++ ++ static ArchiveBuilder* current() { ++ assert_is_vm_thread(); ++ assert(_current != NULL, "ArchiveBuilder must be active"); ++ return _current; ++ } ++ ++ static DumpAllocStats* alloc_stats() { ++ return &(current()->_alloc_stats); ++ } ++ ++ static Symbol* get_relocated_symbol(Symbol* orig_symbol) { ++ return (Symbol*)current()->get_dumped_addr((address)orig_symbol); ++ } ++ ++ static CompactHashtableStats* symbol_stats() { ++ return alloc_stats()->symbol_stats(); ++ } ++ ++ void print_stats(); ++}; ++ ++#endif // SHARE_VM_CDS_ARCHIVEBUILDER_HPP +diff --git a/hotspot/src/share/vm/cds/archiveUtils.cpp b/hotspot/src/share/vm/cds/archiveUtils.cpp +new file mode 100644 +index 000000000..88c04241d +--- /dev/null ++++ b/hotspot/src/share/vm/cds/archiveUtils.cpp +@@ -0,0 +1,247 @@ ++/* ++ * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "cds/archiveBuilder.hpp" ++#include "cds/archiveUtils.hpp" ++#include "cds/dynamicArchive.hpp" ++#include "classfile/systemDictionaryShared.hpp" ++#include "memory/filemap.hpp" ++#include "memory/resourceArea.hpp" ++#include "runtime/arguments.hpp" ++#include "utilities/bitMap.inline.hpp" ++#include "utilities/align.hpp" ++ ++BitMap* ArchivePtrMarker::_ptrmap = NULL; ++VirtualSpace* ArchivePtrMarker::_vs; ++ ++bool ArchivePtrMarker::_compacted; ++ ++void ArchivePtrMarker::initialize(BitMap* ptrmap, VirtualSpace* vs) { ++ assert(_ptrmap == NULL, "initialize only once"); ++ _vs = vs; ++ _compacted = false; ++ _ptrmap = ptrmap; ++ ++ // Use this as initial guesstimate. We should need less space in the ++ // archive, but if we're wrong the bitmap will be expanded automatically. ++ size_t estimated_archive_size = MetaspaceGC::capacity_until_GC(); ++ // But set it smaller in debug builds so we always test the expansion code. ++ // (Default archive is about 12MB). ++ DEBUG_ONLY(estimated_archive_size = 6 * M); ++ ++ // We need one bit per pointer in the archive. ++ _ptrmap->resize(estimated_archive_size / sizeof(intptr_t), false); ++} ++ ++void ArchivePtrMarker::mark_pointer(address* ptr_loc) { ++ assert(_ptrmap != NULL, "not initialized"); ++ assert(!_compacted, "cannot mark anymore"); ++ ++ if (ptr_base() <= ptr_loc && ptr_loc < ptr_end()) { ++ address value = *ptr_loc; ++ // We don't want any pointer that points to very bottom of the archive, otherwise when ++ // MetaspaceShared::default_base_address()==0, we can't distinguish between a pointer ++ // to nothing (NULL) vs a pointer to an objects that happens to be at the very bottom ++ // of the archive. ++ assert(value != (address)ptr_base(), "don't point to the bottom of the archive"); ++ ++ if (value != NULL) { ++ assert(uintx(ptr_loc) % sizeof(intptr_t) == 0, "pointers must be stored in aligned addresses"); ++ size_t idx = ptr_loc - ptr_base(); ++ if (_ptrmap->size() <= idx) { ++ _ptrmap->resize((idx + 1) * 2, false); ++ } ++ assert(idx < _ptrmap->size(), "must be"); ++ _ptrmap->set_bit(idx); ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Marking pointer [" PTR_FORMAT "] -> " PTR_FORMAT " @ " SIZE_FORMAT_W(5), p2i(ptr_loc), p2i(*ptr_loc), idx); ++ } ++ } ++ } ++} ++ ++void ArchivePtrMarker::clear_pointer(address* ptr_loc) { ++ assert(_ptrmap != NULL, "not initialized"); ++ assert(!_compacted, "cannot clear anymore"); ++ ++ assert(ptr_base() <= ptr_loc && ptr_loc < ptr_end(), "must be"); ++ assert(uintx(ptr_loc) % sizeof(intptr_t) == 0, "pointers must be stored in aligned addresses"); ++ size_t idx = ptr_loc - ptr_base(); ++ assert(idx < _ptrmap->size(), "cannot clear pointers that have not been marked"); ++ _ptrmap->clear_bit(idx); ++ if (TraceDynamicCDS) ++ dynamic_cds_log->print_cr("Clearing pointer [" PTR_FORMAT "] -> " PTR_FORMAT " @ " SIZE_FORMAT_W(5), p2i(ptr_loc), p2i(*ptr_loc), idx); ++} ++ ++class ArchivePtrBitmapCleaner: public BitMapClosure { ++ BitMap* _ptrmap; ++ address* _ptr_base; ++ address _relocatable_base; ++ address _relocatable_end; ++ size_t _max_non_null_offset; ++ ++public: ++ ArchivePtrBitmapCleaner(BitMap* ptrmap, address* ptr_base, address relocatable_base, address relocatable_end) : ++ _ptrmap(ptrmap), _ptr_base(ptr_base), ++ _relocatable_base(relocatable_base), _relocatable_end(relocatable_end), _max_non_null_offset(0) {} ++ ++ bool do_bit(size_t offset) { ++ address* ptr_loc = _ptr_base + offset; ++ address ptr_value = *ptr_loc; ++ if (ptr_value != NULL) { ++ assert(_relocatable_base <= ptr_value && ptr_value < _relocatable_end, "do not point to arbitrary locations!"); ++ if (_max_non_null_offset < offset) { ++ _max_non_null_offset = offset; ++ } ++ } else { ++ _ptrmap->clear_bit(offset); ++ } ++ ++ return true; ++ } ++ ++ size_t max_non_null_offset() const { return _max_non_null_offset; } ++}; ++ ++void ArchivePtrMarker::compact(address relocatable_base, address relocatable_end) { ++ assert(!_compacted, "cannot compact again"); ++ ArchivePtrBitmapCleaner cleaner(_ptrmap, ptr_base(), relocatable_base, relocatable_end); ++ _ptrmap->iterate(&cleaner); ++ compact(cleaner.max_non_null_offset()); ++} ++ ++void ArchivePtrMarker::compact(size_t max_non_null_offset) { ++ assert(!_compacted, "cannot compact again"); ++ _ptrmap->resize(max_non_null_offset + 1, false); ++ _compacted = true; ++} ++ ++char* DumpRegion::expand_top_to(char* newtop) { ++ assert(is_allocatable(), "must be initialized and not packed"); ++ assert(newtop >= _top, "must not grow backwards"); ++ if (newtop > _end) { ++ vm_exit_during_initialization("Unable to allocate memory", ++ "Please reduce the number of shared classes."); ++ ShouldNotReachHere(); ++ } ++ ++ commit_to(newtop); ++ _top = newtop; ++ ++ if (_max_delta > 0) { ++ uintx delta = ArchiveBuilder::current()->buffer_to_offset((address)(newtop-1)); ++ if (delta > _max_delta) { ++ // This is just a sanity check and should not appear in any real world usage. This ++ // happens only if you allocate more than 2GB of shared objects and would require ++ // millions of shared classes. ++ vm_exit_during_initialization("Out of memory in the CDS archive", ++ "Please reduce the number of shared classes."); ++ } ++ } ++ ++ return _top; ++} ++ ++void DumpRegion::commit_to(char* newtop) { ++ Arguments::assert_is_dumping_archive(); ++ char* base = _rs->base(); ++ size_t need_committed_size = newtop - base; ++ size_t has_committed_size = _vs->committed_size(); ++ if (need_committed_size < has_committed_size) { ++ return; ++ } ++ ++ size_t min_bytes = need_committed_size - has_committed_size; ++ size_t preferred_bytes = 1 * M; ++ size_t uncommitted = _vs->reserved_size() - has_committed_size; ++ ++ size_t commit = MAX2(min_bytes, preferred_bytes); ++ commit = MIN2(commit, uncommitted); ++ assert(commit <= uncommitted, "sanity"); ++ ++ if (!_vs->expand_by(commit, false)) { ++ vm_exit_during_initialization(err_msg("Failed to expand shared space to " SIZE_FORMAT " bytes", ++ need_committed_size)); ++ } ++ ++ if (DebugDynamicCDS) { ++ dynamic_cds_log->print_cr("Expanding shared spaces by " SIZE_FORMAT_W(7) " bytes [total " SIZE_FORMAT_W(9) " bytes ending at %p]", ++ commit, _vs->actual_committed_size(), _vs->high()); ++ } ++} ++ ++char* DumpRegion::allocate(size_t num_bytes) { ++ char* p = (char*)align_up(_top, (size_t)KlassAlignmentInBytes); ++ char* newtop = p + align_up(num_bytes, (size_t)KlassAlignmentInBytes); ++ expand_top_to(newtop); ++ memset(p, 0, newtop - p); ++ return p; ++} ++ ++void DumpRegion::append_intptr_t(intptr_t n, bool need_to_mark) { ++ assert(is_aligned(_top, sizeof(intptr_t)), "bad alignment"); ++ intptr_t *p = (intptr_t*)_top; ++ char* newtop = _top + sizeof(intptr_t); ++ expand_top_to(newtop); ++ *p = n; ++ if (need_to_mark) { ++ ArchivePtrMarker::mark_pointer(p); ++ } ++} ++ ++void DumpRegion::init(ReservedSpace* rs, VirtualSpace* vs) { ++ _rs = rs; ++ _vs = vs; ++ // Start with 0 committed bytes. The memory will be committed as needed. ++ if (!_vs->initialize(*_rs, 0)) { ++ fatal("Unable to allocate memory for shared space"); ++ } ++ _base = _top = _rs->base(); ++ _end = _rs->base() + _rs->size(); ++} ++ ++void DumpRegion::pack(DumpRegion* next) { ++ assert(!is_packed(), "sanity"); ++ _end = (char*)align_up(_top, (size_t)os::vm_allocation_granularity()); ++ _is_packed = true; ++ if (next != NULL) { ++ next->_rs = _rs; ++ next->_vs = _vs; ++ next->_base = next->_top = this->_end; ++ next->_end = _rs->base() + _rs->size(); ++ } ++} ++ ++void DynamicWriteClosure::do_region(u_char* start, size_t size) { ++ assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment"); ++ assert(size % sizeof(intptr_t) == 0, "bad size"); ++ do_tag((int)size); ++ while (size > 0) { ++ _dump_region->append_intptr_t(*(intptr_t*)start, true); ++ start += sizeof(intptr_t); ++ size -= sizeof(intptr_t); ++ } ++} +diff --git a/hotspot/src/share/vm/cds/archiveUtils.hpp b/hotspot/src/share/vm/cds/archiveUtils.hpp +new file mode 100644 +index 000000000..55c2431a0 +--- /dev/null ++++ b/hotspot/src/share/vm/cds/archiveUtils.hpp +@@ -0,0 +1,141 @@ ++/* ++ * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef SHARE_VM_CDS_ARCHIVEUTILS_HPP ++#define SHARE_VM_CDS_ARCHIVEUTILS_HPP ++ ++#include "memory/iterator.hpp" ++#include "runtime/virtualspace.hpp" ++#include "utilities/bitMap.hpp" ++ ++class ArchivePtrMarker : AllStatic { ++ static BitMap* _ptrmap; ++ static VirtualSpace* _vs; ++ ++ // Once _ptrmap is compacted, we don't allow bit marking anymore. This is to ++ // avoid unintentional copy operations after the bitmap has been finalized and written. ++ static bool _compacted; ++ ++ static address* ptr_base() { return (address*)_vs->low(); } // committed lower bound (inclusive) ++ static address* ptr_end() { return (address*)_vs->high(); } // committed upper bound (exclusive) ++ ++public: ++ static void initialize(BitMap* ptrmap, VirtualSpace* vs); ++ static void mark_pointer(address* ptr_loc); ++ static void clear_pointer(address* ptr_loc); ++ static void compact(address relocatable_base, address relocatable_end); ++ static void compact(size_t max_non_null_offset); ++ ++ template ++ static void mark_pointer(T* ptr_loc) { ++ mark_pointer((address*)ptr_loc); ++ } ++ ++ template ++ static void set_and_mark_pointer(T* ptr_loc, T ptr_value) { ++ *ptr_loc = ptr_value; ++ mark_pointer(ptr_loc); ++ } ++ ++ static BitMap* ptrmap() { ++ return _ptrmap; ++ } ++}; ++ ++class DumpRegion { ++private: ++ const char* _name; ++ char* _base; ++ char* _top; ++ char* _end; ++ uintx _max_delta; ++ bool _is_packed; ++ ReservedSpace* _rs; ++ VirtualSpace* _vs; ++ ++ void commit_to(char* newtop); ++ ++public: ++ DumpRegion(const char* name, uintx max_delta = 0) ++ : _name(name), _base(NULL), _top(NULL), _end(NULL), ++ _max_delta(max_delta), _is_packed(false) {} ++ ++ char* expand_top_to(char* newtop); ++ char* allocate(size_t num_bytes); ++ ++ void append_intptr_t(intptr_t n, bool need_to_mark = false); ++ ++ char* base() const { return _base; } ++ char* top() const { return _top; } ++ char* end() const { return _end; } ++ size_t reserved() const { return _end - _base; } ++ size_t used() const { return _top - _base; } ++ bool is_packed() const { return _is_packed; } ++ bool is_allocatable() const { ++ return !is_packed() && _base != NULL; ++ } ++ ++ void print(size_t total_bytes) const; ++ void print_out_of_space_msg(const char* failing_region, size_t needed_bytes); ++ ++ void init(ReservedSpace* rs, VirtualSpace* vs); ++ ++ void pack(DumpRegion* next = NULL); ++ ++ bool contains(char* p) const { ++ return base() <= p && p < top(); ++ } ++}; ++ ++// Closure for serializing initialization data out to a data area to be ++// written to the shared file. ++ ++class DynamicWriteClosure : public SerializeClosure { ++private: ++ DumpRegion* _dump_region; ++ ++public: ++ DynamicWriteClosure(DumpRegion* r) { ++ _dump_region = r; ++ } ++ ++ void do_ptr(void** p) { ++ _dump_region->append_intptr_t((intptr_t)*p, true); ++ } ++ ++ void do_u4(u4* p) { ++ _dump_region->append_intptr_t((intptr_t)(*p)); ++ } ++ ++ void do_tag(int tag) { ++ _dump_region->append_intptr_t((intptr_t)tag); ++ } ++ ++ //void do_oop(oop* o); ++ void do_region(u_char* start, size_t size); ++ bool reading() const { return false; } ++}; ++ ++#endif // SHARE_VM_CDS_ARCHIVEUTILS_HPP +diff --git a/hotspot/src/share/vm/cds/dumpAllocStats.cpp b/hotspot/src/share/vm/cds/dumpAllocStats.cpp +new file mode 100644 +index 000000000..e9146555d +--- /dev/null ++++ b/hotspot/src/share/vm/cds/dumpAllocStats.cpp +@@ -0,0 +1,109 @@ ++/* ++ * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "cds/dumpAllocStats.hpp" ++ ++// Returns numerator/denominator as percentage value from 0 to 100. If denominator ++// is zero, return 0.0. ++static inline double percent_of(int numerator, int denominator) { ++ return denominator != 0 ? (double)numerator / denominator * 100.0 : 0.0; ++} ++ ++void DumpAllocStats::print_stats(int ro_all, int rw_all) { ++ if (!DebugDynamicCDS) { ++ return; ++ } ++ ++ // symbols ++ _counts[RO][SymbolHashentryType] = _symbol_stats.hashentry_count; ++ _bytes [RO][SymbolHashentryType] = _symbol_stats.hashentry_bytes; ++ ++ _counts[RO][SymbolBucketType] = _symbol_stats.bucket_count; ++ _bytes [RO][SymbolBucketType] = _symbol_stats.bucket_bytes; ++ ++ // prevent divide-by-zero ++ if (ro_all < 1) { ++ ro_all = 1; ++ } ++ if (rw_all < 1) { ++ rw_all = 1; ++ } ++ ++ int all_ro_count = 0; ++ int all_ro_bytes = 0; ++ int all_rw_count = 0; ++ int all_rw_bytes = 0; ++ ++// To make fmt_stats be a syntactic constant (for format warnings), use #define. ++#define fmt_stats "%-20s: %8d %10d %5.1f | %8d %10d %5.1f | %8d %10d %5.1f" ++ const char *sep = "--------------------+---------------------------+---------------------------+--------------------------"; ++ const char *hdr = " ro_cnt ro_bytes % | rw_cnt rw_bytes % | all_cnt all_bytes %"; ++ ++ dynamic_cds_log->print_cr("Detailed metadata info (excluding heap regions):"); ++ dynamic_cds_log->print_cr("%s", hdr); ++ dynamic_cds_log->print_cr("%s", sep); ++ for (int type = 0; type < int(_number_of_types); type ++) { ++ const char *name = type_name((Type)type); ++ int ro_count = _counts[RO][type]; ++ int ro_bytes = _bytes [RO][type]; ++ int rw_count = _counts[RW][type]; ++ int rw_bytes = _bytes [RW][type]; ++ int count = ro_count + rw_count; ++ int bytes = ro_bytes + rw_bytes; ++ ++ double ro_perc = percent_of(ro_bytes, ro_all); ++ double rw_perc = percent_of(rw_bytes, rw_all); ++ double perc = percent_of(bytes, ro_all + rw_all); ++ ++ dynamic_cds_log->print_cr(fmt_stats, name, ++ ro_count, ro_bytes, ro_perc, ++ rw_count, rw_bytes, rw_perc, ++ count, bytes, perc); ++ ++ all_ro_count += ro_count; ++ all_ro_bytes += ro_bytes; ++ all_rw_count += rw_count; ++ all_rw_bytes += rw_bytes; ++ } ++ ++ int all_count = all_ro_count + all_rw_count; ++ int all_bytes = all_ro_bytes + all_rw_bytes; ++ ++ double all_ro_perc = percent_of(all_ro_bytes, ro_all); ++ double all_rw_perc = percent_of(all_rw_bytes, rw_all); ++ double all_perc = percent_of(all_bytes, ro_all + rw_all); ++ ++ dynamic_cds_log->print_cr("%s", sep); ++ dynamic_cds_log->print_cr(fmt_stats, "Total", ++ all_ro_count, all_ro_bytes, all_ro_perc, ++ all_rw_count, all_rw_bytes, all_rw_perc, ++ all_count, all_bytes, all_perc); ++ ++ assert(all_ro_bytes == ro_all, "everything should have been counted"); ++ assert(all_rw_bytes == rw_all, "everything should have been counted"); ++ ++#undef fmt_stats ++} +diff --git a/hotspot/src/share/vm/cds/dumpAllocStats.hpp b/hotspot/src/share/vm/cds/dumpAllocStats.hpp +new file mode 100644 +index 000000000..2f9247bcb +--- /dev/null ++++ b/hotspot/src/share/vm/cds/dumpAllocStats.hpp +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef SHARE_VM_CDS_DUMPALLOCSTATS_HPP ++#define SHARE_VM_CDS_DUMPALLOCSTATS_HPP ++ ++#include "classfile/compactHashtable.hpp" ++#include "memory/allocation.hpp" ++ ++// This is for dumping detailed statistics for the allocations ++// in the shared spaces. ++class DumpAllocStats : public ResourceObj { ++public: ++ // Here's poor man's enum inheritance ++#define SHAREDSPACE_OBJ_TYPES_DO(f) \ ++ METASPACE_OBJ_TYPES_DO(f) \ ++ f(SymbolHashentry) \ ++ f(SymbolBucket) \ ++ f(Other) ++ ++ enum Type { ++ // Types are MetaspaceObj::ClassType, MetaspaceObj::SymbolType, etc ++ SHAREDSPACE_OBJ_TYPES_DO(METASPACE_OBJ_TYPE_DECLARE) ++ _number_of_types ++ }; ++ ++ static const char* type_name(Type type) { ++ switch(type) { ++ SHAREDSPACE_OBJ_TYPES_DO(METASPACE_OBJ_TYPE_NAME_CASE) ++ default: ++ ShouldNotReachHere(); ++ return NULL; ++ } ++ } ++ ++ CompactHashtableStats _symbol_stats; ++ ++ int _counts[2][_number_of_types]; ++ int _bytes [2][_number_of_types]; ++ ++public: ++ enum { RO = 0, RW = 1 }; ++ ++ DumpAllocStats() { ++ memset(_counts, 0, sizeof(_counts)); ++ memset(_bytes, 0, sizeof(_bytes)); ++ }; ++ ++ CompactHashtableStats* symbol_stats() { return &_symbol_stats; } ++ ++ void record(MetaspaceObj::Type type, int byte_size, bool read_only) { ++ assert(int(type) >= 0 && type < MetaspaceObj::_number_of_types, "sanity"); ++ int which = (read_only) ? RO : RW; ++ _counts[which][type] ++; ++ _bytes [which][type] += byte_size; ++ } ++ ++ void record_other_type(int byte_size, bool read_only) { ++ int which = (read_only) ? RO : RW; ++ _bytes [which][OtherType] += byte_size; ++ } ++ ++ void print_stats(int ro_all, int rw_all); ++}; ++ ++#endif // SHARE_VM_CDS_DUMPALLOCSTATS_HPP +diff --git a/hotspot/src/share/vm/cds/dynamicArchive.cpp b/hotspot/src/share/vm/cds/dynamicArchive.cpp +new file mode 100644 +index 000000000..efed275c8 +--- /dev/null ++++ b/hotspot/src/share/vm/cds/dynamicArchive.cpp +@@ -0,0 +1,412 @@ ++/* ++ * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "cds/archiveBuilder.hpp" ++#include "cds/archiveUtils.hpp" ++#include "cds/dynamicArchive.hpp" ++#include "classfile/systemDictionaryShared.hpp" ++#include "runtime/vm_operations.hpp" ++#include "runtime/arguments.hpp" ++#include "runtime/vmThread.hpp" ++#include "memory/metaspaceShared.hpp" ++#include "memory/filemap.hpp" ++#include "memory/metaspaceClosure.hpp" ++#include "utilities/exceptions.hpp" ++#include "utilities/align.hpp" ++#include "utilities/bitMap.hpp" ++#include "utilities/exceptions.hpp" ++ ++class DynamicArchiveBuilder : public ArchiveBuilder { ++public: ++ static int dynamic_dump_method_comparator(Method* a, Method* b) { ++ Symbol* a_name = a->name(); ++ Symbol* b_name = b->name(); ++ ++ if (a_name == b_name) { ++ return 0; ++ } ++ ++ u4 a_offset = ArchiveBuilder::current()->any_to_offset_u4(a_name); ++ u4 b_offset = ArchiveBuilder::current()->any_to_offset_u4(b_name); ++ ++ if (a_offset < b_offset) { ++ return -1; ++ } else { ++ assert(a_offset > b_offset, "must be"); ++ return 1; ++ } ++ } ++ ++public: ++ FileMapInfo::DynamicArchiveHeader* _header; ++ ++ void init_header(); ++ void release_header(); ++ void sort_methods(); ++ void sort_methods(InstanceKlass* ik) const; ++ void remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const; ++ void write_archive(char* serialized_data); ++ virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) { ++ SystemDictionaryShared::dumptime_classes_do(it); ++ } ++ ++ // Do this before and after the archive dump to see if any corruption ++ // is caused by dynamic dumping. ++ void verify_universe(const char* info) { ++ if (VerifyBeforeExit) { ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Verify %s", info); ++ } ++ // Among other things, this ensures that Eden top is correct. ++ Universe::heap()->prepare_for_verify(); ++ Universe::verify(info); ++ } ++ } ++ ++ void doit() { ++ SystemDictionaryShared::start_dumping(); ++ ++ verify_universe("Before CDS dynamic dump"); ++ DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); ++ ++ // No need DumpTimeTable_lock, since jdk8 doesn't support jcmd dump. ++ // Just remains this lock. ++ MutexLockerEx ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); ++ SystemDictionaryShared::check_excluded_classes(); ++ SystemDictionaryShared::replace_klass_in_constantPool(); ++ ++ init_header(); ++ gather_source_objs(); ++ if (klasses()->length() == 0) { ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("No classes gathered, so do not generate Dynamic CDS jsa"); ++ } ++ return; ++ } ++ reserve_buffer(); ++ ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Copying %d klasses and %d symbols", ++ klasses()->length(), symbols()->length()); ++ } ++ dump_rw_metadata(); ++ dump_ro_metadata(); ++ relocate_metaspaceobj_embedded_pointers(); ++ relocate_roots(); ++ ++ verify_estimate_size(_estimated_metaspaceobj_bytes, "MetaspaceObjs"); ++ ++ char* serialized_data; ++ { ++ // Write the symbol table and system dictionaries to the RO space. ++ // Note that these tables still point to the *original* objects, so ++ // they would need to get the correct addresses. ++ assert(current_dump_space() == ro_region(), "Must be RO space"); ++ SymbolTable::write_to_archive(symbols()); ++ ++ ArchiveBuilder::OtherROAllocMark mark; ++ SystemDictionaryShared::write_to_archive(); ++ ++ serialized_data = ro_region()->top(); ++ DynamicWriteClosure wc(ro_region()); ++ SymbolTable::serialize_shared_table_header(&wc); ++ SystemDictionaryShared::serialize_dictionary_headers(&wc); ++ } ++ ++ verify_estimate_size(_estimated_hashtable_bytes, "Hashtables"); ++ ++ sort_methods(); ++ ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Make classes shareable"); ++ } ++ make_klasses_shareable(); ++ ++ patch_shared_obj_vtable(); ++ ++ relocate_to_requested(); ++ ++ write_archive(serialized_data); ++ release_header(); ++ ++ assert(_num_dump_regions_used == _total_dump_regions, "must be"); ++ verify_universe("After CDS dynamic dump"); ++ } ++}; ++ ++void DynamicArchiveBuilder::init_header() { ++ FileMapInfo* mapinfo = new FileMapInfo(false); ++ assert(FileMapInfo::dynamic_info() == mapinfo, "must be"); ++ _header = mapinfo->dynamic_header(); ++ ++ FileMapInfo* base_info = FileMapInfo::current_info(); ++ _header->set_base_header_crc(base_info->header()->crc()); ++ for (int i = 0; i < MetaspaceShared::n_regions; i++) { ++ _header->set_base_region_crc(i, base_info->header()->space_crc(i)); ++ } ++ ++ _header->populate(base_info, base_info->alignment()); ++} ++ ++void DynamicArchiveBuilder::release_header() { ++ // We temporarily allocated a dynamic FileMapInfo for dumping, which makes it appear we ++ // have mapped a dynamic archive, but we actually have not. We are in a safepoint now. ++ // Let's free it so that if class loading happens after we leave the safepoint, nothing ++ // bad will happen. ++ assert(SafepointSynchronize::is_at_safepoint(), "must be"); ++ FileMapInfo *mapinfo = FileMapInfo::dynamic_info(); ++ assert(mapinfo != NULL && _header == mapinfo->dynamic_header(), "must be"); ++ delete mapinfo; ++ assert(!DynamicArchive::is_mapped(), "must be"); ++ _header = NULL; ++} ++ ++void DynamicArchiveBuilder::sort_methods() { ++ // Because high version support jcmd dynamic cds dump, jvm need go on after dump. ++ // Jdk8 no need as so, just exit after dump. ++ InstanceKlass::disable_method_binary_search(); ++ for (int i = 0; i < klasses()->length(); i++) { ++ Klass* k = klasses()->at(i); ++ if (k->oop_is_instance()) { ++ sort_methods(InstanceKlass::cast(k)); ++ } ++ } ++} ++ ++// The address order of the copied Symbols may be different than when the original ++// klasses were created. Re-sort all the tables. See Method::sort_methods(). ++void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { ++ assert(ik != NULL, "DynamicArchiveBuilder currently doesn't support dumping the base archive"); ++ if (MetaspaceShared::is_in_shared_space(ik)) { ++ // We have reached a supertype that's already in the base archive ++ return; ++ } ++ ++ if (ik->java_mirror() == NULL) { ++ // NULL mirror means this class has already been visited and methods are already sorted ++ return; ++ } ++ ik->remove_java_mirror(); ++ ++ if (DebugDynamicCDS) { ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("sorting methods for " PTR_FORMAT " (" PTR_FORMAT ") %s", ++ p2i(ik), p2i(to_requested(ik)), ik->external_name()); ++ } ++ // Method sorting may re-layout the [iv]tables, which would change the offset(s) ++ // of the locations in an InstanceKlass that would contain pointers. Let's clear ++ // all the existing pointer marking bits, and re-mark the pointers after sorting. ++ remark_pointers_for_instance_klass(ik, false); ++ ++ // Make sure all supertypes have been sorted ++ sort_methods(ik->java_super()); ++ Array* interfaces = ik->local_interfaces(); ++ int len = interfaces->length(); ++ for (int i = 0; i < len; i++) { ++ sort_methods(InstanceKlass::cast(interfaces->at(i))); ++ } ++ ++#ifdef ASSERT ++ if (ik->methods() != NULL) { ++ for (int m = 0; m < ik->methods()->length(); m++) { ++ Symbol* name = ik->methods()->at(m)->name(); ++ assert(MetaspaceShared::is_in_shared_space(name) || is_in_buffer_space(name), "must be"); ++ } ++ } ++ if (ik->default_methods() != NULL) { ++ for (int m = 0; m < ik->default_methods()->length(); m++) { ++ Symbol* name = ik->default_methods()->at(m)->name(); ++ assert(MetaspaceShared::is_in_shared_space(name) || is_in_buffer_space(name), "must be"); ++ } ++ } ++#endif ++ ++ Method::sort_methods(ik->methods(), /*idempotent=*/false, /*set_idnums=*/true, dynamic_dump_method_comparator); ++ if (ik->default_methods() != NULL) { ++ Method::sort_methods(ik->default_methods(), /*idempotent=*/false, /*set_idnums=*/false, dynamic_dump_method_comparator); ++ } ++ ++ EXCEPTION_MARK; ++ ++ ik->vtable()->initialize_vtable(false, CATCH); // No need checkconstraints ++ CLEAR_PENDING_EXCEPTION; ++ ik->itable()->initialize_itable(false, CATCH); ++ CLEAR_PENDING_EXCEPTION; ++ ++ // Set all the pointer marking bits after sorting. ++ remark_pointers_for_instance_klass(ik, true); ++} ++ ++template ++class PointerRemarker: public MetaspaceClosure { ++public: ++ virtual bool do_ref(Ref* ref, bool read_only) { ++ if (should_mark) { ++ ArchivePtrMarker::mark_pointer(ref->addr()); ++ } else { ++ ArchivePtrMarker::clear_pointer(ref->addr()); ++ } ++ return false; // don't recurse ++ } ++}; ++ ++void DynamicArchiveBuilder::remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const { ++ if (should_mark) { ++ PointerRemarker marker; ++ k->metaspace_pointers_do(&marker); ++ marker.finish(); ++ } else { ++ PointerRemarker marker; ++ k->metaspace_pointers_do(&marker); ++ marker.finish(); ++ } ++} ++ ++void DynamicArchiveBuilder::write_archive(char* serialized_data) { ++ _header->set_serialized_data(serialized_data); ++ ++ FileMapInfo* dynamic_info = FileMapInfo::dynamic_info(); ++ assert(dynamic_info != NULL, "Sanity"); ++ ++ // Update file offset ++ ArchiveBuilder::write_archive(dynamic_info); ++ ++ // Write into file ++ dynamic_info->open_for_write(); ++ dynamic_info->set_requested_base((char*)MetaspaceShared::requested_base_address()); ++ dynamic_info->set_header_base_archive_name_size(strlen(Arguments::GetSharedArchivePath()) + 1); ++ dynamic_info->set_header_crc(dynamic_info->compute_header_crc()); ++ ArchiveBuilder::write_archive(dynamic_info); ++ ++ address base = _requested_dynamic_archive_bottom; ++ address top = _requested_dynamic_archive_top; ++ size_t file_size = pointer_delta(top, base, sizeof(char)); ++ ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Written dynamic archive " PTR_FORMAT " - " PTR_FORMAT ++ " , " SIZE_FORMAT " bytes total]", ++ p2i(base), p2i(top), file_size); ++ ++ dynamic_cds_log->print_cr("%d klasses; %d symbols", klasses()->length(), symbols()->length()); ++ } ++} ++ ++class VM_GC_Sync_Operation : public VM_Operation { ++public: ++ ++ VM_GC_Sync_Operation() : VM_Operation() { } ++ ++ // Acquires the Heap_lock. ++ virtual bool doit_prologue() { ++ Heap_lock->lock(); ++ return true; ++ } ++ // Releases the Heap_lock. ++ virtual void doit_epilogue() { ++ Heap_lock->unlock(); ++ } ++}; ++ ++class VM_PopulateDynamicDumpSharedSpace : public VM_GC_Sync_Operation { ++ DynamicArchiveBuilder builder; ++public: ++ VM_PopulateDynamicDumpSharedSpace() : VM_GC_Sync_Operation() {} ++ VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; } ++ void doit() { ++ if (DynamicDumpSharedSpaces == false) { ++ return; ++ } ++ ResourceMark rm; ++ ++ if (SystemDictionaryShared::empty_dumptime_table()) { ++ tty->print_cr("There is no class to be included in the dynamic archive."); ++ return; ++ } ++ ++ builder.doit(); ++ ++ DynamicDumpSharedSpaces = false; ++ exit(0); ++ } ++}; ++ ++bool DynamicArchive::_has_been_dumped_once = false; ++ ++void DynamicArchive::prepare_for_dynamic_dumping_at_exit() { ++ { ++ MutexLockerEx ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); ++ if (DynamicArchive::has_been_dumped_once()) { ++ return; ++ } else { ++ DynamicArchive::set_has_been_dumped_once(); ++ } ++ } ++ EXCEPTION_MARK; ++ ResourceMark rm(THREAD); ++ MetaspaceShared::link_and_cleanup_shared_classes(THREAD); ++ ++ if (HAS_PENDING_EXCEPTION) { ++ tty->print_cr("ArchiveClassesAtExit has failed"); ++ tty->print_cr("%s: %s", PENDING_EXCEPTION->klass()->external_name(), ++ java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); ++ // We cannot continue to dump the archive anymore. ++ DynamicDumpSharedSpaces = false; ++ CLEAR_PENDING_EXCEPTION; ++ } ++} ++ ++void DynamicArchive::dump() { ++ if (Arguments::GetSharedDynamicArchivePath() == NULL) { ++ tty->print_cr("SharedDynamicArchivePath is not specified"); ++ return; ++ } ++ ++ VM_PopulateDynamicDumpSharedSpace op; ++ VMThread::execute(&op); ++} ++ ++bool DynamicArchive::validate(FileMapInfo* dynamic_info) { ++ assert(!dynamic_info->is_static(), "must be"); ++ // Check if the recorded base archive matches with the current one ++ FileMapInfo* base_info = FileMapInfo::current_info(); ++ FileMapInfo::DynamicArchiveHeader* dynamic_header = dynamic_info->dynamic_header(); ++ ++ // Check the header crc ++ if (dynamic_header->base_header_crc() != base_info->crc()) { ++ FileMapInfo::fail_continue("Dynamic archive cannot be used: static archive header checksum verification failed."); ++ return false; ++ } ++ ++ // Check each space's crc ++ for (int i = 0; i < MetaspaceShared::n_regions; i++) { ++ if (dynamic_header->base_region_crc(i) != base_info->space_crc(i)) { ++ FileMapInfo::fail_continue("Dynamic archive cannot be used: static archive region #%d checksum verification failed.", i); ++ return false; ++ } ++ } ++ ++ return true; ++} +diff --git a/hotspot/src/share/vm/cds/dynamicArchive.hpp b/hotspot/src/share/vm/cds/dynamicArchive.hpp +new file mode 100644 +index 000000000..1d5b71221 +--- /dev/null ++++ b/hotspot/src/share/vm/cds/dynamicArchive.hpp +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef SHARE_VM_CDS_DYNAMICARCHIVE_HPP ++#define SHARE_VM_CDS_DYNAMICARCHIVE_HPP ++ ++//#include "classfile/compactHashtable.hpp" ++#include "memory/allocation.hpp" ++#include "memory/filemap.hpp" ++#include "memory/memRegion.hpp" ++#include "runtime/virtualspace.hpp" ++#include "oops/oop.hpp" ++#include "utilities/exceptions.hpp" ++#include "utilities/macros.hpp" ++#include "utilities/resourceHash.hpp" ++ ++#if INCLUDE_CDS ++ ++// Fixme ++class DynamicArchive : AllStatic { ++ static bool _has_been_dumped_once; ++public: ++ static void prepare_for_dynamic_dumping_at_exit(); ++ static void dump(); ++ static bool has_been_dumped_once() { return _has_been_dumped_once; } ++ static void set_has_been_dumped_once() { _has_been_dumped_once = true; } ++ static bool is_mapped() { return FileMapInfo::dynamic_info() != NULL; } ++ static bool validate(FileMapInfo* dynamic_info); ++}; ++ ++#endif // INCLUDE_CDS ++#endif // SHARE_VM_CDS_DYNAMICARCHIVE_HPP +diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp +index 5c36a9d6f..ae9199525 100644 +--- a/hotspot/src/share/vm/classfile/classFileParser.cpp ++++ b/hotspot/src/share/vm/classfile/classFileParser.cpp +@@ -4376,6 +4376,13 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, + instanceKlassHandle this_klass (THREAD, preserve_this_klass); + debug_only(this_klass->verify();) + ++#if INCLUDE_CDS ++ if (DynamicDumpSharedSpaces && !SystemDictionary::is_builtin_loader(class_loader)) { ++ this_klass->set_shared_classpath_index(UNREGISTERED_INDEX); ++ SystemDictionaryShared::set_shared_class_misc_info(this_klass(), cfs); ++ } ++#endif // INCLUDE_CDS ++ + // Clear class if no error has occurred so destructor doesn't deallocate it + _klass = NULL; + return this_klass; +diff --git a/hotspot/src/share/vm/classfile/classLoaderExt.hpp b/hotspot/src/share/vm/classfile/classLoaderExt.hpp +index 7b2360af9..3bd4f3bde 100644 +--- a/hotspot/src/share/vm/classfile/classLoaderExt.hpp ++++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp +@@ -48,7 +48,7 @@ public: + instanceKlassHandle record_result(const int classpath_index, + ClassPathEntry* e, instanceKlassHandle result, TRAPS) { + if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) { +- if (DumpSharedSpaces) { ++ if (DumpSharedSpaces || DynamicDumpSharedSpaces) { + result->set_shared_classpath_index(classpath_index); + } + return result; +diff --git a/hotspot/src/share/vm/classfile/compactHashtable.cpp b/hotspot/src/share/vm/classfile/compactHashtable.cpp +new file mode 100644 +index 000000000..232a89fa1 +--- /dev/null ++++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp +@@ -0,0 +1,216 @@ ++/* ++ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "jvm.h" ++#include "cds/archiveBuilder.hpp" ++#include "classfile/compactHashtable.hpp" ++#include "classfile/javaClasses.hpp" ++#include "memory/metadataFactory.hpp" ++#include "runtime/arguments.hpp" ++#include "runtime/globals.hpp" ++#include "runtime/vmThread.hpp" ++#include "utilities/align.hpp" ++#include "utilities/numberSeq.hpp" ++ ++///////////////////////////////////////////////////// ++// ++// The compact hash table writer implementations ++// ++CompactHashtableWriter::CompactHashtableWriter(int num_entries, ++ CompactHashtableStats* stats) { ++ Arguments::assert_is_dumping_archive(); ++ assert(num_entries >= 0, "sanity"); ++ _num_buckets = calculate_num_buckets(num_entries); ++ assert(_num_buckets > 0, "no buckets"); ++ ++ _num_entries_written = 0; ++ _buckets = NEW_C_HEAP_ARRAY(GrowableArray*, _num_buckets, mtSymbol); ++ for (int i = 0; i < _num_buckets; i++) { ++ _buckets[i] = new (ResourceObj::C_HEAP, mtSymbol) GrowableArray(0, true, mtSymbol); ++ } ++ ++ _stats = stats; ++ _compact_buckets = NULL; ++ _compact_entries = NULL; ++ _num_empty_buckets = 0; ++ _num_value_only_buckets = 0; ++ _num_other_buckets = 0; ++} ++ ++CompactHashtableWriter::~CompactHashtableWriter() { ++ for (int index = 0; index < _num_buckets; index++) { ++ GrowableArray* bucket = _buckets[index]; ++ delete bucket; ++ } ++ ++ FREE_C_HEAP_ARRAY(GrowableArray*, _buckets, mtSymbol); ++} ++ ++size_t CompactHashtableWriter::estimate_size(int num_entries) { ++ int num_buckets = calculate_num_buckets(num_entries); ++ size_t bucket_bytes = ArchiveBuilder::ro_array_bytesize(num_buckets + 1); ++ ++ // In worst case, we have no VALUE_ONLY_BUCKET_TYPE, so each entry takes 2 slots ++ int entries_space = 2 * num_entries; ++ size_t entry_bytes = ArchiveBuilder::ro_array_bytesize(entries_space); ++ ++ return bucket_bytes ++ + entry_bytes ++ + SimpleCompactHashtable::calculate_header_size(); ++} ++ ++// Add a symbol entry to the temporary hash table ++void CompactHashtableWriter::add(unsigned int hash, u4 value) { ++ int index = hash % _num_buckets; ++ _buckets[index]->append_if_missing(Entry(hash, value)); ++ _num_entries_written++; ++} ++ ++void CompactHashtableWriter::allocate_table() { ++ int entries_space = 0; ++ for (int index = 0; index < _num_buckets; index++) { ++ GrowableArray* bucket = _buckets[index]; ++ int bucket_size = bucket->length(); ++ if (bucket_size == 1) { ++ entries_space++; ++ } else if (bucket_size > 1) { ++ entries_space += 2 * bucket_size; ++ } ++ } ++ ++ if (entries_space & ~BUCKET_OFFSET_MASK) { ++ vm_exit_during_initialization("CompactHashtableWriter::allocate_table: Overflow! " ++ "Too many entries."); ++ } ++ ++ _compact_buckets = ArchiveBuilder::new_ro_array(_num_buckets + 1); ++ _compact_entries = ArchiveBuilder::new_ro_array(entries_space); ++ ++ _stats->bucket_count = _num_buckets; ++ _stats->bucket_bytes = align_up(_compact_buckets->size() * BytesPerWord, ++ KlassAlignmentInBytes); ++ _stats->hashentry_count = _num_entries_written; ++ _stats->hashentry_bytes = align_up(_compact_entries->size() * BytesPerWord, ++ KlassAlignmentInBytes); ++} ++ ++// Write the compact table's buckets ++void CompactHashtableWriter::dump_table(NumberSeq* summary) { ++ u4 offset = 0; ++ for (int index = 0; index < _num_buckets; index++) { ++ GrowableArray* bucket = _buckets[index]; ++ int bucket_size = bucket->length(); ++ if (bucket_size == 1) { ++ // bucket with one entry is compacted and only has the symbol offset ++ _compact_buckets->at_put(index, BUCKET_INFO(offset, VALUE_ONLY_BUCKET_TYPE)); ++ ++ Entry ent = bucket->at(0); ++ _compact_entries->at_put(offset++, ent.value()); ++ _num_value_only_buckets++; ++ } else { ++ // regular bucket, each entry is a symbol (hash, offset) pair ++ _compact_buckets->at_put(index, BUCKET_INFO(offset, REGULAR_BUCKET_TYPE)); ++ ++ for (int i=0; iat(i); ++ _compact_entries->at_put(offset++, u4(ent.hash())); // write entry hash ++ _compact_entries->at_put(offset++, ent.value()); ++ } ++ if (bucket_size == 0) { ++ _num_empty_buckets++; ++ } else { ++ _num_other_buckets++; ++ } ++ } ++ summary->add(bucket_size); ++ } ++ ++ // Mark the end of the buckets ++ _compact_buckets->at_put(_num_buckets, BUCKET_INFO(offset, TABLEEND_BUCKET_TYPE)); ++ assert(offset == (u4)_compact_entries->length(), "sanity"); ++} ++ ++// Write the compact table ++void CompactHashtableWriter::dump(SimpleCompactHashtable *cht, const char* table_name) { ++ NumberSeq summary; ++ allocate_table(); ++ dump_table(&summary); ++ ++ int table_bytes = _stats->bucket_bytes + _stats->hashentry_bytes; ++ address base_address = address(SharedBaseAddress); ++ cht->init(base_address, _num_entries_written, _num_buckets, ++ _compact_buckets->data(), _compact_entries->data()); ++ ++ if (InfoDynamicCDS) { ++ double avg_cost = 0.0; ++ if (_num_entries_written > 0) { ++ avg_cost = double(table_bytes)/double(_num_entries_written); ++ } ++ dynamic_cds_log->print_cr("Shared %s table stats -------- base: " PTR_FORMAT, ++ table_name, (intptr_t)base_address); ++ dynamic_cds_log->print_cr("Number of entries : %9d", _num_entries_written); ++ dynamic_cds_log->print_cr("Total bytes used : %9d", table_bytes); ++ dynamic_cds_log->print_cr("Average bytes per entry : %9.3f", avg_cost); ++ dynamic_cds_log->print_cr("Average bucket size : %9.3f", summary.avg()); ++ dynamic_cds_log->print_cr("Variance of bucket size : %9.3f", summary.variance()); ++ dynamic_cds_log->print_cr("Std. dev. of bucket size: %9.3f", summary.sd()); ++ dynamic_cds_log->print_cr("Maximum bucket size : %9d", (int)summary.maximum()); ++ dynamic_cds_log->print_cr("Empty buckets : %9d", _num_empty_buckets); ++ dynamic_cds_log->print_cr("Value_Only buckets : %9d", _num_value_only_buckets); ++ dynamic_cds_log->print_cr("Other buckets : %9d", _num_other_buckets); ++ } ++} ++ ++///////////////////////////////////////////////////////////// ++// ++// The CompactHashtable implementation ++// ++ ++void SimpleCompactHashtable::init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries) { ++ _bucket_count = bucket_count; ++ _entry_count = entry_count; ++ _base_address = base_address; ++ _buckets = buckets; ++ _entries = entries; ++} ++ ++size_t SimpleCompactHashtable::calculate_header_size() { ++ // We have 5 fields. Each takes up sizeof(intptr_t). See WriteClosure::do_u4 ++ size_t bytes = sizeof(intptr_t) * 5; ++ return bytes; ++} ++ ++void SimpleCompactHashtable::serialize_header(SerializeClosure* soc) { ++ // NOTE: if you change this function, you MUST change the number 5 in ++ // calculate_header_size() accordingly. ++ soc->do_u4(&_entry_count); ++ soc->do_u4(&_bucket_count); ++ soc->do_ptr((void**)&_buckets); ++ soc->do_ptr((void**)&_entries); ++ if (soc->reading()) { ++ _base_address = (address)SharedBaseAddress; ++ } ++} +diff --git a/hotspot/src/share/vm/classfile/compactHashtable.hpp b/hotspot/src/share/vm/classfile/compactHashtable.hpp +new file mode 100644 +index 000000000..727b3ebfb +--- /dev/null ++++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp +@@ -0,0 +1,349 @@ ++/* ++ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP ++#define SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP ++ ++#include "oops/symbol.hpp" ++#include "runtime/globals.hpp" ++#include "utilities/array.hpp" ++#include "utilities/growableArray.hpp" ++#include "utilities/numberSeq.hpp" ++ ++ ++template < ++ typename K, ++ typename V, ++ V (*DECODE)(address base_address, u4 offset), ++ bool (*EQUALS)(V value, K key, int len) ++ > ++class CompactHashtable; ++class NumberSeq; ++class SimpleCompactHashtable; ++ ++// Stats for symbol tables in the CDS archive ++class CompactHashtableStats { ++public: ++ int hashentry_count; ++ int hashentry_bytes; ++ int bucket_count; ++ int bucket_bytes; ++ ++ CompactHashtableStats() : ++ hashentry_count(0), hashentry_bytes(0), ++ bucket_count(0), bucket_bytes(0) {} ++}; ++ ++///////////////////////////////////////////////////////////////////////// ++// ++// The compact hash table writer. Used at dump time for writing out ++// the compact table to the shared archive. ++// ++// At dump time, the CompactHashtableWriter obtains all entries from the ++// symbol/string table and adds them to a new temporary hash table. The hash ++// table size (number of buckets) is calculated using ++// '(num_entries + bucket_size - 1) / bucket_size'. The default bucket ++// size is 4 and can be changed by -XX:SharedSymbolTableBucketSize option. ++// 4 is chosen because it produces smaller sized bucket on average for ++// faster lookup. It also has relatively small number of empty buckets and ++// good distribution of the entries. ++// ++// We use a simple hash function (hash % num_bucket) for the table. ++// The new table is compacted when written out. Please see comments ++// above the CompactHashtable class for the table layout detail. The bucket ++// offsets are written to the archive as part of the compact table. The ++// bucket offset is encoded in the low 30-bit (0-29) and the bucket type ++// (regular or compact) are encoded in bit[31, 30]. For buckets with more ++// than one entry, both hash and entry offset are written to the ++// table. For buckets with only one entry, only the entry offset is written ++// to the table and the buckets are tagged as compact in their type bits. ++// Buckets without entry are skipped from the table. Their offsets are ++// still written out for faster lookup. ++// ++class CompactHashtableWriter: public StackObj { ++public: ++ class Entry { ++ unsigned int _hash; ++ u4 _value; ++ ++ public: ++ Entry() {} ++ Entry(unsigned int hash, u4 val) : _hash(hash), _value(val) {} ++ ++ u4 value() { ++ return _value; ++ } ++ unsigned int hash() { ++ return _hash; ++ } ++ ++ bool operator==(const CompactHashtableWriter::Entry& other) { ++ return (_value == other._value && _hash == other._hash); ++ } ++ }; // class CompactHashtableWriter::Entry ++ ++private: ++ int _num_entries_written; ++ int _num_buckets; ++ int _num_empty_buckets; ++ int _num_value_only_buckets; ++ int _num_other_buckets; ++ GrowableArray** _buckets; ++ CompactHashtableStats* _stats; ++ Array* _compact_buckets; ++ Array* _compact_entries; ++ ++public: ++ // This is called at dump-time only ++ CompactHashtableWriter(int num_entries, CompactHashtableStats* stats); ++ ~CompactHashtableWriter(); ++ ++ void add(unsigned int hash, u4 value); ++ ++private: ++ void allocate_table(); ++ void dump_table(NumberSeq* summary); ++ ++ static int calculate_num_buckets(int num_entries) { ++ int num_buckets = num_entries / SharedSymbolTableBucketSize; ++ // calculation of num_buckets can result in zero buckets, we need at least one ++ return (num_buckets < 1) ? 1 : num_buckets; ++ } ++ ++public: ++ void dump(SimpleCompactHashtable *cht, const char* table_name); ++ ++ static size_t estimate_size(int num_entries); ++}; ++ ++#define REGULAR_BUCKET_TYPE 0 ++#define VALUE_ONLY_BUCKET_TYPE 1 ++#define TABLEEND_BUCKET_TYPE 3 ++#define BUCKET_OFFSET_MASK 0x3FFFFFFF ++#define BUCKET_OFFSET(info) ((info) & BUCKET_OFFSET_MASK) ++#define BUCKET_TYPE_SHIFT 30 ++#define BUCKET_TYPE(info) (((info) & ~BUCKET_OFFSET_MASK) >> BUCKET_TYPE_SHIFT) ++#define BUCKET_INFO(offset, type) (((type) << BUCKET_TYPE_SHIFT) | ((offset) & BUCKET_OFFSET_MASK)) ++ ++///////////////////////////////////////////////////////////////////////////// ++// ++// CompactHashtable is used to store the CDS archive's symbol/string tables. ++// ++// Because these tables are read-only (no entries can be added/deleted) at run-time ++// and tend to have large number of entries, we try to minimize the footprint ++// cost per entry. ++// ++// The CompactHashtable is split into two arrays ++// ++// u4 buckets[num_buckets+1]; // bit[31,30]: type; bit[29-0]: offset ++// u4 entries[] ++// ++// The size of buckets[] is 'num_buckets + 1'. Each entry of ++// buckets[] is a 32-bit encoding of the bucket type and bucket offset, ++// with the type in the left-most 2-bit and offset in the remaining 30-bit. ++// The last entry is a special type. It contains the end of the last ++// bucket. ++// ++// There are two types of buckets, regular buckets and value_only buckets. The ++// value_only buckets have '01' in their highest 2-bit, and regular buckets have ++// '00' in their highest 2-bit. ++// ++// For normal buckets, each entry is 8 bytes in the entries[]: ++// u4 hash; /* symbol/string hash */ ++// union { ++// u4 offset; /* Symbol* sym = (Symbol*)(base_address + offset) */ ++// narrowOop str; /* String narrowOop encoding */ ++// } ++// ++// ++// For value_only buckets, each entry has only the 4-byte 'offset' in the entries[]. ++// ++// Example -- note that the second bucket is a VALUE_ONLY_BUCKET_TYPE so the hash code ++// is skipped. ++// buckets[0, 4, 5, ....] ++// | | | ++// | | +---+ ++// | | | ++// | +----+ | ++// v v v ++// entries[H,O,H,O,O,H,O,H,O.....] ++// ++// See CompactHashtable::lookup() for how the table is searched at runtime. ++// See CompactHashtableWriter::dump() for how the table is written at CDS ++// dump time. ++// ++class SimpleCompactHashtable { ++protected: ++ address _base_address; ++ u4 _bucket_count; ++ u4 _entry_count; ++ u4* _buckets; ++ u4* _entries; ++ ++public: ++ SimpleCompactHashtable() { ++ _entry_count = 0; ++ _bucket_count = 0; ++ _buckets = 0; ++ _entries = 0; ++ } ++ ++ void reset() { ++ _bucket_count = 0; ++ _entry_count = 0; ++ _buckets = 0; ++ _entries = 0; ++ } ++ ++ void init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries); ++ ++ // Read/Write the table's header from/to the CDS archive ++ void serialize_header(SerializeClosure* soc) NOT_CDS_RETURN; ++ ++ inline bool empty() const { ++ return (_entry_count == 0); ++ } ++ ++ inline size_t entry_count() const { ++ return _entry_count; ++ } ++ ++ static size_t calculate_header_size(); ++}; ++ ++template < ++ typename K, ++ typename V, ++ V (*DECODE)(address base_address, u4 offset), ++ bool (*EQUALS)(V value, K key, int len) ++ > ++class CompactHashtable : public SimpleCompactHashtable { ++ friend class VMStructs; ++ ++ V decode(u4 offset) const { ++ return DECODE(_base_address, offset); ++ } ++ ++public: ++ // Lookup a value V from the compact table using key K ++ inline V lookup(K key, unsigned int hash, int len) const { ++ if (_entry_count > 0) { ++ int index = hash % _bucket_count; ++ u4 bucket_info = _buckets[index]; ++ u4 bucket_offset = BUCKET_OFFSET(bucket_info); ++ int bucket_type = BUCKET_TYPE(bucket_info); ++ u4* entry = _entries + bucket_offset; ++ ++ if (bucket_type == VALUE_ONLY_BUCKET_TYPE) { ++ V value = decode(entry[0]); ++ if (EQUALS(value, key, len)) { ++ return value; ++ } ++ } else { ++ // This is a regular bucket, which has more than one ++ // entries. Each entry is a pair of entry (hash, offset). ++ // Seek until the end of the bucket. ++ u4* entry_max = _entries + BUCKET_OFFSET(_buckets[index + 1]); ++ while (entry < entry_max) { ++ unsigned int h = (unsigned int)(entry[0]); ++ if (h == hash) { ++ V value = decode(entry[1]); ++ if (EQUALS(value, key, len)) { ++ return value; ++ } ++ } ++ entry += 2; ++ } ++ } ++ } ++ return NULL; ++ } ++ ++ template ++ inline void iterate(ITER* iter) const { ++ for (u4 i = 0; i < _bucket_count; i++) { ++ u4 bucket_info = _buckets[i]; ++ u4 bucket_offset = BUCKET_OFFSET(bucket_info); ++ int bucket_type = BUCKET_TYPE(bucket_info); ++ u4* entry = _entries + bucket_offset; ++ ++ if (bucket_type == VALUE_ONLY_BUCKET_TYPE) { ++ iter->do_value(decode(entry[0])); ++ } else { ++ u4*entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]); ++ while (entry < entry_max) { ++ iter->do_value(decode(entry[1])); ++ entry += 2; ++ } ++ } ++ } ++ } ++ ++ void print_table_statistics(outputStream* st, const char* name) { ++ st->print_cr("%s statistics:", name); ++ int total_entries = 0; ++ int max_bucket = 0; ++ for (u4 i = 0; i < _bucket_count; i++) { ++ u4 bucket_info = _buckets[i]; ++ int bucket_type = BUCKET_TYPE(bucket_info); ++ int bucket_size; ++ ++ if (bucket_type == VALUE_ONLY_BUCKET_TYPE) { ++ bucket_size = 1; ++ } else { ++ bucket_size = (BUCKET_OFFSET(_buckets[i + 1]) - BUCKET_OFFSET(bucket_info)) / 2; ++ } ++ total_entries += bucket_size; ++ if (max_bucket < bucket_size) { ++ max_bucket = bucket_size; ++ } ++ } ++ st->print_cr("Number of buckets : %9d", _bucket_count); ++ st->print_cr("Number of entries : %9d", total_entries); ++ st->print_cr("Maximum bucket size : %9d", max_bucket); ++ } ++}; ++ ++//////////////////////////////////////////////////////////////////////// ++// ++// OffsetCompactHashtable -- This is used to store many types of objects ++// in the CDS archive. On 64-bit platforms, we save space by using a 32-bit ++// offset from the CDS base address. ++ ++template ++inline V read_value_from_compact_hashtable(address base_address, u4 offset) { ++ return (V)(base_address + offset); ++} ++ ++template < ++ typename K, ++ typename V, ++ bool (*EQUALS)(V value, K key, int len) ++ > ++class OffsetCompactHashtable : public CompactHashtable< ++ K, V, read_value_from_compact_hashtable, EQUALS> { ++}; ++ ++#endif // SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP +diff --git a/hotspot/src/share/vm/classfile/sharedClassUtil.hpp b/hotspot/src/share/vm/classfile/sharedClassUtil.hpp +index 13be2b1b5..b24e84d45 100644 +--- a/hotspot/src/share/vm/classfile/sharedClassUtil.hpp ++++ b/hotspot/src/share/vm/classfile/sharedClassUtil.hpp +@@ -43,6 +43,10 @@ public: + return new FileMapInfo::FileMapHeader(); + } + ++ static FileMapInfo::DynamicArchiveHeader* allocate_dynamic_archive_header() { ++ return new FileMapInfo::DynamicArchiveHeader(); ++ } ++ + static size_t file_map_header_size() { + return sizeof(FileMapInfo::FileMapHeader); + } +diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp +index 8dd4e6b21..6a2d8077f 100644 +--- a/hotspot/src/share/vm/classfile/symbolTable.cpp ++++ b/hotspot/src/share/vm/classfile/symbolTable.cpp +@@ -23,6 +23,8 @@ + */ + + #include "precompiled.hpp" ++#include "cds/archiveBuilder.hpp" ++#include "cds/dynamicArchive.hpp" + #include "classfile/altHashing.hpp" + #include "classfile/javaClasses.hpp" + #include "classfile/symbolTable.hpp" +@@ -42,6 +44,19 @@ + + PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC + ++inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key, int len) { ++ if (value->equals(key, len)) { ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++static OffsetCompactHashtable< ++ const char*, Symbol*, ++ symbol_equals_compact_hashtable_entry ++> _dynamic_shared_table; ++ + // -------------------------------------------------------------------------- + + // the number of buckets a thread claims +@@ -95,6 +110,7 @@ void SymbolTable::symbols_do(SymbolClosure *cl) { + int SymbolTable::_symbols_removed = 0; + int SymbolTable::_symbols_counted = 0; + volatile int SymbolTable::_parallel_claimed_idx = 0; ++volatile bool _lookup_shared_first = false; + + void SymbolTable::buckets_unlink(int start_idx, int end_idx, BucketUnlinkContext* context, size_t* memory_total) { + for (int i = start_idx; i < end_idx; ++i) { +@@ -225,10 +241,25 @@ Symbol* SymbolTable::lookup(int index, const char* name, + unsigned int SymbolTable::hash_symbol(const char* s, int len) { + return use_alternate_hashcode() ? + AltHashing::halfsiphash_32(seed(), (const uint8_t*)s, len) : +- java_lang_String::hash_code(s, len); ++ java_lang_String::hash_code((const jbyte*)s, len); + } + ++#if INCLUDE_CDS ++Symbol* SymbolTable::lookup_shared(const char* name, ++ int len, unsigned int hash) { ++ Symbol* sym = NULL; ++ if (DynamicArchive::is_mapped()) { ++ if (use_alternate_hashcode()) { ++ // hash_code parameter may use alternate hashing algorithm but the shared table ++ // always uses the same original hash code. ++ hash = java_lang_String::hash_code((const jbyte*)name, len); ++ } + ++ sym = _dynamic_shared_table.lookup(name, hash, len); ++ } ++ return sym; ++} ++#endif + // We take care not to be blocking while holding the + // SymbolTable_lock. Otherwise, the system might deadlock, since the + // symboltable is used during compilation (VM_thread) The lock free +@@ -236,12 +267,32 @@ unsigned int SymbolTable::hash_symbol(const char* s, int len) { + // entries in the symbol table during normal execution (only during + // safepoints). + +-Symbol* SymbolTable::lookup(const char* name, int len, TRAPS) { ++Symbol* SymbolTable::lookup_common(const char* name, int len) { + unsigned int hashValue = hash_symbol(name, len); + int index = the_table()->hash_to_index(hashValue); ++ Symbol* s; ++ if (_lookup_shared_first) { ++ s = lookup_shared(name, len, hashValue); ++ if (s == NULL) { ++ _lookup_shared_first = false; ++ s = the_table()->lookup(index, name, len, hashValue); ++ } ++ } else { ++ s = the_table()->lookup(index, name, len, hashValue); ++ if (s == NULL) { ++ s = lookup_shared(name, len, hashValue); ++ if (s!= NULL) { ++ _lookup_shared_first = true; ++ } ++ } ++ } ++ return s; ++} + +- Symbol* s = the_table()->lookup(index, name, len, hashValue); +- ++Symbol* SymbolTable::lookup(const char* name, int len, TRAPS) { ++ unsigned int hashValue = hash_symbol(name, len); ++ int index = the_table()->hash_to_index(hashValue); ++ Symbol* s = lookup_common(name, len); + // Found + if (s != NULL) return s; + +@@ -264,8 +315,7 @@ Symbol* SymbolTable::lookup(const Symbol* sym, int begin, int end, TRAPS) { + len = end - begin; + hashValue = hash_symbol(name, len); + index = the_table()->hash_to_index(hashValue); +- Symbol* s = the_table()->lookup(index, name, len, hashValue); +- ++ Symbol* s = lookup_common(name, len); + // Found + if (s != NULL) return s; + } +@@ -294,9 +344,7 @@ Symbol* SymbolTable::lookup(const Symbol* sym, int begin, int end, TRAPS) { + Symbol* SymbolTable::lookup_only(const char* name, int len, + unsigned int& hash) { + hash = hash_symbol(name, len); +- int index = the_table()->hash_to_index(hash); +- +- Symbol* s = the_table()->lookup(index, name, len, hash); ++ Symbol* s = lookup_common(name, len); + return s; + } + +@@ -501,6 +549,42 @@ void SymbolTable::dump(outputStream* st) { + the_table()->dump_table(st, "SymbolTable"); + } + ++static uintx hash_shared_symbol(const char* s, int len) { ++ return java_lang_String::hash_code((const jbyte*)s, len); ++} ++ ++void SymbolTable::copy_shared_symbol_table(GrowableArray* symbols, ++ CompactHashtableWriter* writer) { ++ ArchiveBuilder* builder = ArchiveBuilder::current(); ++ int len = symbols->length(); ++ for (int i = 0; i < len; i++) { ++ Symbol* sym = ArchiveBuilder::get_relocated_symbol(symbols->at(i)); ++ unsigned int fixed_hash = hash_shared_symbol((const char*)sym->bytes(), sym->utf8_length()); ++ assert(fixed_hash == hash_symbol((const char*)sym->bytes(), sym->utf8_length()), ++ "must not rehash during dumping"); ++ sym->set_permanent(); ++ writer->add(fixed_hash, builder->buffer_to_offset_u4((address)sym)); ++ } ++} ++ ++size_t SymbolTable::estimate_size_for_archive() { ++ return CompactHashtableWriter::estimate_size(the_table()->number_of_entries()); ++} ++ ++void SymbolTable::write_to_archive(GrowableArray* symbols) { ++ CompactHashtableWriter writer(symbols->length(), ArchiveBuilder::symbol_stats()); ++ copy_shared_symbol_table(symbols, &writer); ++ _dynamic_shared_table.reset(); ++ writer.dump(&_dynamic_shared_table, "symbol"); ++} ++ ++void SymbolTable::serialize_shared_table_header(SerializeClosure* soc) { ++ _dynamic_shared_table.serialize_header(soc); ++ if (soc->writing()) { ++ // Sanity. Make sure we don't use the shared table at dump time ++ _dynamic_shared_table.reset(); ++ } ++} + + //--------------------------------------------------------------------------- + // Non-product code +diff --git a/hotspot/src/share/vm/classfile/symbolTable.hpp b/hotspot/src/share/vm/classfile/symbolTable.hpp +index 58fd22343..96eb173d1 100644 +--- a/hotspot/src/share/vm/classfile/symbolTable.hpp ++++ b/hotspot/src/share/vm/classfile/symbolTable.hpp +@@ -25,6 +25,7 @@ + #ifndef SHARE_VM_CLASSFILE_SYMBOLTABLE_HPP + #define SHARE_VM_CLASSFILE_SYMBOLTABLE_HPP + ++#include "classfile/compactHashtable.hpp" + #include "memory/allocation.inline.hpp" + #include "oops/symbol.hpp" + #include "utilities/hashtable.hpp" +@@ -107,6 +108,10 @@ private: + add(loader_data, cp, names_count, name, lengths, cp_indices, hashValues, THREAD); + } + ++ static Symbol* lookup_shared(const char* name, int len, unsigned int hash) NOT_CDS_RETURN_(NULL); ++ ++ static Symbol* lookup_common(const char* name, int len); ++ + Symbol* lookup(int index, const char* name, int len, unsigned int hash); + + SymbolTable() +@@ -237,6 +242,10 @@ public: + static void dump(outputStream* st); + + // Sharing ++private: ++ static void copy_shared_symbol_table(GrowableArray* symbols, ++ CompactHashtableWriter* ch_table); ++public: + static void copy_buckets(char** top, char*end) { + the_table()->Hashtable::copy_buckets(top, end); + } +@@ -246,6 +255,9 @@ public: + static void reverse(void* boundary = NULL) { + the_table()->Hashtable::reverse(boundary); + } ++ static size_t estimate_size_for_archive(); ++ static void write_to_archive(GrowableArray* symbols); ++ static void serialize_shared_table_header(SerializeClosure* soc); + + // Rehash the symbol table if it gets out of balance + static void rehash_table(); +diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp +index 0d937c3ba..0ea2d9b79 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp ++++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp +@@ -31,6 +31,7 @@ + #include "classfile/resolutionErrors.hpp" + #include "classfile/systemDictionary.hpp" + #if INCLUDE_CDS ++#include "cds/dynamicArchive.hpp" + #include "classfile/sharedClassUtil.hpp" + #include "classfile/systemDictionaryShared.hpp" + #endif +@@ -185,6 +186,11 @@ bool SystemDictionary::is_app_class_loader(Handle class_loader) { + return (class_loader->klass()->name() == vmSymbols::sun_misc_Launcher_AppClassLoader()); + } + ++bool SystemDictionary::is_builtin_loader(Handle class_loader) { ++ return class_loader.is_null() || ++ class_loader->klass()->name() == vmSymbols::sun_misc_Launcher_AppClassLoader() || ++ class_loader->klass()->name() == vmSymbols::sun_misc_Launcher_ExtClassLoader(); ++} + // ---------------------------------------------------------------------------- + // Resolving of classes + +@@ -1131,76 +1137,92 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name, + check_loader_lock_contention(lockObject, THREAD); + ObjectLocker ol(lockObject, THREAD, DoObjectLock); + ++ instanceKlassHandle k; + TempNewSymbol parsed_name = NULL; + +- // Parse the stream. Note that we do this even though this klass might +- // already be present in the SystemDictionary, otherwise we would not +- // throw potential ClassFormatErrors. +- // +- // Note: "name" is updated. ++#if INCLUDE_CDS ++ if (DynamicArchive::is_mapped()) { ++ k = SystemDictionaryShared::lookup_from_stream(class_name, ++ class_loader, ++ protection_domain, ++ st, ++ CHECK_NULL); ++ } ++#endif + +- // Callers are expected to declare a ResourceMark to determine +- // the lifetime of any updated (resource) allocated under +- // this call to parseClassFile +- ResourceMark rm(THREAD); +- ClassFileParser parser(st); +- instanceKlassHandle k = parser.parseClassFile(class_name, +- loader_data, +- protection_domain, +- parsed_name, +- verify, +- THREAD); +- +- const char* pkg = "java/"; +- size_t pkglen = strlen(pkg); +- if (!HAS_PENDING_EXCEPTION && +- !class_loader.is_null() && +- parsed_name != NULL && +- parsed_name->utf8_length() >= (int)pkglen) { +- ResourceMark rm(THREAD); +- bool prohibited; +- const jbyte* base = parsed_name->base(); +- if ((base[0] | base[1] | base[2] | base[3] | base[4]) & 0x80) { +- prohibited = is_prohibited_package_slow(parsed_name); +- } else { +- char* name = parsed_name->as_C_string(); +- prohibited = (strncmp(name, pkg, pkglen) == 0); +- } +- if (prohibited) { +- // It is illegal to define classes in the "java." package from +- // JVM_DefineClass or jni_DefineClass unless you're the bootclassloader +- char* name = parsed_name->as_C_string(); +- char* index = strrchr(name, '/'); +- assert(index != NULL, "must be"); +- *index = '\0'; // chop to just the package name +- while ((index = strchr(name, '/')) != NULL) { +- *index = '.'; // replace '/' with '.' in package name ++ if (k() != NULL) { ++ parsed_name = k->name(); ++ } else { ++ // Parse the stream. Note that we do this even though this klass might ++ // already be present in the SystemDictionary, otherwise we would not ++ // throw potential ClassFormatErrors. ++ // ++ // Note: "name" is updated. ++ ++ // Callers are expected to declare a ResourceMark to determine ++ // the lifetime of any updated (resource) allocated under ++ // this call to parseClassFile ++ ResourceMark rm(THREAD); ++ ClassFileParser parser(st); ++ k = parser.parseClassFile(class_name, ++ loader_data, ++ protection_domain, ++ parsed_name, ++ verify, ++ THREAD); ++ const char* pkg = "java/"; ++ size_t pkglen = strlen(pkg); ++ if (!HAS_PENDING_EXCEPTION && ++ !class_loader.is_null() && ++ parsed_name != NULL && ++ parsed_name->utf8_length() >= (int)pkglen) { ++ ResourceMark rm(THREAD); ++ bool prohibited; ++ const jbyte* base = parsed_name->base(); ++ if ((base[0] | base[1] | base[2] | base[3] | base[4]) & 0x80) { ++ prohibited = is_prohibited_package_slow(parsed_name); ++ } else { ++ char* name = parsed_name->as_C_string(); ++ prohibited = (strncmp(name, pkg, pkglen) == 0); + } +- const char* fmt = "Prohibited package name: %s"; +- size_t len = strlen(fmt) + strlen(name); +- char* message = NEW_RESOURCE_ARRAY(char, len); +- jio_snprintf(message, len, fmt, name); +- Exceptions::_throw_msg(THREAD_AND_LOCATION, +- vmSymbols::java_lang_SecurityException(), message); +- } +- } ++ if (prohibited) { ++ // It is illegal to define classes in the "java." package from ++ // JVM_DefineClass or jni_DefineClass unless you're the bootclassloader ++ char* name = parsed_name->as_C_string(); ++ char* index = strrchr(name, '/'); ++ assert(index != NULL, "must be"); ++ *index = '\0'; // chop to just the package name ++ while ((index = strchr(name, '/')) != NULL) { ++ *index = '.'; // replace '/' with '.' in package name ++ } ++ const char* fmt = "Prohibited package name: %s"; ++ size_t len = strlen(fmt) + strlen(name); ++ char* message = NEW_RESOURCE_ARRAY(char, len); ++ jio_snprintf(message, len, fmt, name); ++ Exceptions::_throw_msg(THREAD_AND_LOCATION, ++ vmSymbols::java_lang_SecurityException(), message); ++ } ++ } + +- if (!HAS_PENDING_EXCEPTION) { +- assert(parsed_name != NULL, "Sanity"); +- assert(class_name == NULL || class_name == parsed_name, "name mismatch"); +- // Verification prevents us from creating names with dots in them, this +- // asserts that that's the case. +- assert(is_internal_format(parsed_name), +- "external class name format used internally"); ++ if (!HAS_PENDING_EXCEPTION) { ++ assert(parsed_name != NULL, "Sanity"); ++ assert(class_name == NULL || class_name == parsed_name, "name mismatch"); ++ // Verification prevents us from creating names with dots in them, this ++ // asserts that that's the case. ++ assert(is_internal_format(parsed_name), ++ "external class name format used internally"); + + #if INCLUDE_JFR +- { +- InstanceKlass* ik = k(); +- ON_KLASS_CREATION(ik, parser, THREAD); +- k = instanceKlassHandle(ik); +- } ++ { ++ InstanceKlass* ik = k(); ++ ON_KLASS_CREATION(ik, parser, THREAD); ++ k = instanceKlassHandle(ik); ++ } + #endif ++ } ++ } + ++ if (!HAS_PENDING_EXCEPTION) { + // Add class just loaded + // If a class loader supports parallel classloading handle parallel define requests + // find_or_define_instance_class may return a different InstanceKlass +@@ -1274,14 +1296,19 @@ Klass* SystemDictionary::find_shared_class(Symbol* class_name) { + + instanceKlassHandle SystemDictionary::load_shared_class( + Symbol* class_name, Handle class_loader, TRAPS) { +- if (!(class_loader.is_null() || SystemDictionary::is_app_class_loader(class_loader) || ++ if (!(class_loader.is_null() || SystemDictionary::is_app_class_loader(class_loader) || + SystemDictionary::is_ext_class_loader(class_loader))) { + return instanceKlassHandle(); + } + +- instanceKlassHandle ik (THREAD, find_shared_class(class_name)); // InstanceKlass is find with null class loader. ++ Klass* klass = SystemDictionaryShared::find_dynamic_builtin_class(class_name); ++ if (klass == NULL) { ++ klass = find_shared_class(class_name); ++ } ++ ++ instanceKlassHandle ik (THREAD, klass); // InstanceKlass is find with null class loader. + if (ik.not_null()) { +- if (!UseAppCDS) { ++ if (!(UseAppCDS || DynamicArchive::is_mapped())) { + // CDS logic + if (SharedClassUtil::is_shared_boot_class(ik()) && class_loader.is_null()) { + // CDS record boot class load index. +@@ -1289,7 +1316,7 @@ instanceKlassHandle SystemDictionary::load_shared_class( + return load_shared_class(ik, class_loader, protection_domain, THREAD); + } + } else { +- // AppCDS logic. Only use null loader only to load classes that ++ // AppCDS and dynamic CDS logic. Only use null loader only to load classes that + // have been dumped by null loader. For non-null class loaders, + // either the class loader data is not initialized (but also not + // null) or the same class loader is used to load previously +@@ -1424,7 +1451,7 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, + true /* shared class */); + + // register package for this class, if necessary +- if (UseAppCDS && class_loader.not_null()) { ++ if (SystemDictionary::is_app_class_loader(class_loader) || SystemDictionary::is_ext_class_loader(class_loader)) { + + ResourceMark rm(THREAD); + char* name = ik->name()->as_C_string(); +diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp +index 3b9be4430..320f71865 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp ++++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp +@@ -652,6 +652,7 @@ public: + TRAPS); + static bool is_ext_class_loader(Handle class_loader); + static bool is_app_class_loader(Handle class_loader); ++ static bool is_builtin_loader(Handle class_loader); + + protected: + static Klass* find_shared_class(Symbol* class_name); +diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp +new file mode 100644 +index 000000000..99354cd4b +--- /dev/null ++++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp +@@ -0,0 +1,911 @@ ++/* ++ * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "cds/archiveBuilder.hpp" ++#include "cds/dynamicArchive.hpp" ++#include "classfile/systemDictionaryShared.hpp" ++#include "classfile/classLoaderData.inline.hpp" ++#include "runtime/arguments.hpp" ++#include "runtime/mutexLocker.hpp" ++#include "memory/metaspaceShared.hpp" ++#include "memory/metaspaceClosure.hpp" ++#include "utilities/resourceHash.hpp" ++#include "runtime/mutexLocker.hpp" ++#include "utilities/ostream.hpp" ++ ++DEBUG_ONLY(bool SystemDictionaryShared::_no_class_loading_should_happen = false;) ++bool SystemDictionaryShared::_dump_in_progress = false; ++ ++class DumpTimeSharedClassInfo: public CHeapObj { ++ bool _excluded; ++ bool _has_checked_exclusion; ++public: ++ struct DTLoaderConstraint { ++ Symbol* _name; ++ char _loader_type1; ++ char _loader_type2; ++ DTLoaderConstraint(Symbol* name, char l1, char l2) : _name(name), _loader_type1(l1), _loader_type2(l2) { ++ _name->increment_refcount(); ++ } ++ DTLoaderConstraint() : _name(NULL), _loader_type1('0'), _loader_type2('0') {} ++ bool equals(const DTLoaderConstraint& t) { ++ return t._name == _name && ++ ((t._loader_type1 == _loader_type1 && t._loader_type2 == _loader_type2) || ++ (t._loader_type2 == _loader_type1 && t._loader_type1 == _loader_type2)); ++ } ++ }; ++ ++ struct DTVerifierConstraint { ++ Symbol* _name; ++ Symbol* _from_name; ++ DTVerifierConstraint() : _name(NULL), _from_name(NULL) {} ++ DTVerifierConstraint(Symbol* n, Symbol* fn) : _name(n), _from_name(fn) { ++ _name->increment_refcount(); ++ _from_name->increment_refcount(); ++ } ++ }; ++ ++ InstanceKlass* _klass; ++ InstanceKlass* _nest_host; ++ bool _failed_verification; ++ bool _is_archived_lambda_proxy; ++ int _id; ++ int _clsfile_size; ++ int _clsfile_crc32; ++ GrowableArray* _verifier_constraints; ++ GrowableArray* _verifier_constraint_flags; ++ GrowableArray* _loader_constraints; ++ ++ DumpTimeSharedClassInfo() { ++ _klass = NULL; ++ _nest_host = NULL; ++ _failed_verification = false; ++ _is_archived_lambda_proxy = false; ++ _has_checked_exclusion = false; ++ _id = -1; ++ _clsfile_size = -1; ++ _clsfile_crc32 = -1; ++ _excluded = false; ++ _verifier_constraints = NULL; ++ _verifier_constraint_flags = NULL; ++ _loader_constraints = NULL; ++ } ++ ++ void add_verification_constraint(InstanceKlass* k, Symbol* name, ++ Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object); ++ void record_linking_constraint(Symbol* name, Handle loader1, Handle loader2); ++ ++ bool is_builtin() { ++ return SystemDictionaryShared::is_builtin(_klass); ++ } ++ ++ int num_verifier_constraints() { ++ if (_verifier_constraint_flags != NULL) { ++ return _verifier_constraint_flags->length(); ++ } else { ++ return 0; ++ } ++ } ++ ++ int num_loader_constraints() { ++ if (_loader_constraints != NULL) { ++ return _loader_constraints->length(); ++ } else { ++ return 0; ++ } ++ } ++ ++ void metaspace_pointers_do(MetaspaceClosure* it) { ++ it->push(&_klass); ++ it->push(&_nest_host); ++ if (_verifier_constraints != NULL) { ++ for (int i = 0; i < _verifier_constraints->length(); i++) { ++ DTVerifierConstraint* cons = _verifier_constraints->adr_at(i); ++ it->push(&cons->_name); ++ it->push(&cons->_from_name); ++ } ++ } ++ if (_loader_constraints != NULL) { ++ for (int i = 0; i < _loader_constraints->length(); i++) { ++ DTLoaderConstraint* lc = _loader_constraints->adr_at(i); ++ it->push(&lc->_name); ++ } ++ } ++ } ++ ++ bool is_excluded() { ++ // _klass may become NULL due to DynamicArchiveBuilder::set_to_null ++ return _excluded || _failed_verification || _klass == NULL; ++ } ++ ++ // simple accessors ++ void set_excluded() { _excluded = true; } ++ bool has_checked_exclusion() const { return _has_checked_exclusion; } ++ void set_has_checked_exclusion() { _has_checked_exclusion = true; } ++ bool failed_verification() const { return _failed_verification; } ++ void set_failed_verification() { _failed_verification = true; } ++ InstanceKlass* nest_host() const { return _nest_host; } ++ void set_nest_host(InstanceKlass* nest_host) { _nest_host = nest_host; } ++}; ++ ++inline unsigned DumpTimeSharedClassTable_hash(InstanceKlass* const& k) { ++ // Deterministic archive is not possible because classes can be loaded ++ // in multiple threads. ++ return primitive_hash(k); ++} ++ ++class DumpTimeSharedClassTable: public ResourceHashtable< ++ InstanceKlass*, ++ DumpTimeSharedClassInfo, ++ &DumpTimeSharedClassTable_hash, ++ primitive_equals, ++ 15889, // prime number ++ ResourceObj::C_HEAP> ++{ ++ int _builtin_count; ++ int _unregistered_count; ++public: ++ DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k, bool dump_in_progress) { ++ bool created = false; ++ DumpTimeSharedClassInfo* p; ++ if (!dump_in_progress) { ++ p = put_if_absent(k, &created); ++ } else { ++ p = get(k); ++ } ++ if (created) { ++ assert(!SystemDictionaryShared::no_class_loading_should_happen(), ++ "no new classes can be loaded while dumping archive"); ++ p->_klass = k; ++ } else { ++ if (!dump_in_progress) { ++ assert(p->_klass == k, "Sanity"); ++ } ++ } ++ return p; ++ } ++ ++ class CountClassByCategory : StackObj { ++ DumpTimeSharedClassTable* _table; ++ public: ++ CountClassByCategory(DumpTimeSharedClassTable* table) : _table(table) {} ++ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) { ++ if (!info.is_excluded()) { ++ if (info.is_builtin()) { ++ ++ _table->_builtin_count; ++ } else { ++ ++ _table->_unregistered_count; ++ } ++ } ++ return true; // keep on iterating ++ } ++ }; ++ ++ void update_counts() { ++ _builtin_count = 0; ++ _unregistered_count = 0; ++ CountClassByCategory counter(this); ++ iterate(&counter); ++ } ++ ++ int count_of(bool is_builtin) const { ++ if (is_builtin) { ++ return _builtin_count; ++ } else { ++ return _unregistered_count; ++ } ++ } ++}; ++ ++class RunTimeSharedClassInfo { ++public: ++ struct CrcInfo { ++ int _clsfile_size; ++ int _clsfile_crc32; ++ }; ++ ++ // This is different than DumpTimeSharedClassInfo::DTVerifierConstraint. We use ++ // u4 instead of Symbol* to save space on 64-bit CPU. ++ struct RTVerifierConstraint { ++ u4 _name; ++ u4 _from_name; ++ Symbol* name() { return (Symbol*)(SharedBaseAddress + _name);} ++ Symbol* from_name() { return (Symbol*)(SharedBaseAddress + _from_name); } ++ }; ++ ++ struct RTLoaderConstraint { ++ u4 _name; ++ char _loader_type1; ++ char _loader_type2; ++ Symbol* constraint_name() { ++ return (Symbol*)(SharedBaseAddress + _name); ++ } ++ }; ++ ++ InstanceKlass* _klass; ++ int _num_verifier_constraints; ++ int _num_loader_constraints; ++ ++ // optional CrcInfo _crc; (only for UNREGISTERED classes) ++ // optional InstanceKlass* _nest_host ++ // optional RTLoaderConstraint _loader_constraint_types[_num_loader_constraints] ++ // optional RTVerifierConstraint _verifier_constraints[_num_verifier_constraints] ++ // optional char _verifier_constraint_flags[_num_verifier_constraints] ++ ++private: ++ static size_t header_size_size() { ++ return sizeof(RunTimeSharedClassInfo); ++ } ++ static size_t crc_size(InstanceKlass* klass) { ++ if (!SystemDictionaryShared::is_builtin(klass)) { ++ return sizeof(CrcInfo); ++ } else { ++ return 0; ++ } ++ } ++ static size_t verifier_constraints_size(int num_verifier_constraints) { ++ return sizeof(RTVerifierConstraint) * num_verifier_constraints; ++ } ++ static size_t verifier_constraint_flags_size(int num_verifier_constraints) { ++ return sizeof(char) * num_verifier_constraints; ++ } ++ static size_t loader_constraints_size(int num_loader_constraints) { ++ return sizeof(RTLoaderConstraint) * num_loader_constraints; ++ } ++ static size_t nest_host_size(InstanceKlass* klass) { ++ assert(!klass->is_anonymous(), "klass should not be hidden right now."); ++ if (klass->is_anonymous()) { ++ return sizeof(InstanceKlass*); ++ } else { ++ return 0; ++ } ++ } ++ ++public: ++ static size_t byte_size(InstanceKlass* klass, int num_verifier_constraints, int num_loader_constraints) { ++ return header_size_size() + ++ crc_size(klass) + ++ nest_host_size(klass) + ++ loader_constraints_size(num_loader_constraints) + ++ verifier_constraints_size(num_verifier_constraints) + ++ verifier_constraint_flags_size(num_verifier_constraints); ++ } ++ ++private: ++ size_t crc_offset() const { ++ return header_size_size(); ++ } ++ ++ size_t nest_host_offset() const { ++ return crc_offset() + crc_size(_klass); ++ } ++ ++ size_t loader_constraints_offset() const { ++ return nest_host_offset() + nest_host_size(_klass); ++ } ++ size_t verifier_constraints_offset() const { ++ return loader_constraints_offset() + loader_constraints_size(_num_loader_constraints); ++ } ++ size_t verifier_constraint_flags_offset() const { ++ return verifier_constraints_offset() + verifier_constraints_size(_num_verifier_constraints); ++ } ++ ++ void check_verifier_constraint_offset(int i) const { ++ assert(0 <= i && i < _num_verifier_constraints, "sanity"); ++ } ++ ++ void check_loader_constraint_offset(int i) const { ++ assert(0 <= i && i < _num_loader_constraints, "sanity"); ++ } ++ ++public: ++ CrcInfo* crc() const { ++ assert(crc_size(_klass) > 0, "must be"); ++ return (CrcInfo*)(address(this) + crc_offset()); ++ } ++ RTVerifierConstraint* verifier_constraints() { ++ assert(_num_verifier_constraints > 0, "sanity"); ++ return (RTVerifierConstraint*)(address(this) + verifier_constraints_offset()); ++ } ++ RTVerifierConstraint* verifier_constraint_at(int i) { ++ check_verifier_constraint_offset(i); ++ return verifier_constraints() + i; ++ } ++ ++ char* verifier_constraint_flags() { ++ assert(_num_verifier_constraints > 0, "sanity"); ++ return (char*)(address(this) + verifier_constraint_flags_offset()); ++ } ++ ++ RTLoaderConstraint* loader_constraints() { ++ assert(_num_loader_constraints > 0, "sanity"); ++ return (RTLoaderConstraint*)(address(this) + loader_constraints_offset()); ++ } ++ ++ RTLoaderConstraint* loader_constraint_at(int i) { ++ check_loader_constraint_offset(i); ++ return loader_constraints() + i; ++ } ++ ++ void init(DumpTimeSharedClassInfo& info) { ++ ArchiveBuilder* builder = ArchiveBuilder::current(); ++ assert(builder->is_in_buffer_space(info._klass), "must be"); ++ _klass = info._klass; ++ if (!SystemDictionaryShared::is_builtin(_klass)) { ++ CrcInfo* c = crc(); ++ c->_clsfile_size = info._clsfile_size; ++ c->_clsfile_crc32 = info._clsfile_crc32; ++ } ++ _num_verifier_constraints = info.num_verifier_constraints(); ++ _num_loader_constraints = info.num_loader_constraints(); ++ int i; ++ if (_num_verifier_constraints > 0) { ++ RTVerifierConstraint* vf_constraints = verifier_constraints(); ++ char* flags = verifier_constraint_flags(); ++ for (i = 0; i < _num_verifier_constraints; i++) { ++ vf_constraints[i]._name = builder->any_to_offset_u4(info._verifier_constraints->at(i)._name); ++ vf_constraints[i]._from_name = builder->any_to_offset_u4(info._verifier_constraints->at(i)._from_name); ++ } ++ for (i = 0; i < _num_verifier_constraints; i++) { ++ flags[i] = info._verifier_constraint_flags->at(i); ++ } ++ } ++ ++ if (_num_loader_constraints > 0) { ++ RTLoaderConstraint* ld_constraints = loader_constraints(); ++ for (i = 0; i < _num_loader_constraints; i++) { ++ ld_constraints[i]._name = builder->any_to_offset_u4(info._loader_constraints->at(i)._name); ++ ld_constraints[i]._loader_type1 = info._loader_constraints->at(i)._loader_type1; ++ ld_constraints[i]._loader_type2 = info._loader_constraints->at(i)._loader_type2; ++ } ++ } ++ ++ ArchivePtrMarker::mark_pointer(&_klass); ++ } ++ ++ bool matches(int clsfile_size, int clsfile_crc32) const { ++ return crc()->_clsfile_size == clsfile_size && ++ crc()->_clsfile_crc32 == clsfile_crc32; ++ } ++ ++ char verifier_constraint_flag(int i) { ++ check_verifier_constraint_offset(i); ++ return verifier_constraint_flags()[i]; ++ } ++ ++private: ++ // ArchiveBuilder::make_shallow_copy() has reserved a pointer immediately ++ // before archived InstanceKlasses. We can use this slot to do a quick ++ // lookup of InstanceKlass* -> RunTimeSharedClassInfo* without ++ // building a new hashtable. ++ // ++ // info_pointer_addr(klass) --> 0x0100 RunTimeSharedClassInfo* ++ // InstanceKlass* klass --> 0x0108 ++ // 0x0110 fields from Klass ... ++ static RunTimeSharedClassInfo** info_pointer_addr(InstanceKlass* klass) { ++ return &((RunTimeSharedClassInfo**)klass)[-1]; ++ } ++ ++public: ++ static RunTimeSharedClassInfo* get_for(InstanceKlass* klass) { ++ assert(klass->is_shared(), "don't call for non-shared class"); ++ return *info_pointer_addr(klass); ++ } ++ static void set_for(InstanceKlass* klass, RunTimeSharedClassInfo* record) { ++ assert(ArchiveBuilder::current()->is_in_buffer_space(klass), "must be"); ++ assert(ArchiveBuilder::current()->is_in_buffer_space(record), "must be"); ++ *info_pointer_addr(klass) = record; ++ ArchivePtrMarker::mark_pointer(info_pointer_addr(klass)); ++ } ++ ++ // Used by RunTimeSharedDictionary to implement OffsetCompactHashtable::EQUALS ++ static inline bool EQUALS( ++ const RunTimeSharedClassInfo* value, Symbol* key, int len_unused) { ++ return (value->_klass->name() == key); ++ } ++}; ++ ++class RunTimeSharedDictionary : public OffsetCompactHashtable< ++ Symbol*, ++ const RunTimeSharedClassInfo*, ++ RunTimeSharedClassInfo::EQUALS> {}; ++ ++static DumpTimeSharedClassTable* _dumptime_table = NULL; ++// SystemDictionaries in the top layer dynamic archive ++static RunTimeSharedDictionary _dynamic_builtin_dictionary; ++static RunTimeSharedDictionary _dynamic_unregistered_dictionary; ++ ++void SystemDictionaryShared::set_class_has_failed_verification(InstanceKlass* ik) { ++ Arguments::assert_is_dumping_archive(); ++ DumpTimeSharedClassInfo* p = find_or_allocate_info_for(ik); ++ if (p != NULL) { ++ p->set_failed_verification(); ++ } ++} ++ ++void SystemDictionaryShared::start_dumping() { ++ MutexLockerEx ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); ++ _dump_in_progress = true; ++} ++ ++void SystemDictionaryShared::init_dumptime_info(InstanceKlass* k) { ++ (void)find_or_allocate_info_for(k); ++} ++ ++void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) { ++ MutexLockerEx ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); ++ DumpTimeSharedClassInfo* p = _dumptime_table->get(k); ++ if (p == NULL) { ++ return; ++ } ++ _dumptime_table->remove(k); ++} ++ ++DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for(InstanceKlass* k) { ++ MutexLockerEx ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); ++ return find_or_allocate_info_for_locked(k); ++} ++ ++DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for_locked(InstanceKlass* k) { ++ assert_lock_strong(DumpTimeTable_lock); ++ if (_dumptime_table == NULL) { ++ _dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable(); ++ } ++ return _dumptime_table->find_or_allocate_info_for(k, _dump_in_progress); ++} ++ ++bool SystemDictionaryShared::empty_dumptime_table() { ++ if (_dumptime_table == NULL) { ++ return true; ++ } ++ _dumptime_table->update_counts(); ++ if (_dumptime_table->count_of(true) == 0 && _dumptime_table->count_of(false) == 0) { ++ return true; ++ } ++ return false; ++} ++ ++class ExcludeDumpTimeSharedClasses : StackObj { ++public: ++ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) { ++ SystemDictionaryShared::check_for_exclusion(k, &info); ++ return true; // keep on iterating ++ } ++}; ++ ++class IterateDumpTimeSharedClassTable : StackObj { ++ MetaspaceClosure *_it; ++public: ++ IterateDumpTimeSharedClassTable(MetaspaceClosure* it) : _it(it) {} ++ ++ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) { ++ assert_lock_strong(DumpTimeTable_lock); ++ if (!info.is_excluded()) { ++ info.metaspace_pointers_do(_it); ++ } ++ return true; // keep on iterating ++ } ++}; ++ ++class IterateDumpTimeTableReplaceKlass : StackObj { ++public: ++ IterateDumpTimeTableReplaceKlass() { } ++ ++ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) { ++ if (k->oop_is_instance() && !info.is_excluded()) { ++ k->constants()->symbol_replace_excluded_klass(); ++ } ++ return true; ++ } ++}; ++ ++void SystemDictionaryShared::check_excluded_classes() { ++ assert(no_class_loading_should_happen(), "sanity"); ++ assert_lock_strong(DumpTimeTable_lock); ++ ExcludeDumpTimeSharedClasses excl; ++ _dumptime_table->iterate(&excl); ++ _dumptime_table->update_counts(); ++} ++ ++bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeSharedClassInfo* info) { ++ if (MetaspaceShared::is_in_shared_space(k)) { ++ // We have reached a super type that's already in the base archive. Treat it ++ // as "not excluded". ++ assert(DynamicDumpSharedSpaces, "must be"); ++ return false; ++ } ++ ++ if (info == NULL) { ++ info = _dumptime_table->get(k); ++ assert(info != NULL, "supertypes of any classes in _dumptime_table must either be shared, or must also be in _dumptime_table"); ++ } ++ ++ if (!info->has_checked_exclusion()) { ++ if (check_for_exclusion_impl(k)) { ++ info->set_excluded(); ++ } ++ info->set_has_checked_exclusion(); ++ } ++ ++ return info->is_excluded(); ++} ++ ++// Check if a class or any of its supertypes has been redefined. ++bool SystemDictionaryShared::has_been_redefined(InstanceKlass* k) { ++ if (k->has_been_redefined()) { ++ return true; ++ } ++ if (k->java_super() != NULL && has_been_redefined(k->java_super())) { ++ return true; ++ } ++ Array* interfaces = k->local_interfaces(); ++ int len = interfaces->length(); ++ for (int i = 0; i < len; i++) { ++ if (has_been_redefined((InstanceKlass*)interfaces->at(i))) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { ++ if (k->is_in_error_state()) { ++ return warn_excluded(k, "In error state"); ++ } ++ if (k->init_state() < InstanceKlass::loaded) { ++ return warn_excluded(k, "not loaded klass"); ++ } ++ if (has_been_redefined(k)) { ++ return warn_excluded(k, "Has been redefined"); ++ } ++ if (k->signers() != NULL) { ++ // We cannot include signed classes in the archive because the certificates ++ // used during dump time may be different than those used during ++ // runtime (due to expiration, etc). ++ return warn_excluded(k, "Signed JAR"); ++ } ++ if (is_jfr_event_class(k)) { ++ // We cannot include JFR event classes because they need runtime-specific ++ // instrumentation in order to work with -XX:FlightRecorderOptions:retransform=false. ++ // There are only a small number of these classes, so it's not worthwhile to ++ // support them and make CDS more complicated. ++ return warn_excluded(k, "JFR event class"); ++ } ++ if (k->init_state() < InstanceKlass::linked) { ++ // In CDS dumping, we will attempt to link all classes. Those that fail to link will ++ // be recorded in DumpTimeSharedClassInfo. ++ Arguments::assert_is_dumping_archive(); ++ ++ // TODO -- rethink how this can be handled. ++ // We should try to link ik, however, we can't do it here because ++ // 1. We are at VM exit ++ // 2. linking a class may cause other classes to be loaded, which means ++ // a custom ClassLoader.loadClass() may be called, at a point where the ++ // class loader doesn't expect it. ++ if (has_class_failed_verification(k)) { ++ return warn_excluded(k, "Failed verification"); ++ } else { ++ if (k->can_be_verified_at_dumptime()) { ++ return warn_excluded(k, "Not linked"); ++ } ++ } ++ } ++ if (DynamicDumpSharedSpaces && k->major_version() < 50 /*JAVA_6_VERSION*/) { ++ // In order to support old classes during dynamic dump, class rewriting needs to ++ // be reverted. This would result in more complex code and testing but not much gain. ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("Pre JDK 6 class not supported by CDS: %u.%u %s", ++ k->major_version(), k->minor_version(), k->name()->as_C_string()); ++ return true; ++ } ++ ++ if (!k->can_be_verified_at_dumptime() && k->is_linked()) { ++ return warn_excluded(k, "Old class has been linked"); ++ } ++ ++ if (k->is_anonymous() /* && !is_registered_lambda_proxy_class(k) */) { ++ return warn_excluded(k, "Hidden class"); ++ } ++ ++ InstanceKlass* super = k->java_super(); ++ if (super != NULL && check_for_exclusion(super, NULL)) { ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("Skipping %s: super class %s is excluded", k->name()->as_C_string(), super->name()->as_C_string()); ++ return true; ++ } ++ ++ Array* interfaces = k->local_interfaces(); ++ int len = interfaces->length(); ++ for (int i = 0; i < len; i++) { ++ InstanceKlass* intf = (InstanceKlass*)interfaces->at(i); ++ if (check_for_exclusion(intf, NULL)) { ++ dynamic_cds_log->print_cr("Skipping %s: interface %s is excluded", k->name()->as_C_string(), intf->name()->as_C_string()); ++ return true; ++ } ++ } ++ ++ return false; // false == k should NOT be excluded ++} ++ ++// Returns true so the caller can do: return warn_excluded("....."); ++bool SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) { ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("Skipping %s: %s", k->name()->as_C_string(), reason); ++ return true; ++} ++ ++bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) { ++ while (k) { ++ if (k->name()->equals("jdk/jfr/Event")) { ++ return true; ++ } ++ k = k->java_super(); ++ } ++ return false; ++} ++ ++bool SystemDictionaryShared::has_class_failed_verification(InstanceKlass* ik) { ++ if (_dumptime_table == NULL) { ++ assert(DynamicDumpSharedSpaces, "sanity"); ++ assert(ik->is_shared(), "must be a shared class in the static archive"); ++ return false; ++ } ++ DumpTimeSharedClassInfo* p = _dumptime_table->get(ik); ++ return (p == NULL) ? false : p->failed_verification(); ++} ++ ++void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) { ++ assert_lock_strong(DumpTimeTable_lock); ++ IterateDumpTimeSharedClassTable iter(it); ++ _dumptime_table->iterate(&iter); ++} ++ ++void SystemDictionaryShared::replace_klass_in_constantPool() { ++ IterateDumpTimeTableReplaceKlass iter; ++ _dumptime_table->iterate(&iter); ++} ++ ++bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) { ++ assert(_no_class_loading_should_happen, "sanity"); ++ assert_lock_strong(DumpTimeTable_lock); ++ Arguments::assert_is_dumping_archive(); ++ DumpTimeSharedClassInfo* p = find_or_allocate_info_for_locked(k); ++ return (p == NULL) ? true : p->is_excluded(); ++} ++ ++class EstimateSizeForArchive : StackObj { ++ size_t _shared_class_info_size; ++ int _num_builtin_klasses; ++ int _num_unregistered_klasses; ++ ++public: ++ EstimateSizeForArchive() { ++ _shared_class_info_size = 0; ++ _num_builtin_klasses = 0; ++ _num_unregistered_klasses = 0; ++ } ++ ++ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) { ++ if (!info.is_excluded()) { ++ size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_verifier_constraints(), info.num_loader_constraints()); ++ _shared_class_info_size += align_up(byte_size, KlassAlignmentInBytes); ++ } ++ return true; // keep on iterating ++ } ++ ++ size_t total() { ++ return _shared_class_info_size; ++ } ++}; ++ ++size_t SystemDictionaryShared::estimate_size_for_archive() { ++ EstimateSizeForArchive est; ++ _dumptime_table->iterate(&est); ++ size_t total_size = est.total() + ++ CompactHashtableWriter::estimate_size(_dumptime_table->count_of(true)) + ++ CompactHashtableWriter::estimate_size(_dumptime_table->count_of(false)); ++ total_size += CompactHashtableWriter::estimate_size(0); ++ return total_size; ++} ++ ++unsigned int SystemDictionaryShared::hash_for_shared_dictionary(address ptr) { ++ if (ArchiveBuilder::is_active()) { ++ uintx offset = ArchiveBuilder::current()->any_to_offset(ptr); ++ unsigned int hash = primitive_hash(offset); ++ DEBUG_ONLY({ ++ if (((const MetaspaceObj*)ptr)->is_shared()) { ++ assert(hash == SystemDictionaryShared::hash_for_shared_dictionary_quick(ptr), "must be"); ++ } ++ }); ++ return hash; ++ } else { ++ return SystemDictionaryShared::hash_for_shared_dictionary_quick(ptr); ++ } ++} ++ ++class CopySharedClassInfoToArchive : StackObj { ++ CompactHashtableWriter* _writer; ++ bool _is_builtin; ++ ArchiveBuilder *_builder; ++public: ++ CopySharedClassInfoToArchive(CompactHashtableWriter* writer, ++ bool is_builtin) ++ : _writer(writer), _is_builtin(is_builtin), _builder(ArchiveBuilder::current()) {} ++ ++ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) { ++ if (!info.is_excluded() && info.is_builtin() == _is_builtin) { ++ size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_verifier_constraints(), info.num_loader_constraints()); ++ RunTimeSharedClassInfo* record; ++ record = (RunTimeSharedClassInfo*)ArchiveBuilder::ro_region_alloc(byte_size); ++ record->init(info); ++ ++ unsigned int hash; ++ Symbol* name = info._klass->name(); ++ hash = SystemDictionaryShared::hash_for_shared_dictionary((address)name); ++ u4 delta = _builder->buffer_to_offset_u4((address)record); ++ if (_is_builtin && info._klass->is_anonymous()) { ++ // skip ++ } else { ++ _writer->add(hash, delta); ++ } ++ if (TraceDynamicCDS) { ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("%s dictionary: %s", (_is_builtin ? "builtin" : "unregistered"), info._klass->external_name()); ++ } ++ ++ // Save this for quick runtime lookup of InstanceKlass* -> RunTimeSharedClassInfo* ++ RunTimeSharedClassInfo::set_for(info._klass, record); ++ } ++ return true; // keep on iterating ++ } ++}; ++ ++void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionary, ++ bool is_builtin) { ++ CompactHashtableStats stats; ++ dictionary->reset(); ++ CompactHashtableWriter writer(_dumptime_table->count_of(is_builtin), &stats); ++ CopySharedClassInfoToArchive copy(&writer, is_builtin); ++ assert_lock_strong(DumpTimeTable_lock); ++ _dumptime_table->iterate(©); ++ writer.dump(dictionary, is_builtin ? "builtin dictionary" : "unregistered dictionary"); ++} ++ ++void SystemDictionaryShared::write_to_archive() { ++ write_dictionary(&_dynamic_builtin_dictionary, true); ++ write_dictionary(&_dynamic_unregistered_dictionary, false); ++} ++ ++void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc) { ++ _dynamic_builtin_dictionary.serialize_header(soc); ++ _dynamic_unregistered_dictionary.serialize_header(soc); ++} ++ ++void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) { ++ Arguments::assert_is_dumping_archive(); ++ assert(!is_builtin(k), "must be unregistered class"); ++ DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k); ++ if (info != NULL) { ++ info->_clsfile_size = cfs->length(); ++ info->_clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length()); ++ } ++} ++ ++// This function is called for loading only UNREGISTERED classes ++InstanceKlass* SystemDictionaryShared::lookup_from_stream(Symbol* class_name, ++ Handle class_loader, ++ Handle protection_domain, ++ const ClassFileStream* cfs, ++ TRAPS) { ++ if (!UseSharedSpaces) { ++ return NULL; ++ } ++ if (class_name == NULL) { // don't do this for hidden classes ++ return NULL; ++ } ++ if (SystemDictionary::is_builtin_loader(class_loader)) { ++ // Do nothing for the BUILTIN loaders. ++ return NULL; ++ } ++ ++ const RunTimeSharedClassInfo* record = find_record(&_dynamic_unregistered_dictionary, class_name); ++ if (record == NULL) { ++ return NULL; ++ } ++ ++ int clsfile_size = cfs->length(); ++ int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length()); ++ ++ if (!record->matches(clsfile_size, clsfile_crc32)) { ++ return NULL; ++ } ++ ++ return acquire_class_for_current_thread(record->_klass, class_loader, ++ protection_domain, cfs, ++ THREAD); ++} ++ ++const RunTimeSharedClassInfo* ++SystemDictionaryShared::find_record(RunTimeSharedDictionary* dynamic_dict, Symbol* name) { ++ if (!UseSharedSpaces || !name->is_shared()) { ++ // The names of all shared classes must also be a shared Symbol. ++ return NULL; ++ } ++ ++ unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(name); ++ const RunTimeSharedClassInfo* record = NULL; ++ // AppCDS only support builtin classloader, customer class loader is just in dynamic archive. ++ if (DynamicArchive::is_mapped()) { ++ record = dynamic_dict->lookup(name, hash, 0); ++ } ++ ++ return record; ++} ++ ++InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread( ++ InstanceKlass *ik, ++ Handle class_loader, ++ Handle protection_domain, ++ const ClassFileStream *cfs, ++ TRAPS) { ++ ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); ++ ++ { ++ MutexLocker mu(SharedDictionary_lock, THREAD); ++ if (ik->class_loader_data() != NULL) { ++ // ik is already loaded (by this loader or by a different loader) ++ // or ik is being loaded by a different thread (by this loader or by a different loader) ++ return NULL; ++ } ++ ++ // No other thread has acquired this yet, so give it to *this thread* ++ ik->set_class_loader_data(loader_data); ++ } ++ ++ // No longer holding SharedDictionary_lock ++ // No need to lock, as can be held only by a single thread. ++ loader_data->add_class(ik); ++ ++ // Load and check super/interfaces, restore unsharable info ++ instanceKlassHandle shared_klass = SystemDictionary::load_shared_class(ik, class_loader, protection_domain, THREAD); ++ if (shared_klass() == NULL || HAS_PENDING_EXCEPTION) { ++ // TODO: clean up so it can be used again ++ return NULL; ++ } ++ ++ return shared_klass(); ++} ++ ++InstanceKlass* SystemDictionaryShared::find_dynamic_builtin_class(Symbol* name) { ++ const RunTimeSharedClassInfo* record = find_record(&_dynamic_builtin_dictionary, name); ++ if (record != NULL) { ++ assert(!record->_klass->is_anonymous(), "hidden class cannot be looked up by name"); ++ assert(check_klass_alignment(record->_klass), "Address not aligned"); ++ return record->_klass; ++ } else { ++ return NULL; ++ } ++} +diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +index 1bd61b02..36423bee 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp ++++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +@@ -22,7 +22,6 @@ + * + */ + +- + #ifndef SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP + #define SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP + +@@ -30,13 +29,91 @@ + #include "classfile/systemDictionary.hpp" + #include "verifier.hpp" + ++/*=============================================================================== ++ ++ Handling of the classes in the AppCDS archive ++ ++ To ensure safety and to simplify the implementation, archived classes are ++ "segregated" into 2 types. The following rules describe how they ++ are stored and looked up. ++ ++[1] Category of archived classes ++ ++ There are 2 disjoint groups of classes stored in the AppCDS archive: ++ ++ BUILTIN: These classes may be defined ONLY by the BOOT/PLATFORM/APP ++ loaders. ++ ++ UNREGISTERED: These classes may be defined ONLY by a ClassLoader ++ instance that's not listed above (using fingerprint matching) ++ ++[2] How classes from different categories are specified in the classlist: ++ ++ Starting from JDK9, each class in the classlist may be specified with ++ these keywords: "id", "super", "interfaces", "loader" and "source". ++ ++ ++ BUILTIN Only the "id" keyword may be (optionally) specified. All other ++ keywords are forbidden. ++ ++ The named class is looked up from the jimage and from ++ Xbootclasspath/a and CLASSPATH. ++ ++ UNREGISTERED: The "id", "super", and "source" keywords must all be ++ specified. ++ ++ The "interfaces" keyword must be specified if the class implements ++ one or more local interfaces. The "interfaces" keyword must not be ++ specified if the class does not implement local interfaces. ++ ++ The named class is looked up from the location specified in the ++ "source" keyword. ++ ++ Example classlist: ++ ++ # BUILTIN ++ java/lang/Object id: 0 ++ java/lang/Cloneable id: 1 ++ java/lang/String ++ ++ # UNREGISTERED ++ Bar id: 3 super: 0 interfaces: 1 source: /foo.jar ++ ++ ++[3] Identifying the category of archived classes ++ ++ BUILTIN: (C->shared_classpath_index() >= 0) ++ UNREGISTERED: (C->shared_classpath_index() == UNREGISTERED_INDEX (-9999)) ++ ++[4] Lookup of archived classes at run time: ++ ++ (a) BUILTIN loaders: ++ ++ search _builtin_dictionary ++ ++ (b) UNREGISTERED loaders: ++ ++ search _unregistered_dictionary for an entry that matches the ++ (name, clsfile_len, clsfile_crc32). ++ ++===============================================================================*/ ++#define UNREGISTERED_INDEX -9999 ++ ++class DumpTimeSharedClassInfo; ++class RunTimeSharedClassInfo; ++class RunTimeSharedDictionary; ++ + class SystemDictionaryShared: public SystemDictionary { ++private: ++ static bool _dump_in_progress; ++ DEBUG_ONLY(static bool _no_class_loading_should_happen;) ++ + public: + static void initialize(TRAPS) {} + static instanceKlassHandle find_or_load_shared_class(Symbol* class_name, + Handle class_loader, + TRAPS) { +- if (UseAppCDS) { ++ if (UseSharedSpaces) { + instanceKlassHandle ik = load_shared_class(class_name, class_loader, CHECK_NULL); + if (!ik.is_null()) { + instanceKlassHandle nh = instanceKlassHandle(); // null Handle +@@ -48,7 +125,7 @@ public: + } + static void roots_oops_do(OopClosure* blk) {} + static void oops_do(OopClosure* f) {} +- ++ + static bool is_sharing_possible(ClassLoaderData* loader_data) { + oop class_loader = loader_data->class_loader(); + return (class_loader == NULL || +@@ -60,8 +137,43 @@ public: + static size_t dictionary_entry_size() { + return sizeof(DictionaryEntry); + } ++ + static void init_shared_dictionary_entry(Klass* k, DictionaryEntry* entry) {} + ++ static void init_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN; ++ static void remove_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN; ++ ++ static void start_dumping(); ++ ++ static DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k); ++ ++ static DumpTimeSharedClassInfo* find_or_allocate_info_for_locked(InstanceKlass* k); ++ ++ static bool empty_dumptime_table(); ++ ++ static void check_excluded_classes(); ++ ++ static bool check_for_exclusion(InstanceKlass* k, DumpTimeSharedClassInfo* info); ++ ++ static bool has_been_redefined(InstanceKlass* k); ++ ++ static bool check_for_exclusion_impl(InstanceKlass* k); ++ ++ static bool warn_excluded(InstanceKlass* k, const char* reason); ++ ++ static bool is_jfr_event_class(InstanceKlass *k); ++ ++ static bool has_class_failed_verification(InstanceKlass* ik); ++ ++ static bool is_builtin(InstanceKlass* k) { ++ return (k->shared_classpath_index() != UNREGISTERED_INDEX); ++ } ++ ++ static void dumptime_classes_do(class MetaspaceClosure* it); ++ ++ static void replace_klass_in_constantPool(); ++ ++ static bool is_excluded_class(InstanceKlass* k); + // The (non-application) CDS implementation supports only classes in the boot + // class loader, which ensures that the verification dependencies are the same + // during archive creation time and runtime. Thus we can do the dependency checks +@@ -69,6 +181,7 @@ public: + static void add_verification_dependency(Klass* k, Symbol* accessor_clsname, + Symbol* target_clsname) {} + static void finalize_verification_dependencies() {} ++ static void set_class_has_failed_verification(InstanceKlass* ik); + static bool check_verification_dependencies(Klass* k, Handle class_loader, + Handle protection_domain, + char** message_buffer, TRAPS) { +@@ -81,6 +194,49 @@ public: + } + return true; + } ++ static size_t estimate_size_for_archive(); ++ static void write_to_archive(); ++ static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin); ++ static void serialize_dictionary_headers(class SerializeClosure* soc); ++ static unsigned int hash_for_shared_dictionary(address ptr); ++ static void set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs); ++ static InstanceKlass* lookup_from_stream(Symbol* class_name, ++ Handle class_loader, ++ Handle protection_domain, ++ const ClassFileStream* cfs, ++ TRAPS); ++ ++ DEBUG_ONLY(static bool no_class_loading_should_happen() {return _no_class_loading_should_happen;}) ++ ++#ifdef ASSERT ++ class NoClassLoadingMark: public StackObj { ++ public: ++ NoClassLoadingMark() { ++ assert(!_no_class_loading_should_happen, "must not be nested"); ++ _no_class_loading_should_happen = true; ++ } ++ ~NoClassLoadingMark() { ++ _no_class_loading_should_happen = false; ++ } ++ }; ++#endif ++ ++ template ++ static unsigned int hash_for_shared_dictionary_quick(T* ptr) { ++ assert(((MetaspaceObj*)ptr)->is_shared(), "must be"); ++ assert(ptr > (T*)SharedBaseAddress, "must be"); ++ uintx offset = uintx(ptr) - uintx(SharedBaseAddress); ++ return primitive_hash(offset); ++ } ++ ++ static const RunTimeSharedClassInfo* find_record(RunTimeSharedDictionary* dynamic_dict, Symbol* name); ++ static InstanceKlass* acquire_class_for_current_thread(InstanceKlass *ik, ++ Handle class_loader, ++ Handle protection_domain, ++ const ClassFileStream *cfs, ++ TRAPS); ++ ++ static InstanceKlass* find_dynamic_builtin_class(Symbol* name); + }; + + #endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP +diff --git a/hotspot/src/share/vm/memory/allocation.hpp b/hotspot/src/share/vm/memory/allocation.hpp +index aa8f02d09..4d324b442 100644 +--- a/hotspot/src/share/vm/memory/allocation.hpp ++++ b/hotspot/src/share/vm/memory/allocation.hpp +@@ -302,6 +302,11 @@ class MetaspaceObj { + Type type, Thread* thread) throw(); + // can't use TRAPS from this header file. + void operator delete(void* p) { ShouldNotCallThis(); } ++ ++ // Declare a *static* method with the same signature in any subclass of MetaspaceObj ++ // that should be read-only by default. See symbol.hpp for an example. This function ++ // is used by the templates in metaspaceClosure.hpp ++ static bool is_read_only_by_default() { return false; } + }; + + // Base class for classes that constitute name spaces. +@@ -728,6 +733,12 @@ class ArrayAllocator VALUE_OBJ_CLASS_SPEC { + bool _use_malloc; + size_t _size; + bool _free_in_destructor; ++ ++ static bool should_use_malloc(size_t size) { ++ return size < ArrayAllocatorMallocLimit; ++ } ++ ++ static char* allocate_inner(size_t& size, bool& use_malloc); + public: + ArrayAllocator(bool free_in_destructor = true) : + _addr(NULL), _use_malloc(false), _size(0), _free_in_destructor(free_in_destructor) { } +@@ -739,6 +750,7 @@ class ArrayAllocator VALUE_OBJ_CLASS_SPEC { + } + + E* allocate(size_t length); ++ E* reallocate(size_t new_length); + void free(); + }; + +diff --git a/hotspot/src/share/vm/memory/allocation.inline.hpp b/hotspot/src/share/vm/memory/allocation.inline.hpp +index 9f2e1655a..2e794a8b6 100644 +--- a/hotspot/src/share/vm/memory/allocation.inline.hpp ++++ b/hotspot/src/share/vm/memory/allocation.inline.hpp +@@ -151,35 +151,58 @@ template void CHeapObj::operator delete [](void* p){ + } + + template +-E* ArrayAllocator::allocate(size_t length) { +- assert(_addr == NULL, "Already in use"); ++char* ArrayAllocator::allocate_inner(size_t &size, bool &use_malloc) { ++ char* addr = NULL; + +- _size = sizeof(E) * length; +- _use_malloc = _size < ArrayAllocatorMallocLimit; +- +- if (_use_malloc) { +- _addr = AllocateHeap(_size, F); +- if (_addr == NULL && _size >= (size_t)os::vm_allocation_granularity()) { ++ if (use_malloc) { ++ addr = AllocateHeap(size, F); ++ if (addr == NULL && size >= (size_t)os::vm_allocation_granularity()) { + // malloc failed let's try with mmap instead +- _use_malloc = false; ++ use_malloc = false; + } else { +- return (E*)_addr; ++ return addr; + } + } + + int alignment = os::vm_allocation_granularity(); +- _size = align_size_up(_size, alignment); ++ size = align_size_up(size, alignment); + +- _addr = os::reserve_memory(_size, NULL, alignment, F); +- if (_addr == NULL) { +- vm_exit_out_of_memory(_size, OOM_MMAP_ERROR, "Allocator (reserve)"); ++ addr = os::reserve_memory(size, NULL, alignment, F); ++ if (addr == NULL) { ++ vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "Allocator (reserve)"); + } + +- os::commit_memory_or_exit(_addr, _size, !ExecMem, "Allocator (commit)"); ++ os::commit_memory_or_exit(addr, size, !ExecMem, "Allocator (commit)"); ++ return addr; ++} ++ ++template ++E* ArrayAllocator::allocate(size_t length) { ++ assert(_addr == NULL, "Already in use"); + ++ _size = sizeof(E) * length; ++ ++ _use_malloc = should_use_malloc(_size); ++ _addr = allocate_inner(_size, _use_malloc); + return (E*)_addr; + } + ++template ++E* ArrayAllocator::reallocate(size_t new_length) { ++ size_t new_size = sizeof(E) * new_length; ++ bool use_malloc = should_use_malloc(new_size); ++ char* new_addr = allocate_inner(new_size, use_malloc); ++ ++ memcpy(new_addr, _addr, MIN2(new_size, _size)); ++ ++ free(); ++ _size = new_size; ++ _use_malloc = use_malloc; ++ _addr = new_addr; ++ return (E*)new_addr; ++} ++ ++ + template + void ArrayAllocator::free() { + if (_addr != NULL) { +diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp +index 99b1f58d0..3f4106476 100644 +--- a/hotspot/src/share/vm/memory/filemap.cpp ++++ b/hotspot/src/share/vm/memory/filemap.cpp +@@ -24,6 +24,8 @@ + + #include "jvm.h" + #include "precompiled.hpp" ++#include "cds/archiveBuilder.hpp" ++#include "cds/dynamicArchive.hpp" + #include "classfile/classLoader.hpp" + #include "classfile/sharedClassUtil.hpp" + #include "classfile/symbolTable.hpp" +@@ -140,19 +142,33 @@ template static void get_header_version(char (&header_version) [N]) { + } + } + +-FileMapInfo::FileMapInfo() { +- assert(_current_info == NULL, "must be singleton"); // not thread safe +- _current_info = this; ++FileMapInfo::FileMapInfo(bool is_static) { + memset(this, 0, sizeof(FileMapInfo)); ++ _is_static = is_static; ++ ++ if (is_static) { ++ assert(_current_info == NULL, "must be singleton"); // not thread safe ++ _current_info = this; ++ _header = SharedClassUtil::allocate_file_map_header(); ++ } else { ++ assert(_dynamic_archive_info == NULL, "must be singleton"); // not thread safe ++ _dynamic_archive_info = this; ++ _header = SharedClassUtil::allocate_dynamic_archive_header(); ++ } ++ ++ _header->_version = _invalid_version; + _file_offset = 0; + _file_open = false; +- _header = SharedClassUtil::allocate_file_map_header(); +- _header->_version = _invalid_version; + } + + FileMapInfo::~FileMapInfo() { +- assert(_current_info == this, "must be singleton"); // not thread safe +- _current_info = NULL; ++ if (_is_static) { ++ assert(_current_info == this, "must be singleton"); // not thread safe ++ _current_info = NULL; ++ } else { ++ assert(_dynamic_archive_info == this, "must be singleton"); // not thread safe ++ _dynamic_archive_info = NULL; ++ } + } + + void FileMapInfo::populate_header(size_t alignment) { +@@ -163,14 +179,66 @@ size_t FileMapInfo::FileMapHeader::data_size() { + return SharedClassUtil::file_map_header_size() - sizeof(FileMapInfo::FileMapHeaderBase); + } + ++size_t FileMapInfo::DynamicArchiveHeader::data_size() { ++ return sizeof(FileMapInfo::DynamicArchiveHeader) - sizeof(FileMapInfo::FileMapHeaderBase); ++} ++ ++bool FileMapInfo::DynamicArchiveHeader::validate() { ++ if (_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { ++ FileMapInfo::fail_continue("The shared archive file has a bad magic number."); ++ return false; ++ } ++ if (VerifySharedSpaces && compute_crc() != _crc) { ++ fail_continue("Header checksum verification failed."); ++ return false; ++ } ++ if (_version != current_version()) { ++ FileMapInfo::fail_continue("The shared archive file is the wrong version."); ++ return false; ++ } ++ char header_version[JVM_IDENT_MAX]; ++ get_header_version(header_version); ++ if (strncmp(_jvm_ident, header_version, JVM_IDENT_MAX-1) != 0) { ++ if (TraceClassPaths) { ++ tty->print_cr("Expected: %s", header_version); ++ tty->print_cr("Actual: %s", _jvm_ident); ++ } ++ FileMapInfo::fail_continue("The shared archive file was created by a different" ++ " version or build of HotSpot"); ++ return false; ++ } ++ if (_obj_alignment != ObjectAlignmentInBytes) { ++ FileMapInfo::fail_continue("The shared archive file's ObjectAlignmentInBytes of %d" ++ " does not equal the current ObjectAlignmentInBytes of %d.", ++ _obj_alignment, ObjectAlignmentInBytes); ++ return false; ++ } ++ ++ // TODO: much more validate check ++ ++ return true; ++} ++ + void FileMapInfo::FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) { +- _magic = 0xf00baba2; +- _version = _current_version; ++ if (DynamicDumpSharedSpaces) { ++ _magic = CDS_DYNAMIC_ARCHIVE_MAGIC; ++ } else { ++ _magic = CDS_ARCHIVE_MAGIC; ++ } ++ _version = current_version(); + _alignment = alignment; + _obj_alignment = ObjectAlignmentInBytes; +- _classpath_entry_table_size = mapinfo->_classpath_entry_table_size; +- _classpath_entry_table = mapinfo->_classpath_entry_table; +- _classpath_entry_size = mapinfo->_classpath_entry_size; ++ /* TODO ++ _compressed_oops = UseCompressedOops; ++ _compressed_class_ptrs = UseCompressedClassPointers; ++ _max_heap_size = MaxHeapSize; ++ _narrow_klass_shift = CompressedKlassPointers::shift(); ++ */ ++ if (!DynamicDumpSharedSpaces) { ++ _classpath_entry_table_size = mapinfo->_classpath_entry_table_size; ++ _classpath_entry_table = mapinfo->_classpath_entry_table; ++ _classpath_entry_size = mapinfo->_classpath_entry_size; ++ } + + // The following fields are for sanity checks for whether this archive + // will function correctly with this JVM and the bootclasspath it's +@@ -303,62 +371,174 @@ bool FileMapInfo::validate_classpath_entry_table() { + return true; + } + ++bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name, ++ int* size, char** base_archive_name) { ++ int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0); ++ if (fd < 0) { ++ *size = 0; ++ return false; ++ } + +-// Read the FileMapInfo information from the file. +- +-bool FileMapInfo::init_from_file(int fd) { +- size_t sz = _header->data_size(); +- char* addr = _header->data(); ++ // read the header as a dynamic archive header ++ DynamicArchiveHeader* dynamic_header = SharedClassUtil::allocate_dynamic_archive_header(); ++ size_t sz = dynamic_header->data_size(); ++ char* addr = dynamic_header->data(); + size_t n = os::read(fd, addr, (unsigned int)sz); + if (n != sz) { + fail_continue("Unable to read the file header."); ++ delete dynamic_header; ++ os::close(fd); + return false; + } +- if (_header->_version != current_version()) { +- fail_continue("The shared archive file has the wrong version."); ++ if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC) { ++ // Not a dynamic header, no need to proceed further. ++ *size = 0; ++ delete dynamic_header; ++ os::close(fd); + return false; + } + +- size_t info_size = _header->_paths_misc_info_size; +- _paths_misc_info = NEW_C_HEAP_ARRAY_RETURN_NULL(char, info_size, mtClass); +- if (_paths_misc_info == NULL) { +- fail_continue("Unable to read the file header."); ++ // read the base archive name ++ size_t name_size = dynamic_header->base_archive_name_size(); ++ if (name_size == 0) { ++ delete dynamic_header; ++ os::close(fd); + return false; + } +- n = os::read(fd, _paths_misc_info, (unsigned int)info_size); +- if (n != info_size) { +- fail_continue("Unable to read the shared path info header."); +- FREE_C_HEAP_ARRAY(char, _paths_misc_info, mtClass); +- _paths_misc_info = NULL; ++ *base_archive_name = NEW_C_HEAP_ARRAY(char, name_size, mtInternal); ++ n = os::read(fd, *base_archive_name, (unsigned int)name_size); ++ if (n != name_size) { ++ fail_continue("Unable to read the base archive name from the header."); ++ FREE_C_HEAP_ARRAY(char, *base_archive_name, mtInternal); ++ *base_archive_name = NULL; ++ delete dynamic_header; ++ os::close(fd); + return false; + } + +- size_t len = lseek(fd, 0, SEEK_END); +- struct FileMapInfo::FileMapHeader::space_info* si = +- &_header->_space[MetaspaceShared::mc]; +- if (si->_file_offset >= len || len - si->_file_offset < si->_used) { +- fail_continue("The shared archive file has been truncated."); ++ delete dynamic_header; ++ os::close(fd); ++ return true; ++} ++ ++bool FileMapInfo::check_archive(const char* archive_name, bool is_static) { ++ int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0); ++ if (fd < 0) { ++ // do not vm_exit_during_initialization here because Arguments::init_shared_archive_paths() ++ // requires a shared archive name. The open_for_read() function will log a message regarding ++ // failure in opening a shared archive. + return false; + } + +- _file_offset += (long)n; ++ FileMapHeader* header = NULL; ++ if (is_static) { ++ header = SharedClassUtil::allocate_file_map_header(); ++ } else { ++ header = SharedClassUtil::allocate_dynamic_archive_header(); ++ } ++ ++ size_t sz = header->data_size(); ++ size_t n = os::read(fd, header->data(), (unsigned int)sz); ++ if (n != sz) { ++ delete header; ++ os::close(fd); ++ vm_exit_during_initialization("Unable to read header from shared archive", archive_name); ++ return false; ++ } ++ if (is_static) { ++ FileMapHeader* static_header = (FileMapHeader*)header; ++ if (static_header->magic() != CDS_ARCHIVE_MAGIC) { ++ delete header; ++ os::close(fd); ++ vm_exit_during_initialization("Not a base shared archive", archive_name); ++ return false; ++ } ++ } else { ++ DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)header; ++ if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC) { ++ delete header; ++ os::close(fd); ++ vm_exit_during_initialization("Not a top shared archive", archive_name); ++ return false; ++ } ++ } ++ delete header; ++ os::close(fd); ++ return true; ++} ++ ++// Read the FileMapInfo information from the file. ++ ++bool FileMapInfo::init_from_file(int fd) { ++ size_t sz = header()->data_size(); ++ char* addr = header()->data(); ++ size_t n = os::read(fd, addr, (unsigned int)sz); ++ if (n != sz) { ++ fail_continue("Unable to read the file header."); ++ return false; ++ } ++ ++ _file_offset += n; ++ ++ if (is_static()) { ++ size_t info_size = _header->_paths_misc_info_size; ++ _paths_misc_info = NEW_C_HEAP_ARRAY_RETURN_NULL(char, info_size, mtClass); ++ if (_paths_misc_info == NULL) { ++ fail_continue("Unable to read the file header."); ++ return false; ++ } ++ n = os::read(fd, _paths_misc_info, (unsigned int)info_size); ++ if (n != info_size) { ++ fail_continue("Unable to read the shared path info header."); ++ FREE_C_HEAP_ARRAY(char, _paths_misc_info, mtClass); ++ _paths_misc_info = NULL; ++ return false; ++ } ++ ++ // just checking the last region is sufficient since the archive is written ++ // in sequential order ++ size_t len = lseek(fd, 0, SEEK_END); ++ struct FileMapInfo::FileMapHeader::space_info* si = ++ &_header->_space[MetaspaceShared::mc]; ++ if (si->_file_offset >= len || len - si->_file_offset < si->_used) { ++ fail_continue("The shared archive file has been truncated."); ++ return false; ++ } ++ ++ _file_offset += n; ++ } else { ++ _file_offset += dynamic_header()->base_archive_name_size(); // accounts for the size of _base_archive_name ++ } ++ + return true; + } + + + // Read the FileMapInfo information from the file. + bool FileMapInfo::open_for_read() { +- _full_path = make_log_name(Arguments::GetSharedArchivePath(), NULL); +- int fd = open(_full_path, O_RDONLY | O_BINARY, 0); ++ if (_file_open) { ++ return true; ++ } ++ if (is_static()) { ++ _full_path = Arguments::GetSharedArchivePath(); ++ } else { ++ _full_path = Arguments::GetSharedDynamicArchivePath(); ++ } ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("trying to map %s", _full_path); ++ } ++ int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0); + if (fd < 0) { + if (errno == ENOENT) { +- // Not locating the shared archive is ok. +- fail_continue("Specified shared archive not found. archive file path:%s", _full_path); ++ fail_continue("Specified shared archive not found (%s).", _full_path); + } else { +- fail_continue("Failed to open shared archive file (%s).", +- strerror(errno)); ++ fail_continue("Failed to open shared archive file (%s).", strerror(errno)); + } + return false; ++ } else { ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Opened archive %s.", _full_path); ++ } + } + + _fd = fd; +@@ -368,7 +548,7 @@ bool FileMapInfo::open_for_read() { + + // Write the FileMapInfo information to the file. + void FileMapInfo::open_for_write() { +- if (UseAppCDS && AppCDSLockFile != NULL) { ++ if ((DynamicDumpSharedSpaces || UseAppCDS) && AppCDSLockFile != NULL) { + char* pos = strrchr(const_cast(AppCDSLockFile), '/'); + #ifdef __linux__ + if (pos != NULL && pos != AppCDSLockFile) { // No directory path specified +@@ -391,14 +571,18 @@ void FileMapInfo::open_for_write() { + int lock_fd = open(_appcds_file_lock_path, O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR); + if (lock_fd < 0) { + tty->print_cr("Failed to create jsa file !\n Please check: \n 1. The directory exists.\n " +- "2. You have the permission.\n 3. Make sure no other process using the same lock file.\n"); ++ "2. You have the permission.\n 3. Make sure no other process using the same lock file.\n"); + fail_stop("Failed to create appcds lock file, the lock path is: %s.", _appcds_file_lock_path); + } + tty->print_cr("You are using file lock %s in concurrent mode", AppCDSLockFile); + } + #endif + } +- _full_path = make_log_name(Arguments::GetSharedArchivePath(), NULL); ++ if (is_static()) { ++ _full_path = make_log_name(Arguments::GetSharedArchivePath(), NULL); ++ } else { ++ _full_path = make_log_name(Arguments::GetSharedDynamicArchivePath(), NULL); ++ } + if (PrintSharedSpaces) { + tty->print_cr("Dumping shared data to file: "); + tty->print_cr(" %s", _full_path); +@@ -436,6 +620,18 @@ void FileMapInfo::write_header() { + align_file_position(); + } + ++void FileMapInfo::write_dynamic_header() { ++ align_file_position(); ++ size_t sz = _header->data_size(); ++ char* addr = _header->data(); ++ write_bytes(addr, (int)sz); // skip the C++ vtable ++ ++ char* base_archive_name = (char*)Arguments::GetSharedArchivePath(); ++ if (base_archive_name != NULL) { ++ write_bytes(base_archive_name, dynamic_header()->base_archive_name_size()); ++ } ++ align_file_position(); ++} + + // Dump shared spaces to file. + +@@ -464,7 +660,15 @@ void FileMapInfo::write_region(int region, char* base, size_t size, + } else { + si->_file_offset = _file_offset; + } +- si->_base = base; ++ if (is_static()) { ++ si->_base = base; ++ } else { ++ if (region == MetaspaceShared::d_bm) { ++ si->_base = NULL; // always NULL for bm region ++ } else { ++ si->_base = ArchiveBuilder::current()->to_requested(base); ++ } ++ } + si->_used = size; + si->_capacity = capacity; + si->_read_only = read_only; +@@ -473,7 +677,16 @@ void FileMapInfo::write_region(int region, char* base, size_t size, + write_bytes_aligned(base, (int)size); + } + ++char* FileMapInfo::write_bitmap_region(const BitMap* ptrmap) { ++ size_t size_in_bits = ptrmap->size(); ++ size_t size_in_bytes = ptrmap->size_in_words() * BytesPerWord; ++ char* buffer = NEW_C_HEAP_ARRAY(char, size_in_bytes, mtClassShared); ++ ptrmap->write_to((BitMap::bm_word_t*)buffer, size_in_bytes); ++ dynamic_header()->set_ptrmap_size_in_bits(size_in_bits); + ++ write_region(MetaspaceShared::d_bm, (char*)buffer, size_in_bytes, size_in_bytes, /*read_only=*/true, /*allow_exec=*/false); ++ return buffer; ++} + // Dump bytes to file -- at the current file position. + + void FileMapInfo::write_bytes(const void* buffer, int nbytes) { +@@ -542,7 +755,7 @@ void FileMapInfo::close() { + // JVM/TI RedefineClasses() support: + // Remap the shared readonly space to shared readwrite, private. + bool FileMapInfo::remap_shared_readonly_as_readwrite() { +- struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[0]; ++ struct FileMapInfo::FileMapHeader::space_info* si = is_static() ? &_header->_space[0] : &_header->_space[1]; + if (!si->_read_only) { + // the space is already readwrite so we are done + return true; +@@ -570,10 +783,14 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() { + + // Map the whole region at once, assumed to be allocated contiguously. + ReservedSpace FileMapInfo::reserve_shared_memory() { +- struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[0]; +- char* requested_addr = si->_base; ++ char* requested_addr = region_base(0); ++ size_t size = 0; + +- size_t size = FileMapInfo::shared_spaces_size(); ++ if (is_static()) { ++ size = FileMapInfo::shared_spaces_size(); ++ } else { ++ size = align_up((uintptr_t)region_end(1) - (uintptr_t)region_base(0), (size_t)os::vm_allocation_granularity()); ++ } + + // Reserve the space first, then map otherwise map will go right over some + // other reserved memory (like the code cache). +@@ -648,6 +865,7 @@ void FileMapInfo::assert_mark(bool check) { + + + FileMapInfo* FileMapInfo::_current_info = NULL; ++FileMapInfo* FileMapInfo::_dynamic_archive_info = NULL; + SharedClassPathEntry* FileMapInfo::_classpath_entry_table = NULL; + int FileMapInfo::_classpath_entry_table_size = 0; + size_t FileMapInfo::_classpath_entry_size = 0x1234baad; +@@ -674,19 +892,26 @@ bool FileMapInfo::initialize() { + if (!open_for_read()) { + return false; + } +- +- init_from_file(_fd); ++ if (!init_from_file(_fd)) { ++ return false; ++ } + if (!validate_header()) { + return false; + } + +- SharedReadOnlySize = _header->_space[0]._capacity; +- SharedReadWriteSize = _header->_space[1]._capacity; +- SharedMiscDataSize = _header->_space[2]._capacity; +- SharedMiscCodeSize = _header->_space[3]._capacity; ++ if (is_static()) { ++ SharedReadOnlySize = _header->_space[0]._capacity; ++ SharedReadWriteSize = _header->_space[1]._capacity; ++ SharedMiscDataSize = _header->_space[2]._capacity; ++ SharedMiscCodeSize = _header->_space[3]._capacity; ++ } + return true; + } + ++void FileMapInfo::DynamicArchiveHeader::set_as_offset(char* p, size_t *offset) { ++ *offset = ArchiveBuilder::current()->any_to_offset((address)p); ++} ++ + int FileMapInfo::FileMapHeader::compute_crc() { + char* header = data(); + // start computing from the field after _crc +@@ -701,7 +926,7 @@ int FileMapInfo::compute_header_crc() { + } + + bool FileMapInfo::FileMapHeader::validate() { +- if (_magic != (int)0xf00baba2) { ++ if (_magic != CDS_ARCHIVE_MAGIC) { + FileMapInfo::fail_continue("The shared archive file has a bad magic number."); + return false; + } +@@ -738,6 +963,10 @@ bool FileMapInfo::FileMapHeader::validate() { + bool FileMapInfo::validate_header() { + bool status = _header->validate(); + ++ if (status && !is_static()) { ++ return DynamicArchive::validate(this); ++ } ++ + if (status) { + if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) { + if (!PrintSharedArchiveAndExit) { +@@ -761,7 +990,13 @@ bool FileMapInfo::validate_header() { + // Return: + // True if the p is within the mapped shared space, otherwise, false. + bool FileMapInfo::is_in_shared_space(const void* p) { +- for (int i = 0; i < MetaspaceShared::n_regions; i++) { ++ int count = 0; ++ if (is_static()) { ++ count = MetaspaceShared::n_regions; ++ } else { ++ count = MetaspaceShared::d_n_regions; ++ } ++ for (int i = 0; i < count; i++) { + if (p >= _header->_space[i]._base && + p < _header->_space[i]._base + _header->_space[i]._used) { + return true; +@@ -772,6 +1007,11 @@ bool FileMapInfo::is_in_shared_space(const void* p) { + } + + void FileMapInfo::print_shared_spaces() { ++ // TODO: support dynamic archive ++ if (!is_static()) { ++ return; ++ } ++ + gclog_or_tty->print_cr("Shared Spaces:"); + for (int i = 0; i < MetaspaceShared::n_regions; i++) { + struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; +diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp +index 0eee1c7ea..eab9ebcfc 100644 +--- a/hotspot/src/share/vm/memory/filemap.hpp ++++ b/hotspot/src/share/vm/memory/filemap.hpp +@@ -27,6 +27,8 @@ + + #include "memory/metaspaceShared.hpp" + #include "memory/metaspace.hpp" ++#include "runtime/os.hpp" ++#include "utilities/align.hpp" + + // Layout of the file: + // header: dump of archive instance plus versioning info, datestamp, etc. +@@ -37,8 +39,12 @@ + // misc data (block offset table, string table, symbols, dictionary, etc.) + // tag(666) + ++#define CDS_ARCHIVE_MAGIC 0xf00baba2 ++#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8 ++ + static const int JVM_IDENT_MAX = 256; + ++class BitMap; + class Metaspace; + + class SharedClassPathEntry VALUE_OBJ_CLASS_SPEC { +@@ -56,11 +62,13 @@ private: + friend class ManifestStream; + enum { + _invalid_version = -1, +- _current_version = 2 ++ _current_version = 3, + }; + +- bool _file_open; +- int _fd; ++ bool _is_static; ++ bool _file_open; ++ bool _is_mapped; ++ int _fd; + size_t _file_offset; + + private: +@@ -77,20 +85,21 @@ public: + struct FileMapHeaderBase : public CHeapObj { + virtual bool validate() = 0; + virtual void populate(FileMapInfo* info, size_t alignment) = 0; +- }; +- struct FileMapHeader : FileMapHeaderBase { + // Use data() and data_size() to memcopy to/from the FileMapHeader. We need to + // avoid read/writing the C++ vtable pointer. +- static size_t data_size(); ++ virtual size_t data_size() = 0; ++ }; ++ struct FileMapHeader : FileMapHeaderBase { ++ size_t data_size(); + char* data() { + return ((char*)this) + sizeof(FileMapHeaderBase); + } + +- int _magic; // identify file type. +- int _crc; // header crc checksum. +- int _version; // (from enum, above.) +- size_t _alignment; // how shared archive should be aligned +- int _obj_alignment; // value of ObjectAlignmentInBytes ++ unsigned int _magic; // identify file type. ++ int _crc; // header crc checksum. ++ int _version; // (from enum, above.) ++ size_t _alignment; // how shared archive should be aligned ++ int _obj_alignment; // value of ObjectAlignmentInBytes + + struct space_info { + int _crc; // crc checksum of the current space +@@ -137,7 +146,48 @@ public: + + virtual bool validate(); + virtual void populate(FileMapInfo* info, size_t alignment); ++ int crc() { return _crc; } ++ int space_crc(int i) { return _space[i]._crc; } + int compute_crc(); ++ unsigned int magic() const { return _magic; } ++ const char* jvm_ident() const { return _jvm_ident; } ++ }; ++ ++ // Fixme ++ struct DynamicArchiveHeader : FileMapHeader { ++ private: ++ int _base_header_crc; ++ int _base_region_crc[MetaspaceShared::n_regions]; ++ char* _requested_base_address; // Archive relocation is not necessary if we map with this base address. ++ size_t _ptrmap_size_in_bits; // Size of pointer relocation bitmap ++ size_t _base_archive_name_size; ++ size_t _serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize() ++ ++ public: ++ size_t data_size(); ++ int base_header_crc() const { return _base_header_crc; } ++ int base_region_crc(int i) const { ++ return _base_region_crc[i]; ++ } ++ ++ void set_base_header_crc(int c) { _base_header_crc = c; } ++ void set_base_region_crc(int i, int c) { ++ _base_region_crc[i] = c; ++ } ++ ++ void set_requested_base(char* b) { ++ _requested_base_address = b; ++ } ++ size_t ptrmap_size_in_bits() const { return _ptrmap_size_in_bits; } ++ void set_ptrmap_size_in_bits(size_t s) { _ptrmap_size_in_bits = s; } ++ void set_base_archive_name_size(size_t s) { _base_archive_name_size = s; } ++ size_t base_archive_name_size() { return _base_archive_name_size; } ++ void set_as_offset(char* p, size_t *offset); ++ char* from_mapped_offset(size_t offset) const { return _requested_base_address + offset; } ++ void set_serialized_data(char* p) { set_as_offset(p, &_serialized_data_offset); } ++ char* serialized_data() const { return from_mapped_offset(_serialized_data_offset); } ++ ++ virtual bool validate(); + }; + + FileMapHeader * _header; +@@ -147,32 +197,52 @@ public: + char* _paths_misc_info; + + static FileMapInfo* _current_info; ++ static FileMapInfo* _dynamic_archive_info; + ++ static bool get_base_archive_name_from_header(const char* archive_name, ++ int* size, char** base_archive_name); ++ static bool check_archive(const char* archive_name, bool is_static); + bool init_from_file(int fd); + void align_file_position(); + bool validate_header_impl(); + + public: +- FileMapInfo(); ++ FileMapInfo(bool is_static = true); + ~FileMapInfo(); + + static int current_version() { return _current_version; } + int compute_header_crc(); + void set_header_crc(int crc) { _header->_crc = crc; } ++ int space_crc(int i) { return _header->_space[i]._crc; } + void populate_header(size_t alignment); + bool validate_header(); + void invalidate(); ++ int crc() { return _header->_crc; } + int version() { return _header->_version; } + size_t alignment() { return _header->_alignment; } + size_t space_capacity(int i) { return _header->_space[i]._capacity; } ++ size_t used(int i) { return _header->_space[i]._used; } ++ size_t used_aligned(int i) { return align_up(used(i), (size_t)os::vm_allocation_granularity()); } + char* region_base(int i) { return _header->_space[i]._base; } ++ char* region_end(int i) { return region_base(i) + used_aligned(i); } + struct FileMapHeader* header() { return _header; } ++ struct DynamicArchiveHeader* dynamic_header() { ++ // assert(!is_static(), "must be"); ++ return (struct DynamicArchiveHeader*)header(); ++ } ++ ++ void set_header_base_archive_name_size(size_t size) { dynamic_header()->set_base_archive_name_size(size); } + + static FileMapInfo* current_info() { + CDS_ONLY(return _current_info;) + NOT_CDS(return NULL;) + } + ++ static FileMapInfo* dynamic_info() { ++ CDS_ONLY(return _dynamic_archive_info;) ++ NOT_CDS(return NULL;) ++ } ++ + static void assert_mark(bool check); + + // File manipulation. +@@ -180,18 +250,24 @@ public: + bool open_for_read(); + void open_for_write(); + void write_header(); ++ void write_dynamic_header(); + void write_space(int i, Metaspace* space, bool read_only); + void write_region(int region, char* base, size_t size, + size_t capacity, bool read_only, bool allow_exec); ++ char* write_bitmap_region(const BitMap* ptrmap); + void write_bytes(const void* buffer, int count); + void write_bytes_aligned(const void* buffer, int count); + char* map_region(int i); + void unmap_region(int i); + bool verify_region_checksum(int i); + void close(); +- bool is_open() { return _file_open; } ++ bool is_open() { return _file_open; } ++ bool is_static() const { return _is_static; } ++ bool is_mapped() const { return _is_mapped; } ++ void set_is_mapped(bool v) { _is_mapped = v; } + ReservedSpace reserve_shared_memory(); +- ++ void set_requested_base(char* b) { dynamic_header()->set_requested_base(b); } ++ char* serialized_data() { return dynamic_header()->serialized_data(); } + // JVM/TI RedefineClasses() support: + // Remap the shared readonly space to shared readwrite, private. + bool remap_shared_readonly_as_readwrite(); +diff --git a/hotspot/src/share/vm/memory/iterator.hpp b/hotspot/src/share/vm/memory/iterator.hpp +index 62204eea7..dc01186a2 100644 +--- a/hotspot/src/share/vm/memory/iterator.hpp ++++ b/hotspot/src/share/vm/memory/iterator.hpp +@@ -378,6 +378,13 @@ public: + // for verification that sections of the serialized data are of the + // correct length. + virtual void do_tag(int tag) = 0; ++ ++ // Read/write the 32-bit unsigned integer pointed to by p. ++ virtual void do_u4(u4* p) { } ++ ++ bool writing() { ++ return !reading(); ++ } + }; + + class SymbolClosure : public StackObj { +diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp +index 2912f41b6..7e95b5c0b 100644 +--- a/hotspot/src/share/vm/memory/metaspace.cpp ++++ b/hotspot/src/share/vm/memory/metaspace.cpp +@@ -37,6 +37,7 @@ + #include "memory/metaspaceTracer.hpp" + #include "memory/resourceArea.hpp" + #include "memory/universe.hpp" ++#include "runtime/arguments.hpp" + #include "runtime/atomic.inline.hpp" + #include "runtime/globals.hpp" + #include "runtime/init.hpp" +@@ -426,8 +427,16 @@ VirtualSpaceNode::VirtualSpaceNode(size_t bytes) : _top(NULL), _next(NULL), _rs( + assert(shared_base == 0 || _rs.base() == shared_base, "should match"); + } else { + // Get a mmap region anywhere if the SharedBaseAddress fails. ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Could not allocate static space at request address: " INTPTR_FORMAT, p2i(shared_base)); ++ } + _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages); + } ++ // ...failing that, give up. ++ if (!_rs.is_reserved()) { ++ vm_exit_during_initialization( ++ err_msg("Could not allocate static shared space: " SIZE_FORMAT " bytes", bytes)); ++ } + MetaspaceShared::set_shared_rs(&_rs); + } else + #endif +@@ -3322,21 +3331,80 @@ void Metaspace::global_initialize() { + // the addresses don't conflict) + address cds_address = NULL; + if (UseSharedSpaces) { +- FileMapInfo* mapinfo = new FileMapInfo(); ++ FileMapInfo* static_mapinfo = new FileMapInfo(); ++ FileMapInfo* dynamic_mapinfo = new FileMapInfo(false); + + // Open the shared archive file, read and validate the header. If + // initialization fails, shared spaces [UseSharedSpaces] are + // disabled and the file is closed. +- // Map in spaces now also +- if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) { ++ // ++ // This will reserve two address spaces suitable to house Klass structures, one ++ // for the cds archives (static archive and optionally dynamic archive) and ++ // optionally one move for ccs. ++ // ++ // Since both spaces must fall within the compressed class pointer encoding ++ // range, they are allocated close to each other. ++ // ++ // Space for archives will be reserved first, followed by a potential gap, ++ // followed by the space for ccs: ++ // ++ // +-- Base address End ++ // | | ++ // v v ++ // +------------+ +-------------+ +--------------------+ ++ // | static arc | [align] | [dyn. arch] | [align] | compr. class space | ++ // +------------+ +-------------+ +--------------------+ ++ // ++ // (The gap may result from different alignment requirements between metaspace ++ // and CDS) ++ // ++ // If UseCompressedClassPointers is disabled, only one address space will be ++ // reserved: ++ // ++ // +-- Base address End ++ // | | ++ // v v ++ // +------------+ +-------------+ ++ // | static arc | [align] | [dyn. arch] | ++ // +------------+ +-------------+ ++ // ++ // If UseCompressedClassPointers=1, the range encompassing both spaces will be ++ // suitable to en/decode narrow Klass pointers: the base will be valid for ++ // encoding, the range [Base, End) not surpass KlassEncodingMetaspaceMax. ++ if (static_mapinfo->initialize() && MetaspaceShared::map_shared_spaces(static_mapinfo)) { + cds_total = FileMapInfo::shared_spaces_size(); +- cds_address = (address)mapinfo->region_base(0); ++ cds_address = (address)static_mapinfo->region_base(0); ++ MetaspaceShared::set_shared_metaspace_static_bottom(cds_address); ++ // Update SharedBaseAddress to the same value as the dump phase. ++ SharedBaseAddress = (size_t)cds_address; ++ if (!DynamicDumpSharedSpaces && ++ (Arguments::GetSharedDynamicArchivePath() != NULL) && ++ dynamic_mapinfo->initialize() && ++ MetaspaceShared::map_shared_spaces(dynamic_mapinfo)) { ++ cds_total += align_up(dynamic_mapinfo->region_end(1) - dynamic_mapinfo->region_base(0), ++ (size_t)os::vm_allocation_granularity()); ++ } else { ++ assert(!dynamic_mapinfo->is_open(), ++ "dynamic archive file not closed or shared spaces not disabled."); ++ } + } else { +- assert(!mapinfo->is_open() && !UseSharedSpaces, +- "archive file not closed or shared spaces not disabled."); ++ assert(!static_mapinfo->is_open() && !UseSharedSpaces, ++ "static archive file not closed or shared spaces not disabled."); ++ } ++ ++ if (static_mapinfo != NULL && !static_mapinfo->is_mapped()) { ++ delete static_mapinfo; ++ } ++ if (dynamic_mapinfo != NULL && !dynamic_mapinfo->is_mapped()) { ++ delete dynamic_mapinfo; + } + } ++ ++ if (DynamicDumpSharedSpaces && !UseSharedSpaces) { ++ vm_exit_during_initialization("DynamicDumpSharedSpaces is unsupported when base CDS archive is not loaded", NULL); ++ } + #endif // INCLUDE_CDS ++ + #ifdef _LP64 + // If UseCompressedClassPointers is set then allocate the metaspace area + // above the heap and above the CDS area (if it exists). +diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp +index 3920004a8..2b06cb620 100644 +--- a/hotspot/src/share/vm/memory/metaspace.hpp ++++ b/hotspot/src/share/vm/memory/metaspace.hpp +@@ -82,6 +82,7 @@ class VirtualSpaceList; + // quantum of metadata. + + class Metaspace : public CHeapObj { ++ friend class ArchiveBuilder; + friend class VMStructs; + friend class SpaceManager; + friend class VM_CollectForMetadataAllocation; +diff --git a/hotspot/src/share/vm/memory/metaspaceClosure.cpp b/hotspot/src/share/vm/memory/metaspaceClosure.cpp +new file mode 100644 +index 000000000..00ec8fced +--- /dev/null ++++ b/hotspot/src/share/vm/memory/metaspaceClosure.cpp +@@ -0,0 +1,87 @@ ++#include "precompiled.hpp" ++#include "memory/metaspaceClosure.hpp" ++ ++// Update the reference to point to new_loc. ++void MetaspaceClosure::Ref::update(address new_loc) const { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Ref: [" PTR_FORMAT "] -> " PTR_FORMAT " => " PTR_FORMAT, ++ p2i(mpp()), p2i(obj()), p2i(new_loc)); ++ } ++ uintx p = (uintx)new_loc; ++ p |= flag_bits(); // Make sure the flag bits are copied to the new pointer. ++ *(address*)mpp() = (address)p; ++} ++ ++void MetaspaceClosure::push_impl(MetaspaceClosure::Ref* ref) { ++ if (_nest_level < MAX_NEST_LEVEL) { ++ do_push(ref); ++ if (!ref->keep_after_pushing()) { ++ delete ref; ++ } ++ } else { ++ do_pending_ref(ref); ++ ref->set_next(_pending_refs); ++ _pending_refs = ref; ++ } ++} ++ ++void MetaspaceClosure::do_push(MetaspaceClosure::Ref* ref) { ++ if (ref->not_null()) { ++ bool read_only; ++ Writability w = ref->writability(); ++ switch (w) { ++ case _writable: ++ read_only = false; ++ break; ++ case _not_writable: ++ read_only = true; ++ break; ++ default: ++ assert(w == _default, "must be"); ++ read_only = ref->is_read_only_by_default(); ++ } ++ if (_nest_level == 0) { ++ assert(_enclosing_ref == NULL, "must be"); ++ } ++ _nest_level ++; ++ if (do_ref(ref, read_only)) { // true means we want to iterate the embedded pointer in ++ Ref* saved = _enclosing_ref; ++ _enclosing_ref = ref; ++ ref->metaspace_pointers_do(this); ++ _enclosing_ref = saved; ++ } ++ _nest_level --; ++ } ++} ++ ++void MetaspaceClosure::finish() { ++ assert(_nest_level == 0, "must be"); ++ while (_pending_refs != NULL) { ++ Ref* ref = _pending_refs; ++ _pending_refs = _pending_refs->next(); ++ do_push(ref); ++ if (!ref->keep_after_pushing()) { ++ delete ref; ++ } ++ } ++} ++ ++MetaspaceClosure::~MetaspaceClosure() { ++ assert(_pending_refs == NULL, ++ "you must explicitly call MetaspaceClosure::finish() to process all refs!"); ++} ++ ++bool UniqueMetaspaceClosure::do_ref(MetaspaceClosure::Ref* ref, bool read_only) { ++ bool created; ++ _has_been_visited.add_if_absent(ref->obj(), read_only, &created); ++ if (!created) { ++ return false; // Already visited: no need to iterate embedded pointers. ++ } else { ++ if (_has_been_visited.maybe_grow(MAX_TABLE_SIZE)) { ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Expanded _has_been_visited table to %d", _has_been_visited.table_size()); ++ } ++ } ++ return do_unique_ref(ref, read_only); ++ } ++} +diff --git a/hotspot/src/share/vm/memory/metaspaceClosure.hpp b/hotspot/src/share/vm/memory/metaspaceClosure.hpp +new file mode 100644 +index 000000000..f67d8d6fd +--- /dev/null ++++ b/hotspot/src/share/vm/memory/metaspaceClosure.hpp +@@ -0,0 +1,381 @@ ++ ++ ++#ifndef SHARE_VM_MEMORY_METASPACECLOSURE_HPP ++#define SHARE_VM_MEMORY_METASPACECLOSURE_HPP ++ ++#include "memory/allocation.hpp" ++#include "utilities/array.hpp" ++#include "utilities/globalDefinitions.hpp" ++#include "utilities/hashtable.hpp" ++ ++// The metadata hierarchy is separate from the oop hierarchy ++ class MetaspaceObj; // no C++ vtable ++//class Array; // no C++ vtable ++ class Annotations; // no C++ vtable ++ class ConstantPoolCache; // no C++ vtable ++ class ConstMethod; // no C++ vtable ++ class MethodCounters; // no C++ vtable ++ class Symbol; // no C++ vtable ++ class Metadata; // has C++ vtable (so do all subclasses) ++ class ConstantPool; ++ class MethodData; ++ class Method; ++ class Klass; ++ class InstanceKlass; ++ class InstanceMirrorKlass; ++ class InstanceClassLoaderKlass; ++ class InstanceRefKlass; ++ class ArrayKlass; ++ class ObjArrayKlass; ++ class TypeArrayKlass; ++ ++// class MetaspaceClosure -- ++// ++// This class is used for iterating the objects in the HotSpot Metaspaces. It ++// provides an API to walk all the reachable objects starting from a set of ++// root references (such as all Klass'es in the SystemDictionary). ++// ++// Currently it is used for compacting the CDS archive by eliminate temporary ++// objects allocated during archive creation time. See ArchiveBuilder for an example. ++// ++// To support MetaspaceClosure, each subclass of MetaspaceObj must provide ++// a method of the type void metaspace_pointers_do(MetaspaceClosure*). This method ++// should call MetaspaceClosure::push() on every pointer fields of this ++// class that points to a MetaspaceObj. See Annotations::metaspace_pointers_do() ++// for an example. ++ ++ ++class MetaspaceClosure : public StackObj { ++public: ++ enum Writability { ++ _writable, ++ _not_writable, ++ _default ++ }; ++ ++ enum SpecialRef { ++ _method_entry_ref ++ }; ++ ++ // class MetaspaceClosure::Ref -- ++ // ++ // MetaspaceClosure can be viewed as a very simple type of copying garbage ++ // collector. For it to function properly, it requires each subclass of ++ // MetaspaceObj to provide two methods: ++ // ++ // size_t size(); -- to determine how much data to copy ++ // void metaspace_pointers_do(MetaspaceClosure*); -- to locate all the embedded pointers ++ // ++ // Calling these methods would be trivial if these two were virtual methods. ++ // However, to save space, MetaspaceObj has NO vtable. The vtable is introduced ++ // only in the Metadata class. ++ // ++ // To work around the lack of a vtable, we use the Ref class with templates ++ // (see MSORef, OtherArrayRef, MSOArrayRef, and MSOPointerArrayRef) ++ // so that we can statically discover the type of a object. The use of Ref ++ // depends on the fact that: ++ // ++ // [1] We don't use polymorphic pointers for MetaspaceObj's that are not subclasses ++ // of Metadata. I.e., we don't do this: ++ // class Klass { ++ // MetaspaceObj *_obj; ++ // Array* foo() { return (Array*)_obj; } ++ // Symbol* bar() { return (Symbol*) _obj; } ++ // ++ // [2] All Array dimensions are statically declared. ++ class Ref : public CHeapObj { ++ Writability _writability; ++ bool _keep_after_pushing; ++ Ref* _next; ++ void* _user_data; ++ ++ protected: ++ virtual void** mpp() const = 0; ++ Ref(Writability w) : _writability(w), _keep_after_pushing(false), _next(NULL), _user_data(NULL) {} ++ public: ++ virtual bool not_null() const = 0; ++ virtual int size() const = 0; ++ virtual void metaspace_pointers_do(MetaspaceClosure *it) const = 0; ++ virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const = 0; ++ virtual MetaspaceObj::Type msotype() const = 0; ++ virtual bool is_read_only_by_default() const = 0; ++ virtual ~Ref() {} ++ ++ address obj() const { ++ // In some rare cases (see CPSlot in constantPool.hpp) we store some flags in the lowest ++ // 2 bits of a MetaspaceObj pointer. Unmask these when manipulating the pointer. ++ uintx p = (uintx)*mpp(); ++ return (address)(p & (~FLAG_MASK)); ++ } ++ ++ address* addr() const { ++ return (address*)mpp(); ++ } ++ ++ void update(address new_loc) const; ++ ++ Writability writability() const { return _writability; }; ++ void set_keep_after_pushing() { _keep_after_pushing = true; } ++ bool keep_after_pushing() { return _keep_after_pushing; } ++ void set_user_data(void* data) { _user_data = data; } ++ void* user_data() { return _user_data; } ++ void set_next(Ref* n) { _next = n; } ++ Ref* next() const { return _next; } ++ ++ private: ++ static const uintx FLAG_MASK = 0x03; ++ ++ int flag_bits() const { ++ uintx p = (uintx)*mpp(); ++ return (int)(p & FLAG_MASK); ++ } ++ }; ++ ++private: ++ // MSORef -- iterate an instance of MetaspaceObj ++ template class MSORef : public Ref { ++ T** _mpp; ++ T* dereference() const { ++ return *_mpp; ++ } ++ protected: ++ virtual void** mpp() const { ++ return (void**)_mpp; ++ } ++ ++ public: ++ MSORef(T** mpp, Writability w) : Ref(w), _mpp(mpp) {} ++ ++ virtual bool is_read_only_by_default() const { return T::is_read_only_by_default(); } ++ virtual bool not_null() const { return dereference() != NULL; } ++ virtual int size() const { return dereference()->size(); } ++ virtual MetaspaceObj::Type msotype() const { return dereference()->type(); } ++ ++ virtual void metaspace_pointers_do(MetaspaceClosure *it) const { ++ dereference()->metaspace_pointers_do(it); ++ } ++ virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const { ++ ((T*)new_loc)->metaspace_pointers_do(it); ++ } ++ }; ++ ++ // abstract base class for MSOArrayRef, MSOPointerArrayRef and OtherArrayRef ++ template class ArrayRef : public Ref { ++ Array** _mpp; ++ protected: ++ Array* dereference() const { ++ return *_mpp; ++ } ++ virtual void** mpp() const { ++ return (void**)_mpp; ++ } ++ ++ ArrayRef(Array** mpp, Writability w) : Ref(w), _mpp(mpp) {} ++ ++ // all Arrays are read-only by default ++ virtual bool is_read_only_by_default() const { return true; } ++ virtual bool not_null() const { return dereference() != NULL; } ++ virtual int size() const { return dereference()->size(); } ++ virtual MetaspaceObj::Type msotype() const { return MetaspaceObj::array_type(sizeof(T)); } ++ }; ++ ++ // OtherArrayRef -- iterate an instance of Array, where T is NOT a subtype of MetaspaceObj. ++ // T can be a primitive type, such as int, or a structure. However, we do not scan ++ // the fields inside T, so you should not embed any pointers inside T. ++ template class OtherArrayRef : public ArrayRef { ++ public: ++ OtherArrayRef(Array** mpp, Writability w) : ArrayRef(mpp, w) {} ++ ++ virtual void metaspace_pointers_do(MetaspaceClosure *it) const { ++ Array* array = ArrayRef::dereference(); ++ if (TraceDynamicCDS) ++ dynamic_cds_log->print_cr("Iter(OtherArray): %p [%d]", array, array->length()); ++ } ++ virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const { ++ Array* array = (Array*)new_loc; ++ if (TraceDynamicCDS) ++ dynamic_cds_log->print_cr("Iter(OtherArray): %p [%d]", array, array->length()); ++ } ++ }; ++ ++ // MSOArrayRef -- iterate an instance of Array, where T is a subtype of MetaspaceObj. ++ // We recursively call T::metaspace_pointers_do() for each element in this array. ++ template class MSOArrayRef : public ArrayRef { ++ public: ++ MSOArrayRef(Array** mpp, Writability w) : ArrayRef(mpp, w) {} ++ ++ virtual void metaspace_pointers_do(MetaspaceClosure *it) const { ++ metaspace_pointers_do_at_impl(it, ArrayRef::dereference()); ++ } ++ virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const { ++ metaspace_pointers_do_at_impl(it, (Array*)new_loc); ++ } ++ private: ++ void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array* array) const { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Iter(MSOArray): %p [%d]", array, array->length()); ++ } ++ for (int i = 0; i < array->length(); i++) { ++ T* elm = array->adr_at(i); ++ elm->metaspace_pointers_do(it); ++ } ++ } ++ }; ++ ++ // MSOPointerArrayRef -- iterate an instance of Array, where T is a subtype of MetaspaceObj. ++ // We recursively call MetaspaceClosure::push() for each pointer in this array. ++ template class MSOPointerArrayRef : public ArrayRef { ++ public: ++ MSOPointerArrayRef(Array** mpp, Writability w) : ArrayRef(mpp, w) {} ++ ++ virtual void metaspace_pointers_do(MetaspaceClosure *it) const { ++ metaspace_pointers_do_at_impl(it, ArrayRef::dereference()); ++ } ++ virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const { ++ metaspace_pointers_do_at_impl(it, (Array*)new_loc); ++ } ++ private: ++ void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array* array) const { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Iter(MSOPointerArray): %p [%d]", array, array->length()); ++ } ++ for (int i = 0; i < array->length(); i++) { ++ T** mpp = array->adr_at(i); ++ it->push(mpp); ++ } ++ } ++ }; ++ ++ // Normally, chains of references like a->b->c->d are iterated recursively. However, ++ // if recursion is too deep, we save the Refs in _pending_refs, and push them later in ++ // MetaspaceClosure::finish(). This avoids overflowing the C stack. ++ static const int MAX_NEST_LEVEL = 5; ++ Ref* _pending_refs; ++ int _nest_level; ++ Ref* _enclosing_ref; ++ ++ void push_impl(Ref* ref); ++ void do_push(Ref* ref); ++ ++public: ++ MetaspaceClosure(): _pending_refs(NULL), _nest_level(0), _enclosing_ref(NULL) {} ++ ~MetaspaceClosure(); ++ ++ void finish(); ++ ++ // enclosing_ref() is used to compute the offset of a field in a C++ class. For example ++ // class Foo { intx scala; Bar* ptr; } ++ // Foo *f = 0x100; ++ // when the f->ptr field is iterated with do_ref() on 64-bit platforms, we will have ++ // do_ref(Ref* r) { ++ // r->addr() == 0x108; // == &f->ptr; ++ // enclosing_ref()->obj() == 0x100; // == foo ++ // So we know that we are iterating upon a field at offset 8 of the object at 0x100. ++ // ++ // Note that if we have stack overflow, do_pending_ref(r) will be called first and ++ // do_ref(r) will be called later, for the same r. In this case, enclosing_ref() is valid only ++ // when do_pending_ref(r) is called, and will return NULL when do_ref(r) is called. ++ Ref* enclosing_ref() const { ++ return _enclosing_ref; ++ } ++ ++ // This is called when a reference is placed in _pending_refs. Override this ++ // function if you're using enclosing_ref(). See notes above. ++ virtual void do_pending_ref(Ref* ref) {} ++ ++ // returns true if we want to keep iterating the pointers embedded inside ++ virtual bool do_ref(Ref* ref, bool read_only) = 0; ++ ++private: ++ template ++ void push_with_ref(T** mpp, Writability w) { ++ push_impl(new REF_TYPE(mpp, w)); ++ } ++ ++public: ++ // When MetaspaceClosure::push(...) is called, pick the correct Ref subtype to handle it: ++ // ++ // MetaspaceClosure* it = ...; ++ // Klass* o = ...; it->push(&o); => MSORef ++ // Array* a1 = ...; it->push(&a1); => OtherArrayRef ++ // Array* a2 = ...; it->push(&a2); => MSOArrayRef ++ // Array* a3 = ...; it->push(&a3); => MSOPointerArrayRef ++ // Array*>* a4 = ...; it->push(&a4); => MSOPointerArrayRef ++ // Array* a5 = ...; it->push(&a5); => MSOPointerArrayRef ++ // ++ // Note that the following will fail to compile (to prevent you from adding new fields ++ // into the MetaspaceObj subtypes that cannot be properly copied by CDS): ++ // ++ // Hashtable* h = ...; it->push(&h); => Hashtable is not a subclass of MetaspaceObj ++ // Array* a6 = ...; it->push(&a6); => Hashtable is not a subclass of MetaspaceObj ++ // Array* a7 = ...; it->push(&a7); => int is not a subclass of MetaspaceObj ++ ++ template ++ void push(T** mpp, Writability w = _default) { ++ push_with_ref >(mpp, w); ++ } ++ ++ void push(Array** mpp, Writability w = _default) { ++ push_with_ref >(mpp, w); ++ } ++ ++ void push(Array** mpp, Writability w = _default) { ++ push_with_ref >(mpp, w); ++ } ++ ++ void push(Array** mpp, Writability w = _default) { ++ push_with_ref >(mpp, w); ++ } ++ ++ void push(Array** mpp, Writability w = _default) { ++ push_with_ref >(mpp, w); ++ } ++ ++ void push(Array** mpp, Writability w = _default) { ++ push_with_ref >(mpp, w); ++ } ++ ++ template ++ void push(Array** mpp, Writability w = _default) { ++ push_with_ref >(mpp, w); ++ } ++ ++ template ++ void push(Array** mpp, Writability w = _default) { ++ push_with_ref >(mpp, w); ++ } ++ ++#if 0 ++ // Enable this block if you're changing the push(...) methods, to test for types that should be ++ // disallowed. Each of the following "push" calls should result in a compile-time error. ++ void test_disallowed_types(MetaspaceClosure* it) { ++ Hashtable* h = NULL; ++ it->push(&h); ++ ++ Array*>* a6 = NULL; ++ it->push(&a6); ++ ++ Array* a7 = NULL; ++ it->push(&a7); ++ } ++#endif ++}; ++ ++// This is a special MetaspaceClosure that visits each unique MetaspaceObj once. ++class UniqueMetaspaceClosure : public MetaspaceClosure { ++ static const int INITIAL_TABLE_SIZE = 15889; ++ static const int MAX_TABLE_SIZE = 1000000; ++ ++ // Do not override. Returns true if we are discovering ref->obj() for the first time. ++ virtual bool do_ref(Ref* ref, bool read_only); ++ ++public: ++ // Gets called the first time we discover an object. ++ virtual bool do_unique_ref(Ref* ref, bool read_only) = 0; ++ UniqueMetaspaceClosure() : _has_been_visited(INITIAL_TABLE_SIZE) {} ++ ++private: ++ KVHashtable _has_been_visited; ++}; ++ ++#endif // SHARE_MEMORY_METASPACECLOSURE_HPP +diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp +index 9857b7577..00fb9fe91 100644 +--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp ++++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp +@@ -38,6 +38,7 @@ + #include "memory/metaspaceShared.hpp" + #include "oops/objArrayOop.hpp" + #include "oops/oop.inline.hpp" ++#include "runtime/arguments.hpp" + #include "runtime/signature.hpp" + #include "runtime/vm_operations.hpp" + #include "runtime/vmThread.hpp" +@@ -47,14 +48,17 @@ + PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC + + int MetaspaceShared::_max_alignment = 0; +- + ReservedSpace* MetaspaceShared::_shared_rs = NULL; ++char* MetaspaceShared::_requested_base_address; + + bool MetaspaceShared::_link_classes_made_progress; + bool MetaspaceShared::_check_classes_made_progress; + bool MetaspaceShared::_has_error_classes; + bool MetaspaceShared::_archive_loading_failed = false; + bool MetaspaceShared::_remapped_readwrite = false; ++void* MetaspaceShared::_shared_metaspace_static_bottom = NULL; ++void* MetaspaceShared::_shared_metaspace_dynamic_base = NULL; ++void* MetaspaceShared::_shared_metaspace_dynamic_top = NULL; + // Read/write a data stream for restoring/preserving metadata pointers and + // miscellaneous data from/to the shared archive file. + +@@ -843,7 +847,7 @@ int MetaspaceShared::preload_and_dump(const char * class_list_path, + + // Returns true if the class's status has changed + bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) { +- assert(DumpSharedSpaces, "should only be called during dumping"); ++// assert(DumpSharedSpaces, "should only be called during dumping"); + if (ik->init_state() < InstanceKlass::linked) { + bool saved = BytecodeVerificationLocal; + if (!SharedClassUtil::is_shared_boot_class(ik)) { +@@ -862,6 +866,7 @@ bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) { + tty->print_cr("Preload Warning: Verification failed for %s", + ik->external_name()); + CLEAR_PENDING_EXCEPTION; ++ SystemDictionaryShared::set_class_has_failed_verification(ik); + ik->set_in_error_state(); + _has_error_classes = true; + } +@@ -902,6 +907,11 @@ public: + FileMapInfo::assert_mark(tag == old_tag); + } + ++ void do_u4(u4* p) { ++ intptr_t obj = nextPtr(); ++ *p = (u4)(uintx(obj)); ++ } ++ + void do_region(u_char* start, size_t size) { + assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment"); + assert(size % sizeof(intptr_t) == 0, "bad size"); +@@ -918,7 +928,10 @@ public: + + // Return true if given address is in the mapped shared space. + bool MetaspaceShared::is_in_shared_space(const void* p) { +- return UseSharedSpaces && FileMapInfo::current_info()->is_in_shared_space(p); ++ return UseSharedSpaces && ((FileMapInfo::current_info() != NULL && ++ FileMapInfo::current_info()->is_mapped() && ++ FileMapInfo::current_info()->is_in_shared_space(p)) || ++ is_shared_dynamic(p)); + } + + void MetaspaceShared::print_shared_spaces() { +@@ -927,19 +940,34 @@ void MetaspaceShared::print_shared_spaces() { + } + } + +- + // Map shared spaces at requested addresses and return if succeeded. + // Need to keep the bounds of the ro and rw space for the Metaspace::contains + // call, or is_in_shared_space. + bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { + size_t image_alignment = mapinfo->alignment(); + ++ mapinfo->set_is_mapped(false); ++ + #ifndef _WINDOWS + // Map in the shared memory and then map the regions on top of it. + // On Windows, don't map the memory here because it will cause the + // mappings of the regions to fail. + ReservedSpace shared_rs = mapinfo->reserve_shared_memory(); +- if (!shared_rs.is_reserved()) return false; ++ if (!shared_rs.is_reserved()) { ++ FileMapInfo::fail_continue("Unable to reserve shared memory"); ++ FLAG_SET_DEFAULT(UseSharedSpaces, false); ++ return false; ++ } ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Reserved archive_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (" SIZE_FORMAT ") bytes", ++ p2i(shared_rs.base()), p2i(shared_rs.base() + shared_rs.size()), shared_rs.size()); ++ } ++ if (mapinfo->is_static()) { ++ _requested_base_address = shared_rs.base(); ++ } else { ++ _shared_metaspace_dynamic_base = shared_rs.base(); ++ _shared_metaspace_dynamic_top = shared_rs.base() + shared_rs.size(); ++ } + #endif + + assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces"); +@@ -950,40 +978,79 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { + char* _mc_base = NULL; + + // Map each shared region +- if ((_ro_base = mapinfo->map_region(ro)) != NULL && +- mapinfo->verify_region_checksum(ro) && +- (_rw_base = mapinfo->map_region(rw)) != NULL && +- mapinfo->verify_region_checksum(rw) && +- (_md_base = mapinfo->map_region(md)) != NULL && +- mapinfo->verify_region_checksum(md) && +- (_mc_base = mapinfo->map_region(mc)) != NULL && +- mapinfo->verify_region_checksum(mc) && +- (image_alignment == (size_t)max_alignment()) && +- mapinfo->validate_classpath_entry_table()) { +- // Success (no need to do anything) +- return true; ++ if (mapinfo->is_static()) { ++ if ((_ro_base = mapinfo->map_region(ro)) != NULL && ++ mapinfo->verify_region_checksum(ro) && ++ (_rw_base = mapinfo->map_region(rw)) != NULL && ++ mapinfo->verify_region_checksum(rw) && ++ (_md_base = mapinfo->map_region(md)) != NULL && ++ mapinfo->verify_region_checksum(md) && ++ (_mc_base = mapinfo->map_region(mc)) != NULL && ++ mapinfo->verify_region_checksum(mc) && ++ (image_alignment == (size_t)max_alignment()) && ++ mapinfo->validate_classpath_entry_table()) { ++ mapinfo->set_is_mapped(true); ++ return true; ++ } + } else { +- // If there was a failure in mapping any of the spaces, unmap the ones +- // that succeeded +- if (_ro_base != NULL) mapinfo->unmap_region(ro); +- if (_rw_base != NULL) mapinfo->unmap_region(rw); +- if (_md_base != NULL) mapinfo->unmap_region(md); +- if (_mc_base != NULL) mapinfo->unmap_region(mc); ++ if ((_rw_base = mapinfo->map_region(d_rw)) != NULL && ++ mapinfo->verify_region_checksum(d_rw) && ++ (_ro_base = mapinfo->map_region(d_ro)) != NULL && ++ mapinfo->verify_region_checksum(d_ro) && ++ (image_alignment == (size_t)max_alignment())) { ++ mapinfo->set_is_mapped(true); ++ return true; ++ } ++ } ++ ++ // If there was a failure in mapping any of the spaces, unmap the ones ++ // that succeeded ++ if (_ro_base != NULL) mapinfo->unmap_region(ro); ++ if (_rw_base != NULL) mapinfo->unmap_region(rw); ++ if (_md_base != NULL) mapinfo->unmap_region(md); ++ if (_mc_base != NULL) mapinfo->unmap_region(mc); + #ifndef _WINDOWS +- // Release the entire mapped region +- shared_rs.release(); ++ // Release the entire mapped region ++ shared_rs.release(); + #endif +- // If -Xshare:on is specified, print out the error message and exit VM, +- // otherwise, set UseSharedSpaces to false and continue. +- if (RequireSharedSpaces || PrintSharedArchiveAndExit) { +- vm_exit_during_initialization("Unable to use shared archive.", "Failed map_region for using -Xshare:on."); +- } else { +- FLAG_SET_DEFAULT(UseSharedSpaces, false); +- } +- return false; ++ // If -Xshare:on is specified, print out the error message and exit VM, ++ // otherwise, set UseSharedSpaces to false and continue. ++ if (RequireSharedSpaces || PrintSharedArchiveAndExit) { ++ vm_exit_during_initialization("Unable to use shared archive.", "Failed map_region for using -Xshare:on."); ++ } else { ++ FLAG_SET_DEFAULT(UseSharedSpaces, false); + } ++ return false; + } + ++void** MetaspaceShared::_vtbl_list = NULL; ++ ++intptr_t* MetaspaceShared::get_archived_vtable(MetaspaceObj::Type msotype, address obj) { ++ Arguments::assert_is_dumping_archive(); ++ switch (msotype) { ++ case MetaspaceObj::SymbolType: ++ case MetaspaceObj::TypeArrayU1Type: ++ case MetaspaceObj::TypeArrayU2Type: ++ case MetaspaceObj::TypeArrayU4Type: ++ case MetaspaceObj::TypeArrayU8Type: ++ case MetaspaceObj::TypeArrayOtherType: ++ case MetaspaceObj::ConstMethodType: ++ case MetaspaceObj::ConstantPoolCacheType: ++ case MetaspaceObj::AnnotationType: ++ case MetaspaceObj::MethodCountersType: ++ // These have no vtables. ++ break; ++ case MetaspaceObj::MethodDataType: ++ // We don't archive MethodData <-- should have been removed in removed_unsharable_info ++ ShouldNotReachHere(); ++ break; ++ default: ++ int vtable_offset = MetaspaceShared::vtbl_list_size * sizeof(void*) + sizeof(intptr_t); ++ char* vtable_start = (char*)_vtbl_list + vtable_offset; ++ return (intptr_t*)find_matching_vtbl_ptr(_vtbl_list, (void*)vtable_start, obj); ++ } ++ return NULL; ++} + // Read the miscellaneous data from the shared file, and + // serialize it out to its various destinations. + +@@ -996,6 +1063,7 @@ void MetaspaceShared::initialize_shared_spaces() { + // for Klass objects. They get filled in later. + + void** vtbl_list = (void**)buffer; ++ _vtbl_list = vtbl_list; + buffer += MetaspaceShared::vtbl_list_size * sizeof(void*); + Universe::init_self_patching_vtbl_list(vtbl_list, vtbl_list_size); + +@@ -1079,6 +1147,15 @@ void MetaspaceShared::initialize_shared_spaces() { + // Close the mapinfo file + mapinfo->close(); + ++ FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); ++ if (dynamic_mapinfo != NULL) { ++ intptr_t* buffer = (intptr_t*)dynamic_mapinfo->serialized_data(); ++ ReadClosure rc(&buffer); ++ SymbolTable::serialize_shared_table_header(&rc); ++ SystemDictionaryShared::serialize_dictionary_headers(&rc); ++ dynamic_mapinfo->close(); ++ } ++ + if (PrintSharedArchiveAndExit) { + if (PrintSharedDictionary) { + tty->print_cr("\nShared classes:\n"); +@@ -1104,6 +1181,11 @@ bool MetaspaceShared::remap_shared_readonly_as_readwrite() { + if (!mapinfo->remap_shared_readonly_as_readwrite()) { + return false; + } ++ ++ mapinfo = FileMapInfo::dynamic_info(); ++ if (mapinfo != NULL && !mapinfo->remap_shared_readonly_as_readwrite()) { ++ return false; ++ } + _remapped_readwrite = true; + } + return true; +diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp +index d58ebecb2..a9dadfbb9 100644 +--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp ++++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp +@@ -28,6 +28,7 @@ + #include "memory/memRegion.hpp" + #include "runtime/virtualspace.hpp" + #include "utilities/exceptions.hpp" ++#include "utilities/growableArray.hpp" + #include "utilities/macros.hpp" + + #define LargeSharedArchiveSize (300*M) +@@ -44,6 +45,7 @@ + (uintx)(type ## SharedArchiveSize * region ## RegionPercentage) : Shared ## region ## Size + + class FileMapInfo; ++class SerializeClosure; + + // Class Data Sharing Support + class MetaspaceShared : AllStatic { +@@ -56,6 +58,11 @@ class MetaspaceShared : AllStatic { + static bool _has_error_classes; + static bool _archive_loading_failed; + static bool _remapped_readwrite; ++ static void* _shared_metaspace_static_bottom; ++ static void** _vtbl_list; // Remember the vtable start address for dynamic dump metadata ++ static char* _requested_base_address; ++ static void* _shared_metaspace_dynamic_base; ++ static void* _shared_metaspace_dynamic_top; + public: + enum { + vtbl_list_size = 17, // number of entries in the shared space vtable list. +@@ -71,11 +78,20 @@ class MetaspaceShared : AllStatic { + }; + + enum { +- ro = 0, // read-only shared space in the heap +- rw = 1, // read-write shared space in the heap +- md = 2, // miscellaneous data for initializing tables, etc. +- mc = 3, // miscellaneous code - vtable replacement. +- n_regions = 4 ++ // core archive spaces ++ ro = 0, // read-only shared space in the heap ++ rw = 1, // read-write shared space in the heap ++ md = 2, // miscellaneous data for initializing tables, etc. (static only) ++ mc = 3, // miscellaneous code - vtable replacement. (static only) ++ n_regions = 4 // total number of static regions ++ }; ++ ++ enum { ++ // core dynamic archive spaces ++ d_rw = 0, // read-write shared space in the heap ++ d_ro = 1, // read-only shared space in the heap ++ d_bm = 2, // relocation bitmaps (freed after file mapping is finished) ++ d_n_regions = 2 // d_rw and d_ro + }; + + // Accessor functions to save shared space created for metadata, which has +@@ -108,6 +124,28 @@ class MetaspaceShared : AllStatic { + _archive_loading_failed = true; + } + static bool map_shared_spaces(FileMapInfo* mapinfo) NOT_CDS_RETURN_(false); ++ ++ static bool is_shared_dynamic(const void* p) { ++ return p < _shared_metaspace_dynamic_top && p >= _shared_metaspace_dynamic_base; ++ } ++ ++ // This is the base address as specified by -XX:SharedBaseAddress during -Xshare:dump. ++ // Both the base/top archives are written using this as their base address. ++ // ++ // During static dump: _requested_base_address == SharedBaseAddress. ++ // ++ // During dynamic dump: _requested_base_address is not always the same as SharedBaseAddress: ++ // - SharedBaseAddress is used for *reading the base archive*. I.e., CompactHashtable uses ++ // it to convert offsets to pointers to Symbols in the base archive. ++ // The base archive may be mapped to an OS-selected address due to ASLR. E.g., ++ // you may have SharedBaseAddress == 0x00ff123400000000. ++ // - _requested_base_address is used for *writing the output archive*. It's usually ++ // 0x800000000 (unless it was set by -XX:SharedBaseAddress during -Xshare:dump). ++ static char* requested_base_address() { ++ return _requested_base_address; ++ } ++ ++ static intptr_t* get_archived_vtable(MetaspaceObj::Type msotype, address obj); + static void initialize_shared_spaces() NOT_CDS_RETURN; + + // Return true if given address is in the mapped shared space. +@@ -138,5 +176,8 @@ class MetaspaceShared : AllStatic { + + static int count_class(const char* classlist_file); + static void estimate_regions_size() NOT_CDS_RETURN; ++ ++ static void set_shared_metaspace_static_bottom(void* bottom) { _shared_metaspace_static_bottom = bottom; } ++ static void* shared_metaspace_static_bottom() { return _shared_metaspace_static_bottom; } + }; + #endif // SHARE_VM_MEMORY_METASPACE_SHARED_HPP +diff --git a/hotspot/src/share/vm/oops/annotations.cpp b/hotspot/src/share/vm/oops/annotations.cpp +index 776b8606b..6b3080f17 100644 +--- a/hotspot/src/share/vm/oops/annotations.cpp ++++ b/hotspot/src/share/vm/oops/annotations.cpp +@@ -27,6 +27,7 @@ + #include "memory/heapInspection.hpp" + #include "memory/metadataFactory.hpp" + #include "memory/oopFactory.hpp" ++#include "memory/metaspaceClosure.hpp" + #include "oops/annotations.hpp" + #include "oops/instanceKlass.hpp" + #include "utilities/ostream.hpp" +@@ -36,6 +37,17 @@ Annotations* Annotations::allocate(ClassLoaderData* loader_data, TRAPS) { + return new (loader_data, size(), true, MetaspaceObj::AnnotationType, THREAD) Annotations(); + } + ++void Annotations::metaspace_pointers_do(MetaspaceClosure* it) { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Iter(Annotations): %p", this); ++ } ++ ++ it->push(&_class_annotations); ++ it->push(&_fields_annotations); ++ it->push(&_class_type_annotations); ++ it->push(&_fields_type_annotations); // FIXME: need a test case where _fields_type_annotations != NULL ++} ++ + // helper + void Annotations::free_contents(ClassLoaderData* loader_data, Array* p) { + if (p != NULL) { +diff --git a/hotspot/src/share/vm/oops/annotations.hpp b/hotspot/src/share/vm/oops/annotations.hpp +index ad405a8db..d1f7bc71b 100644 +--- a/hotspot/src/share/vm/oops/annotations.hpp ++++ b/hotspot/src/share/vm/oops/annotations.hpp +@@ -35,6 +35,7 @@ + class ClassLoaderData; + class outputStream; + class KlassSizeStats; ++class MetaspaceClosure; + + typedef Array AnnotationArray; + +@@ -54,6 +55,8 @@ class Annotations: public MetaspaceObj { + Array* _fields_type_annotations; + + public: ++ void metaspace_pointers_do(MetaspaceClosure* it); ++ + // Allocate instance of this class + static Annotations* allocate(ClassLoaderData* loader_data, TRAPS); + +@@ -61,8 +64,14 @@ class Annotations: public MetaspaceObj { + void deallocate_contents(ClassLoaderData* loader_data); + DEBUG_ONLY(bool on_stack() { return false; }) // for template + ++ // Annotations should be stored in the read-only region of CDS archive. ++ static bool is_read_only_by_default() { return true; } ++ ++ MetaspaceObj::Type type() const { return AnnotationType; } ++ + // Sizing (in words) + static int size() { return sizeof(Annotations) / wordSize; } ++ + #if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; + #endif +diff --git a/hotspot/src/share/vm/oops/arrayKlass.cpp b/hotspot/src/share/vm/oops/arrayKlass.cpp +index 129bce63d..9009d6972 100644 +--- a/hotspot/src/share/vm/oops/arrayKlass.cpp ++++ b/hotspot/src/share/vm/oops/arrayKlass.cpp +@@ -30,6 +30,7 @@ + #include "jvmtifiles/jvmti.h" + #include "memory/gcLocker.hpp" + #include "memory/universe.inline.hpp" ++#include "memory/metaspaceClosure.hpp" + #include "oops/arrayKlass.hpp" + #include "oops/arrayOop.hpp" + #include "oops/instanceKlass.hpp" +@@ -64,6 +65,19 @@ oop ArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) { + return NULL; + } + ++void ArrayKlass::metaspace_pointers_do(MetaspaceClosure* it) { ++ Klass::metaspace_pointers_do(it); ++ ++ if (TraceDynamicCDS) { ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("Iter(InstanceKlass): %p (%s)", this, external_name()); ++ } ++ ++ // need to cast away volatile ++ it->push((Klass**)&_higher_dimension); ++ it->push((Klass**)&_lower_dimension); ++} ++ + // find field according to JVM spec 5.4.3.2, returns the klass in which the field is defined + Klass* ArrayKlass::find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const { + // There are no fields in an array klass but look to the super class (Object) +@@ -203,6 +217,14 @@ void ArrayKlass::remove_unshareable_info() { + _higher_dimension = NULL; + } + ++void ArrayKlass::remove_java_mirror() { ++ Klass::remove_java_mirror(); ++ if (_higher_dimension != NULL) { ++ ArrayKlass *ak = ArrayKlass::cast(higher_dimension()); ++ ak->remove_java_mirror(); ++ } ++} ++ + void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { + assert(loader_data == ClassLoaderData::the_null_class_loader_data(), "array classes belong to null loader"); + Klass::restore_unshareable_info(loader_data, protection_domain, CHECK); +diff --git a/hotspot/src/share/vm/oops/arrayKlass.hpp b/hotspot/src/share/vm/oops/arrayKlass.hpp +index d28ece376..9b6fd9e0b 100644 +--- a/hotspot/src/share/vm/oops/arrayKlass.hpp ++++ b/hotspot/src/share/vm/oops/arrayKlass.hpp +@@ -100,7 +100,7 @@ class ArrayKlass: public Klass { + + GrowableArray* compute_secondary_supers(int num_extra_slots); + bool compute_is_subtype_of(Klass* k); +- ++ virtual void metaspace_pointers_do(MetaspaceClosure* it); + // Sizing + static int header_size() { return sizeof(ArrayKlass)/HeapWordSize; } + static int static_size(int header_size); +@@ -141,6 +141,7 @@ class ArrayKlass: public Klass { + + // CDS support - remove and restore oops from metadata. Oops are not shared. + virtual void remove_unshareable_info(); ++ virtual void remove_java_mirror(); + virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS); + + // Printing +diff --git a/hotspot/src/share/vm/oops/constMethod.cpp b/hotspot/src/share/vm/oops/constMethod.cpp +index a496149df..fc7d74512 100644 +--- a/hotspot/src/share/vm/oops/constMethod.cpp ++++ b/hotspot/src/share/vm/oops/constMethod.cpp +@@ -26,6 +26,7 @@ + #include "interpreter/interpreter.hpp" + #include "memory/gcLocker.hpp" + #include "memory/heapInspection.hpp" ++#include "memory/metaspaceClosure.hpp" + #include "memory/metadataFactory.hpp" + #include "oops/constMethod.hpp" + #include "oops/method.hpp" +@@ -148,6 +149,31 @@ Method* ConstMethod::method() const { + return _constants->pool_holder()->method_with_idnum(_method_idnum); + } + ++void ConstMethod::metaspace_pointers_do(MetaspaceClosure* it) { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Iter(ConstMethod): %p", this); ++ } ++ ++ if (!method()->method_holder()->is_rewritten()) { ++ it->push(&_constants, MetaspaceClosure::_writable); ++ } else { ++ it->push(&_constants); ++ } ++ it->push(&_stackmap_data); ++ if (has_method_annotations()) { ++ it->push(method_annotations_addr()); ++ } ++ if (has_parameter_annotations()) { ++ it->push(parameter_annotations_addr()); ++ } ++ if (has_type_annotations()) { ++ it->push(type_annotations_addr()); ++ } ++ if (has_default_annotations()) { ++ it->push(default_annotations_addr()); ++ } ++} ++ + // linenumber table - note that length is unknown until decompression, + // see class CompressedLineNumberReadStream. + +diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp +index 0caa3a26f..20cff631e 100644 +--- a/hotspot/src/share/vm/oops/constMethod.hpp ++++ b/hotspot/src/share/vm/oops/constMethod.hpp +@@ -129,7 +129,7 @@ class MethodParametersElement VALUE_OBJ_CLASS_SPEC { + }; + + class KlassSizeStats; +- ++class MetaspaceClosure; + // Class to collect the sizes of ConstMethod inline tables + #define INLINE_TABLES_DO(do_element) \ + do_element(localvariable_table_length) \ +@@ -344,6 +344,12 @@ public: + // Size needed + static int size(int code_size, InlineTableSizes* sizes); + ++ // ConstMethods should be stored in the read-only region of CDS archive. ++ static bool is_read_only_by_default() { return true; } ++ ++ void metaspace_pointers_do(MetaspaceClosure* it); ++ MetaspaceObj::Type type() const { return ConstMethodType; } ++ + int size() const { return _constMethod_size;} + void set_constMethod_size(int size) { _constMethod_size = size; } + #if INCLUDE_SERVICES +diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp +index b6158e4e9..f8078bffa 100644 +--- a/hotspot/src/share/vm/oops/constantPool.cpp ++++ b/hotspot/src/share/vm/oops/constantPool.cpp +@@ -23,16 +23,19 @@ + */ + + #include "precompiled.hpp" ++#include "cds/archiveUtils.hpp" + #include "classfile/classLoaderData.hpp" + #include "classfile/javaClasses.hpp" + #include "classfile/metadataOnStackMark.hpp" + #include "classfile/symbolTable.hpp" + #include "classfile/systemDictionary.hpp" ++#include "classfile/systemDictionaryShared.hpp" + #include "classfile/vmSymbols.hpp" + #include "interpreter/linkResolver.hpp" + #include "memory/heapInspection.hpp" + #include "memory/metadataFactory.hpp" + #include "memory/oopFactory.hpp" ++#include "memory/metaspaceClosure.hpp" + #include "oops/constantPool.hpp" + #include "oops/instanceKlass.hpp" + #include "oops/objArrayKlass.hpp" +@@ -153,6 +156,52 @@ void ConstantPool::initialize_resolved_references(ClassLoaderData* loader_data, + } + } + ++void ConstantPool::metaspace_pointers_do(MetaspaceClosure* it) { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Iter(ConstantPool): %p", this); ++ } ++ ++ it->push(&_tags, MetaspaceClosure::_writable); ++ it->push(&_cache); ++ it->push(&_pool_holder); ++ it->push(&_operands); ++ it->push(&_reference_map, MetaspaceClosure::_writable); ++ ++ for (int i = 0; i < length(); i++) { ++ // About resolved klasses, we should be careful because of data structure difference ++ // between jdk8 and jdk17. ++ constantTag ctag = tag_at(i); ++ if (ctag.is_string() || ctag.is_utf8() || ctag.is_replaced_symbol()) { ++ it->push(symbol_at_addr(i)); ++ } else if (ctag.is_klass()) { ++ it->push((Klass**)obj_at_addr_raw(i)); ++ } ++ } ++} ++ ++// We replace data in base() by normal symbol in two conditions: ++// 1. resolved klass ++// The value is klass ptr, in remove_unshareable_info we need replace klass ptr by klass‘s ++// name. The klass may be excluded, hence klass ptr is NULL and lost klass'name ++// at the end. Replace excluded klasses by names. ++// 2. unresolved klass ++// The value is symbol ptr | 1, the data is unparseable pushed in MetaspaceClosure, we need ++// replace the data by a normal symbol ptr at first, and store value symbol ptr | 1 at last. ++void ConstantPool::symbol_replace_excluded_klass() { ++ for (int i = 0; i < length(); i++) { ++ constantTag ctag = tag_at(i); ++ if (ctag.is_klass()) { ++ Klass* klass = resolved_klass_at(i); ++ if (SystemDictionaryShared::is_excluded_class((InstanceKlass*)klass)) { ++ replaced_symbol_at_put(i, klass->name()); ++ } ++ } else if (ctag.is_unresolved_klass()) { ++ CPSlot entry = slot_at(i); ++ replaced_symbol_at_put(i, entry.get_symbol()); ++ } ++ } ++} ++ + // CDS support. Create a new resolved_references array. + void ConstantPool::restore_unshareable_info(TRAPS) { + +@@ -180,18 +229,30 @@ void ConstantPool::restore_unshareable_info(TRAPS) { + } + + void ConstantPool::remove_unshareable_info() { +- if (UseAppCDS) { +- if (cache() != NULL) { +- cache()->reset(); ++ if (cache() != NULL) { ++ cache()->remove_unshareable_info(); ++ } ++ ++ // Shared ConstantPools are in the RO region, so the _flags cannot be modified. ++ // The _on_stack flag is used to prevent ConstantPools from deallocation during ++ // class redefinition. Since shared ConstantPools cannot be deallocated anyway, ++ // we always set _on_stack to true to avoid having to change _flags during runtime. ++ _flags |= _on_stack; ++ int num_klasses = 0; ++ for (int index = 1; index < length(); index++) { // Index 0 is unused ++ if (tag_at(index).is_unresolved_klass_in_error()) { ++ tag_at_put(index, JVM_CONSTANT_UnresolvedClass); ++ } else if (tag_at(index).is_method_handle_in_error()) { ++ tag_at_put(index, JVM_CONSTANT_MethodHandle); ++ } else if (tag_at(index).is_method_type_in_error()) { ++ tag_at_put(index, JVM_CONSTANT_MethodType); + } +- for (int i = 0; i < _length; i++) { +- if (tag_at(i).is_klass()) { +- Klass* resolvedKlass = resolved_klass_at(i); +- ResourceMark rm; +- char* name = resolvedKlass->name()->as_C_string(); +- int len = strlen(name); +- unresolved_klass_at_put(i, resolvedKlass->name()); +- } ++ ++ if (tag_at(index).is_klass()) { ++ Klass* resolved_Klass = resolved_klass_at(index); ++ unresolved_klass_at_put(index, resolved_Klass->name()); ++ } else if (tag_at(index).is_replaced_symbol()) { ++ unresolved_klass_at_put(index, *symbol_at_addr(index)); + } + } + // Resolved references are not in the shared archive. +@@ -519,8 +580,14 @@ Klass* ConstantPool::klass_ref_at(int which, TRAPS) { + + + Symbol* ConstantPool::klass_name_at(int which) const { +- assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(), +- "Corrupted constant pool"); ++ // Dynamic CDS dump need call here in verify, release version no need do it. ++#ifndef PRODUCT ++ assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass() || ++ tag_at(which).is_replaced_symbol(), "Corrupted constant pool"); ++ if (tag_at(which).is_replaced_symbol()) { ++ return *symbol_at_addr(which); ++ } ++#endif + // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*. + // It is not safe to rely on the tag bit's here, since we don't have a lock, and the entry and + // tag is not updated atomicly. +diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp +index ec111df04..b5b4db38b 100644 +--- a/hotspot/src/share/vm/oops/constantPool.hpp ++++ b/hotspot/src/share/vm/oops/constantPool.hpp +@@ -231,6 +231,9 @@ class ConstantPool : public Metadata { + return cache()->entry_at(cp_cache_index); + } + ++ virtual void metaspace_pointers_do(MetaspaceClosure* it); ++ void symbol_replace_excluded_klass(); ++ virtual MetaspaceObj::Type type() const { return ConstantPoolType; } + // Assembly code support + static int tags_offset_in_bytes() { return offset_of(ConstantPool, _tags); } + static int cache_offset_in_bytes() { return offset_of(ConstantPool, _cache); } +@@ -315,6 +318,11 @@ class ConstantPool : public Metadata { + *symbol_at_addr(which) = s; + } + ++ void replaced_symbol_at_put(int which, Symbol*s) { ++ tag_at_put(which, JVM_CONSTANT_ReplacedSymbol); ++ *symbol_at_addr(which) = s; ++ } ++ + void string_at_put(int which, int obj_index, oop str) { + resolved_references()->obj_at_put(obj_index, str); + } +@@ -747,6 +755,10 @@ class ConstantPool : public Metadata { + void collect_statistics(KlassSizeStats *sz) const; + #endif + ++ // ConstantPools should be stored in the read-only region of CDS archive. ++ // But the vtable will be patched in JDK8, so it must be writable. ++ static bool is_read_only_by_default() { return false; } ++ + friend class ClassFileParser; + friend class SystemDictionary; + +diff --git a/hotspot/src/share/vm/oops/cpCache.cpp b/hotspot/src/share/vm/oops/cpCache.cpp +index ebcf3d6a9..51f5397b8 100644 +--- a/hotspot/src/share/vm/oops/cpCache.cpp ++++ b/hotspot/src/share/vm/oops/cpCache.cpp +@@ -24,14 +24,17 @@ + + #include "precompiled.hpp" + #include "gc_implementation/shared/markSweep.inline.hpp" ++#include "interpreter/bytecodeStream.hpp" + #include "interpreter/interpreter.hpp" + #include "interpreter/rewriter.hpp" + #include "memory/universe.inline.hpp" ++#include "memory/metaspaceClosure.hpp" + #include "oops/cpCache.hpp" + #include "oops/objArrayOop.hpp" + #include "oops/oop.inline.hpp" + #include "prims/jvmtiRedefineClassesTrace.hpp" + #include "prims/methodHandles.hpp" ++#include "runtime/arguments.hpp" + #include "runtime/handles.inline.hpp" + #include "runtime/orderAccess.inline.hpp" + #include "utilities/macros.hpp" +@@ -602,6 +605,72 @@ void ConstantPoolCache::initialize(const intArray& inverse_index_map, + } + } + ++void ConstantPoolCache::metaspace_pointers_do(MetaspaceClosure* it) { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Iter(ConstantPoolCache): %p", this); ++ } ++ it->push(&_constant_pool); ++ // it->push(&_reference_map); ++} ++ ++void ConstantPoolCache::remove_unshareable_info() { ++ walk_entries_for_initialization(/*check_only = */ false); ++} ++ ++void ConstantPoolCache::walk_entries_for_initialization(bool check_only) { ++ Arguments::assert_is_dumping_archive(); ++ // When dumping the archive, we want to clean up the ConstantPoolCache ++ // to remove any effect of linking due to the execution of Java code -- ++ // each ConstantPoolCacheEntry will have the same contents as if ++ // ConstantPoolCache::initialize has just returned: ++ // ++ // - We keep the ConstantPoolCache::constant_pool_index() bits for all entries. ++ // - We keep the "f2" field for entries used by invokedynamic and invokehandle ++ // - All other bits in the entries are cleared to zero. ++ ResourceMark rm; ++ ++ InstanceKlass* ik = constant_pool()->pool_holder(); ++ bool* f2_used = NEW_RESOURCE_ARRAY(bool, length()); ++ memset(f2_used, 0, sizeof(bool) * length()); ++ ++ Thread* current = Thread::current(); ++ ++ // Find all the slots that we need to preserve f2 ++ for (int i = 0; i < ik->methods()->length(); i++) { ++ Method* m = ik->methods()->at(i); ++ RawBytecodeStream bcs(methodHandle(current, m)); ++ while (!bcs.is_last_bytecode()) { ++ Bytecodes::Code opcode = bcs.raw_next(); ++ switch (opcode) { ++ case Bytecodes::_invokedynamic: { ++ int index = Bytes::get_native_u4(bcs.bcp() + 1); ++ int cp_cache_index = constant_pool()->invokedynamic_cp_cache_index(index); ++ f2_used[cp_cache_index] = 1; ++ } ++ break; ++ case Bytecodes::_invokehandle: { ++ int cp_cache_index = Bytes::get_native_u2(bcs.bcp() + 1); ++ f2_used[cp_cache_index] = 1; ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ ++ if (check_only) { ++ DEBUG_ONLY( ++ for (int i=0; iverify_just_initialized(f2_used[i]); ++ }) ++ } else { ++ for (int i=0; ireinitialize(f2_used[i]); ++ } ++ } ++} ++ + #if INCLUDE_JVMTI + // RedefineClasses() API support: + // If any entry of this ConstantPoolCache points to any of +diff --git a/hotspot/src/share/vm/oops/cpCache.hpp b/hotspot/src/share/vm/oops/cpCache.hpp +index 48f9bbd27..cb2fa43d6 100644 +--- a/hotspot/src/share/vm/oops/cpCache.hpp ++++ b/hotspot/src/share/vm/oops/cpCache.hpp +@@ -124,6 +124,7 @@ class PSPromotionManager; + // source code. The _indices field with the bytecode must be written last. + + class CallInfo; ++class MetaspaceClosure; + + class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; +@@ -397,6 +398,24 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { + // When shifting flags as a 32-bit int, make sure we don't need an extra mask for tos_state: + assert((((u4)-1 >> tos_state_shift) & ~tos_state_mask) == 0, "no need for tos_state mask"); + } ++ ++ void reinitialize(bool f2_used) { ++ _indices &= cp_index_mask; ++ _f1 = NULL; ++ _flags = 0; ++ if (!f2_used) { ++ _f2 = 0; ++ } ++ } ++ ++ void verify_just_initialized(bool f2_used) { ++ assert((_indices & (~cp_index_mask)) == 0, "sanity"); ++ assert(_f1 == NULL, "sanity"); ++ assert(_flags == 0, "sanity"); ++ if (!f2_used) { ++ assert(_f2 == 0, "sanity"); ++ } ++} + }; + + +@@ -468,6 +487,10 @@ class ConstantPoolCache: public MetaspaceObj { + return base() + i; + } + ++ void metaspace_pointers_do(MetaspaceClosure* it); ++ void remove_unshareable_info(); ++ void walk_entries_for_initialization(bool check_only); ++ MetaspaceObj::Type type() const { return ConstantPoolCacheType; } + // Code generation + static ByteSize base_offset() { return in_ByteSize(sizeof(ConstantPoolCache)); } + static ByteSize entry_offset(int raw_index) { +@@ -488,7 +511,7 @@ class ConstantPoolCache: public MetaspaceObj { + #endif // INCLUDE_JVMTI + + void reset(); +- ++ + // Deallocate - no fields to deallocate + DEBUG_ONLY(bool on_stack() { return false; }) + void deallocate_contents(ClassLoaderData* data) {} +diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp +index 367c9a09d..0d1b1a8d0 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.cpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.cpp +@@ -39,6 +39,7 @@ + #include "memory/iterator.inline.hpp" + #include "memory/metadataFactory.hpp" + #include "memory/oopFactory.hpp" ++#include "memory/metaspaceClosure.hpp" + #include "oops/fieldStreams.hpp" + #include "oops/instanceClassLoaderKlass.hpp" + #include "oops/instanceKlass.hpp" +@@ -53,6 +54,7 @@ + #include "prims/jvmtiRedefineClasses.hpp" + #include "prims/jvmtiThreadState.hpp" + #include "prims/methodComparator.hpp" ++#include "runtime/arguments.hpp" + #include "runtime/fieldDescriptor.hpp" + #include "runtime/handles.inline.hpp" + #include "runtime/javaCalls.hpp" +@@ -463,12 +465,73 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { + MetadataFactory::free_metadata(loader_data, annotations()); + } + set_annotations(NULL); ++ ++ if (Arguments::is_dumping_archive()) { ++ SystemDictionaryShared::remove_dumptime_info(this); ++ } + } + + bool InstanceKlass::should_be_initialized() const { + return !is_initialized(); + } + ++void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) { ++ Klass::metaspace_pointers_do(it); ++ ++ if (TraceDynamicCDS) { ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("Iter(InstanceKlass): %p (%s)", this, external_name()); ++ } ++ ++ it->push(&_annotations); ++ it->push((Klass**)&_array_klasses); ++ if (!is_rewritten()) { ++ it->push(&_constants, MetaspaceClosure::_writable); ++ } else { ++ it->push(&_constants); ++ } ++ it->push(&_inner_classes); ++#if INCLUDE_JVMTI ++ it->push(&_previous_versions); ++#endif ++ it->push(&_array_name); ++ it->push(&_methods); ++ it->push(&_default_methods); ++ it->push(&_local_interfaces); ++ it->push(&_transitive_interfaces); ++ it->push(&_method_ordering); ++ if (!is_rewritten()) { ++ it->push(&_default_vtable_indices, MetaspaceClosure::_writable); ++ } else { ++ it->push(&_default_vtable_indices); ++ } ++ ++ // _fields might be written into by Rewriter::scan_method() -> fd.set_has_initialized_final_update() ++ it->push(&_fields, MetaspaceClosure::_writable); ++ ++ if (itable_length() > 0) { ++ itableOffsetEntry* ioe = (itableOffsetEntry*)start_of_itable(); ++ int method_table_offset_in_words = ioe->offset()/wordSize; ++ int nof_interfaces = (method_table_offset_in_words - itable_offset_in_words()) ++ / itableOffsetEntry::size(); ++ ++ for (int i = 0; i < nof_interfaces; i ++, ioe ++) { ++ if (ioe->interface_klass() != NULL) { ++ it->push(ioe->interface_klass_addr()); ++ itableMethodEntry* ime = ioe->first_method_entry(this); ++ int n = klassItable::method_count_for_interface(ioe->interface_klass()); ++ for (int index = 0; index < n; index ++) { ++ it->push(ime[index].method_addr()); ++ } ++ } ++ } ++ } ++ ++ // it->push(&_nest_members); ++ // it->push(&_permitted_subclasses); ++ // it->push(&_record_components); ++} ++ + klassVtable* InstanceKlass::vtable() const { + return new klassVtable(this, start_of_vtable(), vtable_length() / vtableEntry::size()); + } +@@ -765,6 +828,28 @@ bool InstanceKlass::link_class_impl( + } + + ++// Check if a class or any of its supertypes has a version older than 50. ++// CDS will not perform verification of old classes during dump time because ++// without changing the old verifier, the verification constraint cannot be ++// retrieved during dump time. ++// Verification of archived old classes will be performed during run time. ++bool InstanceKlass::can_be_verified_at_dumptime() const { ++ if (major_version() < 50 /*JAVA_6_VERSION*/) { ++ return false; ++ } ++ if (java_super() != NULL && !java_super()->can_be_verified_at_dumptime()) { ++ return false; ++ } ++ Array* interfaces = local_interfaces(); ++ int len = interfaces->length(); ++ for (int i = 0; i < len; i++) { ++ if (!((InstanceKlass*)interfaces->at(i))->can_be_verified_at_dumptime()) { ++ return false; ++ } ++ } ++ return true; ++} ++ + // Rewrite the byte codes of all of the methods of a class. + // The rewriter must be called exactly once. Rewriting must happen after + // verification but before the first method of the class is executed. +@@ -1459,7 +1544,32 @@ static int linear_search(Array* methods, Symbol* name, Symbol* signatur + } + #endif + ++bool InstanceKlass::_disable_method_binary_search = false; ++ ++NOINLINE int linear_search(const Array* methods, const Symbol* name) { ++ int len = methods->length(); ++ int l = 0; ++ int h = len - 1; ++ while (l <= h) { ++ Method* m = methods->at(l); ++ if (m->name() == name) { ++ return l; ++ } ++ l++; ++ } ++ return -1; ++} ++ + static int binary_search(Array* methods, Symbol* name) { ++ if (InstanceKlass::_disable_method_binary_search) { ++ assert(DynamicDumpSharedSpaces, "must be"); ++ // At the final stage of dynamic dumping, the methods array may not be sorted ++ // by ascending addresses of their names, so we can't use binary search anymore. ++ // However, methods with the same name are still laid out consecutively inside the ++ // methods array, so let's look for the first one that matches. ++ return linear_search(methods, name); ++ } ++ + int len = methods->length(); + // methods are sorted, so do binary search + int l = 0; +@@ -2455,24 +2565,37 @@ void InstanceKlass::remove_unshareable_info() { + m->remove_unshareable_info(); + } + +- if (UseAppCDS) { ++ if (UseAppCDS || DynamicDumpSharedSpaces) { + if (_oop_map_cache != NULL) { + delete _oop_map_cache; + _oop_map_cache = NULL; + } +- ++ + JNIid::deallocate(jni_ids()); + set_jni_ids(NULL); +- ++ + jmethodID* jmeths = methods_jmethod_ids_acquire(); + if (jmeths != (jmethodID*)NULL) { + release_set_methods_jmethod_ids(NULL); + FreeHeap(jmeths); + } + } +- + // do array classes also. + array_klasses_do(remove_unshareable_in_class); ++ // These are not allocated from metaspace. They are safe to set to NULL. ++ _member_names = NULL; ++ _dependencies = NULL; ++ _osr_nmethods_head = NULL; ++ _init_thread = NULL; ++} ++ ++void InstanceKlass::remove_java_mirror() { ++ Klass::remove_java_mirror(); ++ ++ // do array classes also. ++ if (array_klasses() != NULL) { ++ array_klasses()->remove_java_mirror(); ++ } + } + + static void restore_unshareable_in_class(Klass* k, TRAPS) { +diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp +index 39d2c580c..43919e83d 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.hpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.hpp +@@ -323,6 +323,7 @@ class InstanceKlass: public Klass { + friend class SystemDictionary; + + public: ++ static bool _disable_method_binary_search; + bool has_nonstatic_fields() const { + return (_misc_flags & _misc_has_nonstatic_fields) != 0; + } +@@ -488,6 +489,7 @@ class InstanceKlass: public Klass { + void link_class(TRAPS); + bool link_class_or_fail(TRAPS); // returns false on failure + void unlink_class(); ++ bool can_be_verified_at_dumptime() const; + void rewrite_class(TRAPS); + void link_methods(TRAPS); + Method* class_initializer(); +@@ -525,6 +527,10 @@ class InstanceKlass: public Klass { + Method* find_method(Symbol* name, Symbol* signature) const; + static Method* find_method(Array* methods, Symbol* name, Symbol* signature); + ++ static void disable_method_binary_search() { ++ _disable_method_binary_search = true; ++ } ++ + // find a local method, but skip static methods + Method* find_instance_method(Symbol* name, Symbol* signature, + PrivateLookupMode private_mode); +@@ -1001,7 +1007,8 @@ class InstanceKlass: public Klass { + bool can_be_fastpath_allocated() const { + return !layout_helper_needs_slow_path(layout_helper()); + } +- ++ ++ virtual void metaspace_pointers_do(MetaspaceClosure* iter); + // Java vtable/itable + klassVtable* vtable() const; // return new klassVtable wrapper + inline Method* method_at_vtable(int index); +@@ -1075,7 +1082,7 @@ class InstanceKlass: public Klass { + + public: + void set_in_error_state() { +- assert(DumpSharedSpaces, "only call this when dumping archive"); ++ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "only call this when dumping archive"); + _init_state = initialization_error; + } + bool check_sharing_error_state(); +@@ -1150,6 +1157,7 @@ private: + public: + // CDS support - remove and restore oops from metadata. Oops are not shared. + virtual void remove_unshareable_info(); ++ virtual void remove_java_mirror(); + virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS); + + // jvm support +diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp +index 5269060a4..34d9d9895 100644 +--- a/hotspot/src/share/vm/oops/klass.cpp ++++ b/hotspot/src/share/vm/oops/klass.cpp +@@ -26,16 +26,19 @@ + #include "classfile/javaClasses.hpp" + #include "classfile/dictionary.hpp" + #include "classfile/systemDictionary.hpp" ++#include "classfile/systemDictionaryShared.hpp" + #include "classfile/vmSymbols.hpp" + #include "gc_implementation/shared/markSweep.inline.hpp" + #include "gc_interface/collectedHeap.inline.hpp" + #include "memory/heapInspection.hpp" + #include "memory/metadataFactory.hpp" ++#include "memory/metaspaceClosure.hpp" + #include "memory/oopFactory.hpp" + #include "memory/resourceArea.hpp" + #include "oops/instanceKlass.hpp" + #include "oops/klass.inline.hpp" + #include "oops/oop.inline2.hpp" ++#include "runtime/arguments.hpp" + #include "runtime/atomic.inline.hpp" + #include "runtime/orderAccess.inline.hpp" + #include "utilities/stack.hpp" +@@ -69,6 +72,10 @@ ClassLoaderData *Klass::_fake_loader_data_Ext = reinterpret_castincrement_refcount(); ++ ++ if (Arguments::is_dumping_archive() && oop_is_instance()) { ++ SystemDictionaryShared::init_dumptime_info(InstanceKlass::cast(this)); ++ } + } + + bool Klass::is_subclass_of(const Klass* k) const { +@@ -369,6 +376,36 @@ GrowableArray* Klass::compute_secondary_supers(int num_extra_slots) { + return NULL; + } + ++void Klass::metaspace_pointers_do(MetaspaceClosure* it) { ++ if (TraceDynamicCDS) { ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("Iter(Klass): %p (%s)", this, external_name()); ++ } ++ ++ it->push(&_name); ++ it->push(&_secondary_super_cache); ++ it->push(&_secondary_supers); ++ for (int i = 0; i < _primary_super_limit; i++) { ++ it->push(&_primary_supers[i]); ++ } ++ it->push(&_super); ++ it->push((Klass**)&_subklass); ++ it->push((Klass**)&_next_sibling); ++ it->push(&_next_link); ++ ++ vtableEntry* vt = start_of_vtable(); ++ for (int i = 0; i < vtable_length(); i++) { ++ it->push(vt[i].method_addr()); ++ } ++} ++ ++inline vtableEntry* Klass::start_of_vtable() const { ++ return (vtableEntry*) ((address)this + in_bytes(vtable_start_offset())); ++} ++ ++inline ByteSize Klass::vtable_start_offset() { ++ return in_ByteSize(InstanceKlass::header_size() * wordSize); ++} + + Klass* Klass::subklass() const { + return _subklass == NULL ? NULL : _subklass; +@@ -530,7 +567,7 @@ void Klass::oops_do(OopClosure* cl) { + } + + void Klass::remove_unshareable_info() { +- assert (DumpSharedSpaces, "only called for DumpSharedSpaces"); ++ assert (DumpSharedSpaces || DynamicDumpSharedSpaces, "only called for DumpSharedSpaces or DynamicDumpSharedSpaces"); + + JFR_ONLY(REMOVE_ID(this);) + set_subklass(NULL); +@@ -539,40 +576,46 @@ void Klass::remove_unshareable_info() { + set_java_mirror(NULL); + set_next_link(NULL); + +- if (!UseAppCDS) { +- // CDS logic ++ if (class_loader_data() == NULL) { ++ // Null out class loader data for classes loaded by bootstrap (null) loader ++ set_class_loader_data(NULL); ++ } else if (SystemDictionary::is_ext_class_loader(class_loader())) { ++ // Mark class loaded by system class loader ++ set_class_loader_data(_fake_loader_data_Ext); ++ } else if (SystemDictionary::is_app_class_loader(class_loader())) { ++ set_class_loader_data(_fake_loader_data_App); ++ } else { ++ // Class loader data for classes loaded by customer loader + set_class_loader_data(NULL); +- } else if (class_loader_data() != NULL) { +- // AppCDS logic +- if (class_loader() == NULL) { +- // Null out class loader data for classes loaded by bootstrap (null) loader +- set_class_loader_data(NULL); +- } else if(SystemDictionary::is_ext_class_loader(class_loader())) { +- // Mark class loaded by system class loader +- set_class_loader_data(_fake_loader_data_Ext); +- } else { +- set_class_loader_data(_fake_loader_data_App); +- } + } + } + ++void Klass::remove_java_mirror() { ++ Arguments::assert_is_dumping_archive(); ++ if (TraceDynamicCDS) { ++ ResourceMark rm; ++ dynamic_cds_log->print_cr("remove java_mirror: %s", external_name()); ++ } ++ // Just null out the mirror. The class_loader_data() no longer exists. ++ _java_mirror = NULL; ++} ++ + void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { + JFR_ONLY(RESTORE_ID(this);) ++ if (TraceDynamicCDS) { ++ ResourceMark rm(THREAD); ++ dynamic_cds_log->print_cr("restore: %s", external_name()); ++ } ++ + // If an exception happened during CDS restore, some of these fields may already be + // set. We leave the class on the CLD list, even if incomplete so that we don't + // modify the CLD list outside a safepoint. + if (class_loader_data() == NULL || has_fake_loader_data()) { +- // CDS should not set fake loader data +- assert(!has_fake_loader_data() || (has_fake_loader_data() && UseAppCDS), +- "setting fake loader data possible only with AppCDS enabled"); +- // Restore class_loader_data + set_class_loader_data(loader_data); +- + // Add to class loader list first before creating the mirror + // (same order as class file parsing) + loader_data->add_class(this); + } +- + // Recreate the class mirror. + // Only recreate it if not present. A previous attempt to restore may have + // gotten an OOM later but keep the mirror if it was created. +diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp +index f70587eab..4e45a7756 100644 +--- a/hotspot/src/share/vm/oops/klass.hpp ++++ b/hotspot/src/share/vm/oops/klass.hpp +@@ -94,6 +94,8 @@ class ParCompactionManager; + class KlassSizeStats; + class fieldDescriptor; + class MarkSweep; ++class MetaspaceClosure; ++class vtableEntry; + + class Klass : public Metadata { + friend class VMStructs; +@@ -209,7 +211,7 @@ protected: + bool has_fake_loader_data_App() { return class_loader_data() == _fake_loader_data_App; } + bool has_fake_loader_data_Ext() { return class_loader_data() == _fake_loader_data_Ext; } + bool has_fake_loader_data() { return (has_fake_loader_data_App() || has_fake_loader_data_Ext()); } +- ++ + bool is_klass() const volatile { return true; } + + // super +@@ -316,6 +318,7 @@ protected: + _shared_class_path_index = index; + }; + ++ virtual void metaspace_pointers_do(MetaspaceClosure* it); + + protected: // internal accessors + Klass* subklass_oop() const { return _subklass; } +@@ -323,7 +326,10 @@ protected: + void set_subklass(Klass* s); + void set_next_sibling(Klass* s); + ++ vtableEntry* start_of_vtable() const; ++ + public: ++ static ByteSize vtable_start_offset(); + + // Compiler support + static ByteSize super_offset() { return in_ByteSize(offset_of(Klass, _super)); } +@@ -505,6 +511,7 @@ protected: + public: + // CDS support - remove and restore oops from metadata. Oops are not shared. + virtual void remove_unshareable_info(); ++ virtual void remove_java_mirror(); + virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS); + + protected: +@@ -725,6 +732,7 @@ protected: + + virtual const char* internal_name() const = 0; + ++ virtual MetaspaceObj::Type type() const { return ClassType; } + // Verification + virtual void verify_on(outputStream* st); + void verify() { verify_on(tty); } +diff --git a/hotspot/src/share/vm/oops/klassVtable.hpp b/hotspot/src/share/vm/oops/klassVtable.hpp +index 244f3c0cc..9379bcca0 100644 +--- a/hotspot/src/share/vm/oops/klassVtable.hpp ++++ b/hotspot/src/share/vm/oops/klassVtable.hpp +@@ -176,6 +176,7 @@ class vtableEntry VALUE_OBJ_CLASS_SPEC { + } + static int method_offset_in_bytes() { return offset_of(vtableEntry, _method); } + Method* method() const { return _method; } ++ Method** method_addr() { return &_method; } + + private: + Method* _method; +@@ -216,6 +217,7 @@ class itableOffsetEntry VALUE_OBJ_CLASS_SPEC { + int _offset; + public: + Klass* interface_klass() const { return _interface; } ++ InstanceKlass**interface_klass_addr() { return(InstanceKlass**) &_interface; } + int offset() const { return _offset; } + + static itableMethodEntry* method_entry(Klass* k, int offset) { return (itableMethodEntry*)(((address)k) + offset); } +@@ -238,6 +240,7 @@ class itableMethodEntry VALUE_OBJ_CLASS_SPEC { + + public: + Method* method() const { return _method; } ++ Method**method_addr() { return &_method; } + + void clear() { _method = NULL; } + +diff --git a/hotspot/src/share/vm/oops/metadata.hpp b/hotspot/src/share/vm/oops/metadata.hpp +index dc52c452e..372faa953 100644 +--- a/hotspot/src/share/vm/oops/metadata.hpp ++++ b/hotspot/src/share/vm/oops/metadata.hpp +@@ -28,6 +28,7 @@ + #include "utilities/exceptions.hpp" + #include "utilities/globalDefinitions.hpp" + #include "utilities/ostream.hpp" ++class MetaspaceClosure; + + // This is the base class for an internal Class related metadata + class Metadata : public MetaspaceObj { +@@ -47,8 +48,9 @@ class Metadata : public MetaspaceObj { + virtual bool is_method() const volatile { return false; } + virtual bool is_methodData() const volatile { return false; } + virtual bool is_constantPool() const volatile { return false; } +- ++ virtual MetaspaceObj::Type type() const = 0; + virtual const char* internal_name() const = 0; ++ virtual void metaspace_pointers_do(MetaspaceClosure* iter) {} + + void print() const { print_on(tty); } + void print_value() const { print_value_on(tty); } +diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp +index 64cdae9c7..305348bd0 100644 +--- a/hotspot/src/share/vm/oops/method.cpp ++++ b/hotspot/src/share/vm/oops/method.cpp +@@ -37,6 +37,7 @@ + #include "memory/heapInspection.hpp" + #include "memory/metadataFactory.hpp" + #include "memory/metaspaceShared.hpp" ++#include "memory/metaspaceClosure.hpp" + #include "memory/oopFactory.hpp" + #include "oops/constMethod.hpp" + #include "oops/methodData.hpp" +@@ -834,6 +835,20 @@ void Method::set_not_osr_compilable(int comp_level, bool report, const char* rea + assert(!CompilationPolicy::can_be_osr_compiled(this, comp_level), "sanity check"); + } + ++void Method::metaspace_pointers_do(MetaspaceClosure* it) { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Iter(Method): %p", this); ++ } ++ ++ if (!method_holder()->is_rewritten()) { ++ it->push(&_constMethod, MetaspaceClosure::_writable); ++ } else { ++ it->push(&_constMethod); ++ } ++ it->push(&_method_data); ++ it->push(&_method_counters); ++} ++ + // Revert to using the interpreter and clear out the nmethod + void Method::clear_code(bool acquire_lock /* = true */) { + MutexLockerEx pl(acquire_lock ? Patching_lock : NULL, Mutex::_no_safepoint_check_flag); +@@ -1421,12 +1436,15 @@ static int method_comparator(Method* a, Method* b) { + + // This is only done during class loading, so it is OK to assume method_idnum matches the methods() array + // default_methods also uses this without the ordering for fast find_method +-void Method::sort_methods(Array* methods, bool idempotent, bool set_idnums) { ++void Method::sort_methods(Array* methods, bool idempotent, bool set_idnums, method_comparator_func func) { + int length = methods->length(); + if (length > 1) { ++ if (func == NULL) { ++ func = method_comparator; ++ } + { + No_Safepoint_Verifier nsv; +- QuickSort::sort(methods->data(), length, method_comparator, idempotent); ++ QuickSort::sort(methods->data(), length, func, idempotent); + } + // Reset method ordering + if (set_idnums) { +diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp +index 1f507ac0f..ec93f2fb4 100644 +--- a/hotspot/src/share/vm/oops/method.hpp ++++ b/hotspot/src/share/vm/oops/method.hpp +@@ -99,6 +99,7 @@ class MethodCounters; + class ConstMethod; + class InlineTableSizes; + class KlassSizeStats; ++class MetaspaceClosure; + + class Method : public Metadata { + friend class VMStructs; +@@ -857,6 +858,9 @@ class Method : public Metadata { + void print_made_not_compilable(int comp_level, bool is_osr, bool report, const char* reason); + + public: ++ void metaspace_pointers_do(MetaspaceClosure* it); ++ virtual MetaspaceObj::Type type() const { return MethodType; } ++ + MethodCounters* get_method_counters(TRAPS) { + if (_method_counters == NULL) { + build_method_counters(this, CHECK_AND_CLEAR_NULL); +@@ -897,8 +901,9 @@ class Method : public Metadata { + void print_name(outputStream* st = tty) PRODUCT_RETURN; // prints as "virtual void foo(int)" + #endif + ++ typedef int (*method_comparator_func)(Method* a, Method* b); + // Helper routine used for method sorting +- static void sort_methods(Array* methods, bool idempotent = false, bool set_idnums = true); ++ static void sort_methods(Array* methods, bool idempotent = false, bool set_idnums = true, method_comparator_func func = NULL); + + // Deallocation function for redefine classes or if an error occurs + void deallocate_contents(ClassLoaderData* loader_data); +diff --git a/hotspot/src/share/vm/oops/methodCounters.hpp b/hotspot/src/share/vm/oops/methodCounters.hpp +index b98644574..6a3f7a738 100644 +--- a/hotspot/src/share/vm/oops/methodCounters.hpp ++++ b/hotspot/src/share/vm/oops/methodCounters.hpp +@@ -129,5 +129,12 @@ class MethodCounters: public MetaspaceObj { + return offset_of(MethodCounters, _interpreter_invocation_count); + } + ++ MetaspaceObj::Type type() const { return MethodCountersType; } ++ ++ void metaspace_pointers_do(MetaspaceClosure* it) { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Iter(MethodCounters): %p", this); ++ } ++ } + }; + #endif //SHARE_VM_OOPS_METHODCOUNTERS_HPP +diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp +index eb48188a6..bde6ca123 100644 +--- a/hotspot/src/share/vm/oops/methodData.cpp ++++ b/hotspot/src/share/vm/oops/methodData.cpp +@@ -29,6 +29,7 @@ + #include "interpreter/bytecodeStream.hpp" + #include "interpreter/linkResolver.hpp" + #include "memory/heapInspection.hpp" ++#include "memory/metaspaceClosure.hpp" + #include "oops/methodData.hpp" + #include "prims/jvmtiRedefineClasses.hpp" + #include "runtime/compilationPolicy.hpp" +@@ -1683,3 +1684,11 @@ void MethodData::clean_weak_method_links() { + clean_extra_data(&cl); + verify_extra_data_clean(&cl); + } ++ ++ ++void MethodData::metaspace_pointers_do(MetaspaceClosure* iter) { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Iter(MethodData): %p", this); ++ } ++ iter->push(&_method); ++} +diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp +index 3cd7cd6f1..eb121268f 100644 +--- a/hotspot/src/share/vm/oops/methodData.hpp ++++ b/hotspot/src/share/vm/oops/methodData.hpp +@@ -67,7 +67,7 @@ class KlassSizeStats; + + // forward decl + class ProfileData; +- ++class MetaspaceClosure; + // DataLayout + // + // Overlay for generic profiling data. +@@ -2486,6 +2486,9 @@ public: + void clean_method_data(BoolObjectClosure* is_alive); + + void clean_weak_method_links(); ++ ++ virtual void metaspace_pointers_do(MetaspaceClosure* iter); ++ virtual MetaspaceObj::Type type() const { return MethodDataType; } + }; + + #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP +diff --git a/hotspot/src/share/vm/oops/objArrayKlass.cpp b/hotspot/src/share/vm/oops/objArrayKlass.cpp +index 19abfbd5a..60d173e9e 100644 +--- a/hotspot/src/share/vm/oops/objArrayKlass.cpp ++++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp +@@ -33,6 +33,7 @@ + #include "memory/metadataFactory.hpp" + #include "memory/resourceArea.hpp" + #include "memory/universe.inline.hpp" ++#include "memory/metaspaceClosure.hpp" + #include "oops/instanceKlass.hpp" + #include "oops/klass.inline.hpp" + #include "oops/objArrayKlass.hpp" +@@ -569,6 +570,12 @@ int ObjArrayKlass::oop_adjust_pointers(oop obj) { + return size; + } + ++void ObjArrayKlass::metaspace_pointers_do(MetaspaceClosure* it) { ++ ArrayKlass::metaspace_pointers_do(it); ++ it->push(&_element_klass); ++ it->push(&_bottom_klass); ++} ++ + #if INCLUDE_ALL_GCS + void ObjArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { + assert(obj->is_objArray(), "obj must be obj array"); +diff --git a/hotspot/src/share/vm/oops/objArrayKlass.hpp b/hotspot/src/share/vm/oops/objArrayKlass.hpp +index ab3cbc61c..c17adba70 100644 +--- a/hotspot/src/share/vm/oops/objArrayKlass.hpp ++++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp +@@ -109,7 +109,8 @@ class ObjArrayKlass : public ArrayKlass { + template inline void objarray_follow_contents(oop obj, int index, MarkSweep* mark); + + int oop_adjust_pointers(oop obj); +- ++ ++ virtual void metaspace_pointers_do(MetaspaceClosure* iter); + // Parallel Scavenge and Parallel Old + PARALLEL_GC_DECLS + #if INCLUDE_ALL_GCS +diff --git a/hotspot/src/share/vm/oops/symbol.hpp b/hotspot/src/share/vm/oops/symbol.hpp +index aaa55c589..4b1b5cb5d 100644 +--- a/hotspot/src/share/vm/oops/symbol.hpp ++++ b/hotspot/src/share/vm/oops/symbol.hpp +@@ -25,9 +25,9 @@ + #ifndef SHARE_VM_OOPS_SYMBOL_HPP + #define SHARE_VM_OOPS_SYMBOL_HPP + +-#include "utilities/utf8.hpp" + #include "memory/allocation.hpp" + #include "runtime/atomic.hpp" ++#include "utilities/utf8.hpp" + + // A Symbol is a canonicalized string. + // All Symbols reside in global SymbolTable and are reference counted. +@@ -101,6 +101,7 @@ + // Since sometimes this is allocated from Metadata, pick a base allocation + // type without virtual functions. + class ClassLoaderData; ++class MetaspaceClosure; + + // We separate the fields in SymbolBase from Symbol::_body so that + // Symbol::size(int) can correctly calculate the space needed. +@@ -113,7 +114,7 @@ class SymbolBase : public MetaspaceObj { + int _identity_hash; + }; + +-class Symbol : private SymbolBase { ++class Symbol : public SymbolBase { + friend class VMStructs; + friend class SymbolTable; + friend class MoveSymbols; +@@ -160,6 +161,9 @@ class Symbol : private SymbolBase { + int refcount() const { return _refcount; } + void increment_refcount(); + void decrement_refcount(); ++ bool is_permanent() const { ++ return (refcount() == -1); ++ } + + int byte_at(int index) const { + assert(index >=0 && index < _length, "symbol index overflow"); +@@ -180,6 +184,17 @@ class Symbol : private SymbolBase { + return starts_with(prefix, (int) strlen(prefix)); + } + ++ void set_permanent() { ++ _refcount = -1; ++ } ++ ++ void metaspace_pointers_do(MetaspaceClosure* it) { ++ if (TraceDynamicCDS) { ++ dynamic_cds_log->print_cr("Iter(Symbol): %p", this); ++ } ++ } ++ ++ MetaspaceObj::Type type() const { return SymbolType; } + // Tests if the symbol starts with the given prefix. + int index_of_at(int i, const char* str, int len) const; + int index_of_at(int i, const char* str) const { +@@ -208,6 +223,9 @@ class Symbol : private SymbolBase { + + jchar* as_unicode(int& length) const; + ++ // Symbols should be stored in the read-only region of CDS archive. ++ static bool is_read_only_by_default() { return true; } ++ + // Treating this symbol as a class name, returns the Java name for the class. + // String is allocated in resource area if buffer is not provided. + // See Klass::external_name() +diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp +index 6f5e75107..1f603021a 100644 +--- a/hotspot/src/share/vm/runtime/arguments.cpp ++++ b/hotspot/src/share/vm/runtime/arguments.cpp +@@ -29,6 +29,7 @@ + #include "compiler/compilerOracle.hpp" + #include "memory/allocation.inline.hpp" + #include "memory/cardTableRS.hpp" ++#include "memory/filemap.hpp" + #include "memory/genCollectedHeap.hpp" + #include "memory/referenceProcessor.hpp" + #include "memory/universe.inline.hpp" +@@ -126,6 +127,7 @@ bool Arguments::_BackgroundCompilation = BackgroundCompilation; + bool Arguments::_ClipInlining = ClipInlining; + + char* Arguments::SharedArchivePath = NULL; ++char* Arguments::SharedDynamicArchivePath = NULL; + + AgentLibraryList Arguments::_libraryList; + AgentLibraryList Arguments::_agentList; +@@ -179,6 +181,117 @@ static void logOption(const char* opt) { + } + } + ++#if INCLUDE_CDS ++// Sharing support ++// Construct the path to the archive ++int Arguments::num_archives(const char* archive_path) { ++ if (archive_path == NULL) { ++ return 0; ++ } ++ int npaths = 1; ++ char* p = (char*)archive_path; ++ while (*p != '\0') { ++ if (*p == os::path_separator()[0]) { ++ npaths++; ++ } ++ p++; ++ } ++ return npaths; ++} ++ ++void Arguments::extract_shared_archive_paths(const char* archive_path, ++ char** base_archive_path, ++ char** top_archive_path) { ++ char* begin_ptr = (char*)archive_path; ++ char* end_ptr = strchr((char*)archive_path, os::path_separator()[0]); ++ if (end_ptr == NULL || end_ptr == begin_ptr) { ++ vm_exit_during_initialization("Base archive was not specified", archive_path); ++ } ++ size_t len = end_ptr - begin_ptr; ++ char* cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal); ++ strncpy(cur_path, begin_ptr, len); ++ cur_path[len] = '\0'; ++ FileMapInfo::check_archive((const char*)cur_path, true /*is_static*/); ++ *base_archive_path = cur_path; ++ ++ begin_ptr = ++end_ptr; ++ if (*begin_ptr == '\0') { ++ vm_exit_during_initialization("Top archive was not specified", archive_path); ++ } ++ end_ptr = strchr(begin_ptr, '\0'); ++ assert(end_ptr != NULL, "sanity"); ++ len = end_ptr - begin_ptr; ++ cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal); ++ strncpy(cur_path, begin_ptr, len + 1); ++ ++ FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/); ++ *top_archive_path = cur_path; ++} ++ ++bool Arguments::init_shared_archive_paths() { ++ if (ArchiveClassesAtExit != NULL) { ++ if (DumpSharedSpaces) { ++ vm_exit_during_initialization("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump"); ++ } ++ SharedDynamicArchivePath = os::strdup_check_oom(ArchiveClassesAtExit, mtClassShared); ++ } else { ++ if (SharedDynamicArchivePath != NULL) { ++ os::free(SharedDynamicArchivePath); ++ SharedDynamicArchivePath = NULL; ++ } ++ } ++ ++ if (SharedArchiveFile != NULL) { ++ int archives = num_archives(SharedArchiveFile); ++ if (is_dumping_archive()) { ++ if (archives > 1) { ++ vm_exit_during_initialization( ++ "Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping"); ++ } ++ if (DynamicDumpSharedSpaces) { ++ if (strcmp(SharedArchiveFile, ArchiveClassesAtExit) == 0) { ++ vm_exit_during_initialization( ++ "Cannot have the same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit", ++ SharedArchiveFile); ++ } ++ } ++ } ++ ++ if (!is_dumping_archive()) { ++ if (archives > 2) { ++ vm_exit_during_initialization( ++ "Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option"); ++ } ++ if (archives == 1) { ++ char* temp_archive_path = os::strdup_check_oom(SharedArchiveFile, mtClassShared); ++ int name_size; ++ bool success = ++ FileMapInfo::get_base_archive_name_from_header(temp_archive_path, &name_size, &SharedArchivePath); ++ if (!success) { ++ SharedArchivePath = temp_archive_path; ++ } else { ++ SharedDynamicArchivePath = temp_archive_path; ++ } ++ } else { ++ extract_shared_archive_paths((const char*)SharedArchiveFile, ++ &SharedArchivePath, &SharedDynamicArchivePath); ++ } ++ ++ // We must use tty here instead of dynamic_cds_log for dynamic_cds_log is initialized after share path init. ++ if (InfoDynamicCDS && SharedArchivePath != NULL) { ++ tty->print_cr("SharedArchivePath: %s", SharedArchivePath); ++ } ++ if (InfoDynamicCDS && SharedDynamicArchivePath != NULL) { ++ tty->print_cr("SharedDynamicArchivePath: %s", SharedDynamicArchivePath); ++ } ++ } else { // CDS dumping ++ SharedArchivePath = os::strdup_check_oom(SharedArchiveFile, mtClassShared); ++ } ++ } ++ return (SharedArchivePath != NULL); ++} ++#endif // INCLUDE_CDS ++ + // Process java launcher properties. + void Arguments::process_sun_java_launcher_properties(JavaVMInitArgs* args) { + // See if sun.java.launcher or sun.java.launcher.pid is defined. +@@ -3724,6 +3837,30 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req + set_mode_flags(_int); + } + ++#if INCLUDE_CDS ++ if (ArchiveClassesAtExit == NULL) { ++ FLAG_SET_DEFAULT(DynamicDumpSharedSpaces, false); ++ } else { ++ FLAG_SET_DEFAULT(DynamicDumpSharedSpaces, true); ++ // When Dynamic CDS dump is turned on, we will set ClassUnloading false, ++ // and there is no need to care if the class loader is alive. ++ FLAG_SET_DEFAULT(ClassUnloading, false); ++ } ++ ++ if (TraceDynamicCDS) { ++ FLAG_SET_DEFAULT(DebugDynamicCDS, true); ++ FLAG_SET_DEFAULT(InfoDynamicCDS, true); ++ } else if (DebugDynamicCDS) { ++ FLAG_SET_DEFAULT(InfoDynamicCDS, true); ++ } ++ ++#ifdef _LP64 ++ // We attempt to set SharedBaseAddress right above ++ // the java heap base on ObjectAlignmentInBytes. ++ FLAG_SET_DEFAULT(SharedBaseAddress, (ObjectAlignmentInBytes * 4 * G)); ++#endif // _LP64 ++#endif // INCLUDE_CDS ++ + // eventually fix up InitialTenuringThreshold if only MaxTenuringThreshold is set + if (FLAG_IS_DEFAULT(InitialTenuringThreshold) && (InitialTenuringThreshold > MaxTenuringThreshold)) { + FLAG_SET_ERGO(uintx, InitialTenuringThreshold, MaxTenuringThreshold); +@@ -3885,6 +4022,11 @@ void Arguments::set_shared_spaces_flags() { + } + #endif + } ++ ++#if INCLUDE_CDS ++ // Initialize shared archive paths which could include both base and dynamic archive paths ++ init_shared_archive_paths(); ++#endif // INCLUDE_CDS + } + + #if !INCLUDE_ALL_GCS +diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp +index a1fcfc398..19f5cb60b 100644 +--- a/hotspot/src/share/vm/runtime/arguments.hpp ++++ b/hotspot/src/share/vm/runtime/arguments.hpp +@@ -443,7 +443,8 @@ class Arguments : AllStatic { + static bool CheckCompileOnly; + + static char* SharedArchivePath; +- static char* AppCDSLockPath; ++ ++ static char* SharedDynamicArchivePath; + + public: + // Parses the arguments, first phase +@@ -553,6 +554,22 @@ class Arguments : AllStatic { + + static const char* GetSharedArchivePath() { return SharedArchivePath; } + ++ static const char* GetSharedDynamicArchivePath() { return SharedDynamicArchivePath; } ++ ++ static bool init_shared_archive_paths(); ++ ++ static void extract_shared_archive_paths(const char* archive_path, ++ char** base_archive_path, ++ char** top_archive_path); ++ ++ static int num_archives(const char* archive_path); ++ ++ static bool is_dumping_archive() { return DumpSharedSpaces || DynamicDumpSharedSpaces; } ++ ++ static void assert_is_dumping_archive() { ++ assert(Arguments::is_dumping_archive(), "dump time only"); ++ } ++ + static bool CompileMethod(char* className, char* methodName) { + return + methodExists( +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 91e52f033..eb13ee0d7 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -3910,6 +3910,24 @@ class CommandLineFlags { + NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)), \ + "Address to allocate shared memory region for class data") \ + \ ++ experimental(ccstr, ArchiveClassesAtExit, NULL, \ ++ "The path and name of the dynamic archive file") \ ++ \ ++ product(bool, InfoDynamicCDS, false, \ ++ "Log info level in DynamicCDS") \ ++ \ ++ product(bool, TraceDynamicCDS, false, \ ++ "Trace details in DynamicCDS") \ ++ \ ++ product(bool, DebugDynamicCDS, false, \ ++ "Debug details in DynamicCDS") \ ++ \ ++ product(bool, DynamicDumpSharedSpaces, false, \ ++ "Dynamic archive") \ ++ \ ++ product(uintx, SharedSymbolTableBucketSize, 4, \ ++ "Average number of symbols per bucket in shared table") \ ++ \ + diagnostic(bool, EnableInvokeDynamic, true, \ + "support JSR 292 (method handles, invokedynamic, " \ + "anonymous classes") \ +@@ -4017,6 +4035,9 @@ class CommandLineFlags { + "Dump the names all loaded classes, that could be stored into " \ + "the CDS archive, in the specified file") \ + \ ++ product(ccstr, DynamicCDSLog, NULL, \ ++ "Dynamic CDS log path") \ ++ \ + product(ccstr, SharedClassListFile, NULL, \ + "Override the default CDS class list") \ + \ +diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp +index 0a263b017..4f290c826 100644 +--- a/hotspot/src/share/vm/runtime/java.cpp ++++ b/hotspot/src/share/vm/runtime/java.cpp +@@ -23,6 +23,7 @@ + */ + + #include "precompiled.hpp" ++#include "cds/dynamicArchive.hpp" + #include "classfile/classLoader.hpp" + #include "classfile/symbolTable.hpp" + #include "classfile/systemDictionary.hpp" +@@ -546,6 +547,13 @@ void before_exit(JavaThread * thread) { + // Note: we don't wait until it actually dies. + os::terminate_signal_thread(); + ++#if INCLUDE_CDS ++ if (DynamicDumpSharedSpaces) { ++ DynamicArchive::dump(); ++ ShouldNotReachHere(); ++ } ++#endif ++ + print_statistics(); + Universe::heap()->print_tracing_info(); + +diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp +index a96ae50eb..a1c61f864 100644 +--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp ++++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp +@@ -39,6 +39,7 @@ + + Mutex* Patching_lock = NULL; + Monitor* SystemDictionary_lock = NULL; ++Mutex* SharedDictionary_lock = NULL; + Mutex* PackageTable_lock = NULL; + Mutex* CompiledIC_lock = NULL; + Mutex* InlineCacheBuffer_lock = NULL; +@@ -129,6 +130,7 @@ Monitor* RedefineClasses_lock = NULL; + + Mutex* FreeHumongousRegions_lock = NULL; + ++Mutex* DumpTimeTable_lock = NULL; + #ifdef INCLUDE_JFR + Mutex* JfrStacktrace_lock = NULL; + Monitor* JfrMsg_lock = NULL; +@@ -224,6 +226,7 @@ void mutex_init() { + def(JmethodIdCreation_lock , Mutex , leaf, true ); // used for creating jmethodIDs. + + def(SystemDictionary_lock , Monitor, leaf, true ); // lookups done by VM thread ++ def(SharedDictionary_lock , Mutex , leaf, true ); + def(PackageTable_lock , Mutex , leaf, false); + def(InlineCacheBuffer_lock , Mutex , leaf, true ); + def(VMStatistic_lock , Mutex , leaf, false); +@@ -289,7 +292,7 @@ void mutex_init() { + def(RedefineClasses_lock , Monitor, nonleaf+5, true); + + def(FreeHumongousRegions_lock , Mutex , nonleaf, false); +- ++ def(DumpTimeTable_lock , Mutex , leaf - 1, true); + #if INCLUDE_JFR + def(JfrMsg_lock , Monitor, leaf, true); + def(JfrBuffer_lock , Mutex, leaf, true); +diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp +index 428c80181..f28058b0e 100644 +--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp ++++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp +@@ -47,6 +47,7 @@ + + extern Mutex* Patching_lock; // a lock used to guard code patching of compiled code + extern Monitor* SystemDictionary_lock; // a lock on the system dictonary ++extern Mutex* SharedDictionary_lock; // a lock on the CDS shared dictionary + extern Mutex* PackageTable_lock; // a lock on the class loader package table + extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access + extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the InlineCacheBuffer +@@ -145,6 +146,8 @@ extern Monitor* RedefineClasses_lock; // locks classes from parallel + + extern Mutex* FreeHumongousRegions_lock; // locks humongous regions from freeing in parallel + ++extern Mutex* DumpTimeTable_lock; // SystemDictionaryShared::find_or_allocate_info_for ++ + #if INCLUDE_JFR + extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table + extern Monitor* JfrMsg_lock; // protects JFR messaging +diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp +index ed41265cc..5c5d60220 100644 +--- a/hotspot/src/share/vm/runtime/os.cpp ++++ b/hotspot/src/share/vm/runtime/os.cpp +@@ -568,7 +568,7 @@ bool os::find_builtin_agent(AgentLibrary *agent_lib, const char *syms[], + + // --------------------- heap allocation utilities --------------------- + +-char *os::strdup(const char *str, MEMFLAGS flags) { ++char* os::strdup(const char *str, MEMFLAGS flags) { + size_t size = strlen(str); + char *dup_str = (char *)malloc(size + 1, flags); + if (dup_str == NULL) return NULL; +@@ -576,6 +576,13 @@ char *os::strdup(const char *str, MEMFLAGS flags) { + return dup_str; + } + ++char* os::strdup_check_oom(const char* str, MEMFLAGS flags) { ++ char* p = os::strdup(str, flags); ++ if (p == NULL) { ++ vm_exit_out_of_memory(strlen(str) + 1, OOM_MALLOC_ERROR, "os::strdup_check_oom"); ++ } ++ return p; ++} + + + #define paranoid 0 /* only set to 1 if you suspect checking code has bug */ +diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp +index 296380f39..7ae49fd5b 100644 +--- a/hotspot/src/share/vm/runtime/os.hpp ++++ b/hotspot/src/share/vm/runtime/os.hpp +@@ -731,6 +731,8 @@ class os: AllStatic { + static void free (void *memblock, MEMFLAGS flags = mtNone); + static bool check_heap(bool force = false); // verify C heap integrity + static char* strdup(const char *, MEMFLAGS flags = mtInternal); // Like strdup ++ // Like strdup, but exit VM when strdup() returns NULL ++ static char* strdup_check_oom(const char*, MEMFLAGS flags = mtInternal); + + #ifndef PRODUCT + static julong num_mallocs; // # of calls to malloc/realloc +diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp +index 94b9e69d2..807786d98 100644 +--- a/hotspot/src/share/vm/runtime/thread.cpp ++++ b/hotspot/src/share/vm/runtime/thread.cpp +@@ -23,6 +23,7 @@ + */ + + #include "precompiled.hpp" ++#include "cds/dynamicArchive.hpp" + #include "classfile/classLoader.hpp" + #include "classfile/javaClasses.hpp" + #include "classfile/systemDictionary.hpp" +@@ -3934,6 +3935,15 @@ void JavaThread::invoke_shutdown_hooks() { + this->clear_pending_exception(); + } + ++#if INCLUDE_CDS ++ // Link all classes for dynamic CDS dumping before vm exit. ++ // Same operation is being done in JVM_BeforeHalt for handling the ++ // case where the application calls System.exit(). ++ if (DynamicDumpSharedSpaces) { ++ DynamicArchive::prepare_for_dynamic_dumping_at_exit(); ++ } ++#endif ++ + EXCEPTION_MARK; + Klass* k = + SystemDictionary::resolve_or_null(vmSymbols::java_lang_Shutdown(), +diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp +index ede8db156..358ec6e09 100644 +--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp ++++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp +@@ -23,6 +23,7 @@ + */ + + #include "precompiled.hpp" ++#include "cds/dynamicArchive.hpp" + #include "classfile/classLoaderStats.hpp" + #include "gc_implementation/shared/vmGCOperations.hpp" + #include "runtime/javaCalls.hpp" +@@ -57,6 +58,7 @@ void DCmdRegistrant::register_dcmds(){ + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + #if INCLUDE_SERVICES // Heap dumping/inspection supported + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false)); ++ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + #endif // INCLUDE_SERVICES +@@ -375,6 +377,17 @@ int HeapDumpDCmd::num_arguments() { + } + } + ++void DynamicCDSDumpDCmd::execute(DCmdSource source, TRAPS) { ++#if INCLUDE_CDS ++ if (DynamicDumpSharedSpaces) { ++ DynamicArchive::dump(); ++ ShouldNotReachHere(); ++ } else { ++ warning("Dynamic CDS is not enabled"); ++ } ++#endif ++} ++ + ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), + _all("-all", "Inspect all objects, including unreachable objects", +diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp +index b1fb57e53..e28011f25 100644 +--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp ++++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp +@@ -267,6 +267,29 @@ public: + }; + #endif // INCLUDE_SERVICES + ++class DynamicCDSDumpDCmd : public DCmdWithParser { ++public: ++ DynamicCDSDumpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap) { } ++ static const char* name() { ++ return "GC.dynamic_cds_dump"; ++ } ++ static const char* description() { ++ return "Dynamic CDS dump"; ++ } ++ static const char* impact() { ++ return "Medium"; ++ } ++ static const JavaPermission permission() { ++ JavaPermission p = {"java.lang.management.ManagementPermission", ++ "monitor", NULL}; ++ return p; ++ } ++ static int num_arguments() { ++ return 0; ++ } ++ virtual void execute(DCmdSource source, TRAPS); ++}; ++ + // See also: inspectheap in attachListener.cpp + class ClassHistogramDCmd : public DCmdWithParser { + protected: +diff --git a/hotspot/src/share/vm/utilities/array.hpp b/hotspot/src/share/vm/utilities/array.hpp +index 920b87501..371876b56 100644 +--- a/hotspot/src/share/vm/utilities/array.hpp ++++ b/hotspot/src/share/vm/utilities/array.hpp +@@ -302,6 +302,7 @@ define_array(intArray , int ) define_stack(intStack , intArray ) + + template + class Array: public MetaspaceObj { ++ friend class ArchiveBuilder; + friend class MetadataFactory; + friend class VMStructs; + friend class MethodHandleCompiler; // special case +diff --git a/hotspot/src/share/vm/utilities/bitMap.cpp b/hotspot/src/share/vm/utilities/bitMap.cpp +index e64add155..12b4b4160 100644 +--- a/hotspot/src/share/vm/utilities/bitMap.cpp ++++ b/hotspot/src/share/vm/utilities/bitMap.cpp +@@ -67,16 +67,14 @@ void BitMap::resize(idx_t size_in_bits, bool in_resource_area) { + idx_t new_size_in_words = size_in_words(); + if (in_resource_area) { + _map = NEW_RESOURCE_ARRAY(bm_word_t, new_size_in_words); ++ Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) _map, ++ MIN2(old_size_in_words, new_size_in_words)); + } else { +- if (old_map != NULL) { +- _map_allocator.free(); +- } +- _map = _map_allocator.allocate(new_size_in_words); ++ _map = _map_allocator.reallocate(new_size_in_words); + } +- Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) _map, +- MIN2(old_size_in_words, new_size_in_words)); ++ + if (new_size_in_words > old_size_in_words) { +- clear_range_of_words(old_size_in_words, size_in_words()); ++ clear_range_of_words(old_size_in_words, new_size_in_words); + } + } + +@@ -454,6 +452,11 @@ bool BitMap::is_empty() const { + return rest == 0 || (*word & right_n_bits((int)rest)) == (bm_word_t) NoBits; + } + ++void BitMap::write_to(bm_word_t* buffer, size_t buffer_size_in_bytes) const { ++ assert(buffer_size_in_bytes == (size_in_words() * BytesPerWord), "must be"); ++ memcpy(buffer, _map, size_in_words() * BytesPerWord); ++} ++ + void BitMap::clear_large() { + clear_large_range_of_words(0, size_in_words()); + } +diff --git a/hotspot/src/share/vm/utilities/bitMap.hpp b/hotspot/src/share/vm/utilities/bitMap.hpp +index 51c58da8e..08452bd90 100644 +--- a/hotspot/src/share/vm/utilities/bitMap.hpp ++++ b/hotspot/src/share/vm/utilities/bitMap.hpp +@@ -269,6 +269,7 @@ class BitMap VALUE_OBJ_CLASS_SPEC { + bool is_full() const; + bool is_empty() const; + ++ void write_to(bm_word_t* buffer, size_t buffer_size_in_bytes) const; + void print_on_error(outputStream* st, const char* prefix) const; + + #ifndef PRODUCT +diff --git a/hotspot/src/share/vm/utilities/constantTag.hpp b/hotspot/src/share/vm/utilities/constantTag.hpp +index ae99d5706..07a873743 100644 +--- a/hotspot/src/share/vm/utilities/constantTag.hpp ++++ b/hotspot/src/share/vm/utilities/constantTag.hpp +@@ -43,7 +43,8 @@ enum { + JVM_CONSTANT_UnresolvedClassInError = 103, // Error tag due to resolution error + JVM_CONSTANT_MethodHandleInError = 104, // Error tag due to resolution error + JVM_CONSTANT_MethodTypeInError = 105, // Error tag due to resolution error +- JVM_CONSTANT_InternalMax = 105 // Last implementation tag ++ JVM_CONSTANT_ReplacedSymbol = 106, ++ JVM_CONSTANT_InternalMax = 106 // Last implementation tag + }; + + +@@ -62,7 +63,7 @@ class constantTag VALUE_OBJ_CLASS_SPEC { + bool is_double() const { return _tag == JVM_CONSTANT_Double; } + bool is_name_and_type() const { return _tag == JVM_CONSTANT_NameAndType; } + bool is_utf8() const { return _tag == JVM_CONSTANT_Utf8; } +- ++ bool is_replaced_symbol() const { return _tag == JVM_CONSTANT_ReplacedSymbol; } + bool is_invalid() const { return _tag == JVM_CONSTANT_Invalid; } + + bool is_unresolved_klass() const { +diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp +index 81866b840..25f6f026c 100644 +--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp ++++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp +@@ -1511,6 +1511,16 @@ static inline void* dereference_vptr(const void* addr) { + return *(void**)addr; + } + ++ ++template unsigned primitive_hash(const K& k) { ++ unsigned hash = (unsigned)((uintptr_t)k); ++ return hash ^ (hash >> 3); // just in case we're dealing with aligned ptrs ++} ++ ++template bool primitive_equals(const K& k0, const K& k1) { ++ return k0 == k1; ++} ++ + #ifndef PRODUCT + + // For unit testing only +@@ -1519,7 +1529,6 @@ public: + static void test_globals(); + static void test_proper_unit(); + }; +- + #endif // PRODUCT + + #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_HPP +diff --git a/hotspot/src/share/vm/utilities/hashtable.cpp b/hotspot/src/share/vm/utilities/hashtable.cpp +index c026e6a0e..66df8f1f8 100644 +--- a/hotspot/src/share/vm/utilities/hashtable.cpp ++++ b/hotspot/src/share/vm/utilities/hashtable.cpp +@@ -34,7 +34,7 @@ + #include "utilities/hashtable.hpp" + #include "utilities/hashtable.inline.hpp" + #include "utilities/numberSeq.hpp" +- ++#include "utilities/align.hpp" + + // This hashtable is implemented as an open hash table with a fixed number of buckets. + +@@ -145,7 +145,7 @@ template void BasicHashtable::free_buckets() { + // Don't delete the buckets in the shared space. They aren't + // allocated by os::malloc + if (!UseSharedSpaces || +- !FileMapInfo::current_info()->is_in_shared_space(_buckets)) { ++ !MetaspaceShared::is_in_shared_space(_buckets)) { + FREE_C_HEAP_ARRAY(HashtableBucket, _buckets, F); + } + _buckets = NULL; +@@ -221,7 +221,7 @@ template void BasicHashtable::copy_table(char** top, char* end) + *top += entry_size(); + } + } +- *plen = (char*)(*top) - (char*)plen - sizeof(*plen); ++ *plen = ((char*)(*top) - (char*)plen) - sizeof(*plen); + + // Set the shared bit. + +@@ -317,7 +317,6 @@ template void RehashableHashtable::dump_table(output + st->print_cr("Maximum bucket size : %9d", (int)summary.maximum()); + } + +- + // Dump the hash table buckets. + + template void BasicHashtable::copy_buckets(char** top, char* end) { +@@ -335,6 +334,57 @@ template void BasicHashtable::copy_buckets(char** top, char* end + *top += len; + } + ++template bool BasicHashtable::resize(int new_size) { ++ ++ // Allocate new buckets ++ HashtableBucket* buckets_new = NEW_C_HEAP_ARRAY2_RETURN_NULL(HashtableBucket, new_size, F, CURRENT_PC); ++ if (buckets_new == NULL) { ++ return false; ++ } ++ ++ // Clear the new buckets ++ for (int i = 0; i < new_size; i++) { ++ buckets_new[i].clear(); ++ } ++ ++ int table_size_old = _table_size; ++ // hash_to_index() uses _table_size, so switch the sizes now ++ _table_size = new_size; ++ ++ // Move entries from the old table to a new table ++ for (int index_old = 0; index_old < table_size_old; index_old++) { ++ for (BasicHashtableEntry* p = _buckets[index_old].get_entry(); p != NULL; ) { ++ BasicHashtableEntry* next = p->next(); ++ int index_new = hash_to_index(p->hash()); ++ ++ p->set_next(buckets_new[index_new].get_entry()); ++ buckets_new[index_new].set_entry(p); ++ p = next; ++ } ++ } ++ ++ // The old backets now can be released ++ BasicHashtable::free_buckets(); ++ ++ // Switch to the new storage ++ _buckets = buckets_new; ++ ++ return true; ++} ++ ++template bool BasicHashtable::maybe_grow(int max_size, int load_factor) { ++ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); ++ ++ if (table_size() >= max_size) { ++ return false; ++ } ++ if (number_of_entries() / table_size() > load_factor) { ++ resize(MIN2(table_size() * 2, max_size)); ++ return true; ++ } else { ++ return false; ++ } ++} + + #ifndef PRODUCT + +@@ -352,7 +402,6 @@ template void Hashtable::print() { + } + } + +- + template void BasicHashtable::verify() { + int count = 0; + for (int i = 0; i < table_size(); i++) { +@@ -406,3 +455,4 @@ template class BasicHashtable; + template class BasicHashtable; + template class BasicHashtable; + template class BasicHashtable; ++template class BasicHashtable; +diff --git a/hotspot/src/share/vm/utilities/hashtable.hpp b/hotspot/src/share/vm/utilities/hashtable.hpp +index 30e442d15..358b09c3d 100644 +--- a/hotspot/src/share/vm/utilities/hashtable.hpp ++++ b/hotspot/src/share/vm/utilities/hashtable.hpp +@@ -151,7 +151,7 @@ public: + void copy_table(char** top, char* end); + + // Bucket handling +- int hash_to_index(unsigned int full_hash) { ++ int hash_to_index(unsigned int full_hash) const { + int h = full_hash % _table_size; + assert(h >= 0 && h < _table_size, "Illegal hash value"); + return h; +@@ -184,7 +184,7 @@ protected: + int entry_size() const { return _entry_size; } + + // The following method is MT-safe and may be used with caution. +- BasicHashtableEntry* bucket(int i); ++ BasicHashtableEntry* bucket(int i) const; + + // The following method is not MT-safe and must be done under lock. + BasicHashtableEntry** bucket_addr(int i) { return _buckets[i].entry_addr(); } +@@ -234,7 +234,7 @@ protected: + // is mt-safe wrt. to other calls of this method. + void bulk_free_entries(BucketUnlinkContext* context); + public: +- int table_size() { return _table_size; } ++ int table_size() const { return _table_size; } + void set_entry(int index, BasicHashtableEntry* entry); + + void add_entry(int index, BasicHashtableEntry* entry); +@@ -243,6 +243,10 @@ public: + + int number_of_entries() { return _number_of_entries; } + ++ bool resize(int new_size); ++ ++ bool maybe_grow(int max_size, int load_factor = 0); ++ + void verify() PRODUCT_RETURN; + }; + +@@ -364,4 +368,92 @@ public: + } + }; + ++// A subclass of BasicHashtable that allows you to do a simple K -> V mapping ++// without using tons of boilerplate code. ++template< ++ typename K, typename V, MEMFLAGS F, ++ unsigned (*HASH) (K const&) = primitive_hash, ++ bool (*EQUALS)(K const&, K const&) = primitive_equals ++ > ++class KVHashtable : public BasicHashtable { ++ class KVHashtableEntry : public BasicHashtableEntry { ++ public: ++ K _key; ++ V _value; ++ KVHashtableEntry* next() { ++ return (KVHashtableEntry*)BasicHashtableEntry::next(); ++ } ++ }; ++ ++protected: ++ KVHashtableEntry* bucket(int i) const { ++ return (KVHashtableEntry*)BasicHashtable::bucket(i); ++ } ++ ++ KVHashtableEntry* new_entry(unsigned int hashValue, K key, V value) { ++ KVHashtableEntry* entry = (KVHashtableEntry*)BasicHashtable::new_entry(hashValue); ++ entry->_key = key; ++ entry->_value = value; ++ return entry; ++ } ++ ++public: ++ KVHashtable(int table_size) : BasicHashtable(table_size, sizeof(KVHashtableEntry)) {} ++ ++ V* add(K key, V value) { ++ unsigned int hash = HASH(key); ++ KVHashtableEntry* entry = new_entry(hash, key, value); ++ BasicHashtable::add_entry(BasicHashtable::hash_to_index(hash), entry); ++ return &(entry->_value); ++ } ++ ++ V* lookup(K key) const { ++ unsigned int hash = HASH(key); ++ int index = BasicHashtable::hash_to_index(hash); ++ for (KVHashtableEntry* e = bucket(index); e != NULL; e = e->next()) { ++ if (e->hash() == hash && EQUALS(e->_key, key)) { ++ return &(e->_value); ++ } ++ } ++ return NULL; ++ } ++ ++ // Look up the key. ++ // If an entry for the key exists, leave map unchanged and return a pointer to its value. ++ // If no entry for the key exists, create a new entry from key and value and return a ++ // pointer to the value. ++ // *p_created is true if entry was created, false if entry pre-existed. ++ V* add_if_absent(K key, V value, bool* p_created) { ++ unsigned int hash = HASH(key); ++ int index = BasicHashtable::hash_to_index(hash); ++ for (KVHashtableEntry* e = bucket(index); e != NULL; e = e->next()) { ++ if (e->hash() == hash && EQUALS(e->_key, key)) { ++ *p_created = false; ++ return &(e->_value); ++ } ++ } ++ KVHashtableEntry* entry = new_entry(hash, key, value); ++ BasicHashtable::add_entry(BasicHashtable::hash_to_index(hash), entry); ++ *p_created = true; ++ return &(entry->_value); ++ } ++ ++ int table_size() const { ++ return BasicHashtable::table_size(); ++ } ++ ++ // ITER contains bool do_entry(K, V const&), which will be ++ // called for each entry in the table. If do_entry() returns false, ++ // the iteration is cancelled. ++ template ++ void iterate(ITER* iter) const { ++ for (int index = 0; index < table_size(); index++) { ++ for (KVHashtableEntry* e = bucket(index); e != NULL; e = e->next()) { ++ bool cont = iter->do_entry(e->_key, &e->_value); ++ if (!cont) { return; } ++ } ++ } ++ } ++}; ++ + #endif // SHARE_VM_UTILITIES_HASHTABLE_HPP +diff --git a/hotspot/src/share/vm/utilities/hashtable.inline.hpp b/hotspot/src/share/vm/utilities/hashtable.inline.hpp +index 9356c985e..ee22ba835 100644 +--- a/hotspot/src/share/vm/utilities/hashtable.inline.hpp ++++ b/hotspot/src/share/vm/utilities/hashtable.inline.hpp +@@ -72,7 +72,7 @@ template inline void BasicHashtable::initialize(int table_size, + + + // The following method is MT-safe and may be used with caution. +-template inline BasicHashtableEntry* BasicHashtable::bucket(int i) { ++template inline BasicHashtableEntry* BasicHashtable::bucket(int i) const { + return _buckets[i].get_entry(); + } + +diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp +index fa199a235..14d82ad0f 100644 +--- a/hotspot/src/share/vm/utilities/ostream.cpp ++++ b/hotspot/src/share/vm/utilities/ostream.cpp +@@ -379,6 +379,7 @@ xmlStream* xtty; + outputStream* tty; + outputStream* gclog_or_tty; + CDS_ONLY(jsaFileStream* classlist_file;) // Only dump the classes that can be stored into the CDS archive ++CDS_ONLY(outputStream* dynamic_cds_log;) + extern Mutex* tty_lock; + + #define EXTRACHARLEN 32 +@@ -1402,6 +1403,16 @@ void ostream_init_log() { + jsaFileStream(list_name); + FREE_C_HEAP_ARRAY(char, list_name, mtInternal); + } ++ ++ // For -XX:DynamicCDSLog= option ++ if (DynamicCDSLog != NULL) { ++ const char* log_name = make_log_name(DynamicCDSLog, NULL); ++ dynamic_cds_log = new(ResourceObj::C_HEAP, mtInternal) ++ fileStream(log_name); ++ FREE_C_HEAP_ARRAY(char, log_name, mtInternal); ++ } else { ++ dynamic_cds_log = tty; ++ } + #endif + + // If we haven't lazily initialized the logfile yet, do it now, +diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp +index c69289fb5..d0f9aac57 100644 +--- a/hotspot/src/share/vm/utilities/ostream.hpp ++++ b/hotspot/src/share/vm/utilities/ostream.hpp +@@ -221,7 +221,7 @@ class jsaFileStream : public fileStream { + }; + + CDS_ONLY(extern jsaFileStream* classlist_file;) +- ++CDS_ONLY(extern outputStream* dynamic_cds_log;) + // unlike fileStream, fdStream does unbuffered I/O by calling + // open() and write() directly. It is async-safe, but output + // from multiple thread may be mixed together. Used by fatal +diff --git a/hotspot/src/share/vm/utilities/resourceHash.hpp b/hotspot/src/share/vm/utilities/resourceHash.hpp +index 82c1219b4..941f25996 100644 +--- a/hotspot/src/share/vm/utilities/resourceHash.hpp ++++ b/hotspot/src/share/vm/utilities/resourceHash.hpp +@@ -27,21 +27,13 @@ + + #include "memory/allocation.hpp" + #include "utilities/top.hpp" ++#include "utilities/globalDefinitions.hpp" + + template struct ResourceHashtableFns { + typedef unsigned (*hash_fn)(K const&); + typedef bool (*equals_fn)(K const&, K const&); + }; + +-template unsigned primitive_hash(const K& k) { +- unsigned hash = (unsigned)((uintptr_t)k); +- return hash ^ (hash >> 3); // just in case we're dealing with aligned ptrs +-} +- +-template bool primitive_equals(const K& k0, const K& k1) { +- return k0 == k1; +-} +- + template< + typename K, typename V, + // xlC does not compile this: +@@ -66,6 +58,10 @@ class ResourceHashtable : public ResourceObj { + + Node(unsigned hash, K const& key, V const& value) : + _hash(hash), _key(key), _value(value), _next(NULL) {} ++ ++ // Create a node with a default-constructed value. ++ Node(unsigned hash, K const& key) : ++ _hash(hash), _key(key), _value(), _next(NULL) {} + }; + + Node* _table[SIZE]; +@@ -139,6 +135,19 @@ class ResourceHashtable : public ResourceObj { + } + } + ++ V* put_if_absent(K const& key, bool* p_created) { ++ unsigned hv = HASH(key); ++ Node** ptr = lookup_node(hv, key); ++ if (*ptr == NULL) { ++ *ptr = new (ALLOC_TYPE, MEM_TYPE) Node(hv, key); ++ *p_created = true; ++ } else { ++ *p_created = false; ++ } ++ return &(*ptr)->_value; ++ } ++ ++ + bool remove(K const& key) { + unsigned hv = HASH(key); + Node** ptr = lookup_node(hv, key); +-- +2.17.1 + diff --git a/Fix-compile-and-runtime-failures-for-minimal1-versio.patch b/Fix-compile-and-runtime-failures-for-minimal1-versio.patch new file mode 100644 index 0000000000000000000000000000000000000000..8733ee419cf43981d1e493966c77ba9783552672 --- /dev/null +++ b/Fix-compile-and-runtime-failures-for-minimal1-versio.patch @@ -0,0 +1,183 @@ +From d915916d5a7f3280270ea4207e4d3892ffa7de04 Mon Sep 17 00:00:00 2001 +Date: Mon, 11 Apr 2022 17:14:06 +0800 +Subject: [PATCH] Fix compile and runtime failures for minimal1 version + +Reference: NA +Summary: < JDK> : Fix compile and runtime failures for minimal1 version +--- + .../src/share/vm/classfile/systemDictionary.cpp | 30 ++++++++++------------ + .../parallelScavenge/psMarkSweep.hpp | 2 +- + hotspot/src/share/vm/prims/jvm.cpp | 12 +++++++++ + hotspot/src/share/vm/prims/jvmtiImpl.hpp | 8 +++--- + hotspot/src/share/vm/runtime/memprofiler.cpp | 2 +- + hotspot/src/share/vm/utilities/taskqueue.cpp | 2 ++ + hotspot/src/share/vm/utilities/taskqueue.hpp | 4 +-- + .../com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.c | 1 - + 8 files changed, 36 insertions(+), 25 deletions(-) + +diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp +index 0d11abfa..794ee9b1 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp ++++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp +@@ -1093,19 +1093,6 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name, + return k(); + } + +-static char* convert_into_package_name(char* name) { +- char* index = strrchr(name, '/'); +- if (index == NULL) { +- return NULL; +- } else { +- *index = '\0'; // chop to just the package name +- while ((index = strchr(name, '/')) != NULL) { +- *index = '.'; // replace '/' with '.' in package name +- } +- return name; +- } +-} +- + static bool is_prohibited_package_slow(Symbol* class_name) { + // Caller has ResourceMark + int length; +@@ -1252,6 +1239,18 @@ void SystemDictionary::set_shared_dictionary(HashtableBucket* t, int le + _shared_dictionary = new Dictionary(_nof_buckets, t, number_of_entries); + } + ++static char* convert_into_package_name(char* name) { ++ char* index = strrchr(name, '/'); ++ if (index == NULL) { ++ return NULL; ++ } else { ++ *index = '\0'; // chop to just the package name ++ while ((index = strchr(name, '/')) != NULL) { ++ *index = '.'; // replace '/' with '.' in package name ++ } ++ return name; ++ } ++} + + // If there is a shared dictionary, then find the entry for the + // given shared system class, if any. +@@ -1267,7 +1266,6 @@ Klass* SystemDictionary::find_shared_class(Symbol* class_name) { + } + } + +- + // Load a class from the shared spaces (found through the shared system + // dictionary). Force the superclass and all interfaces to be loaded. + // Update the class definition to include sibling classes and no +diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp +index 01666ea4d..deeca7bb5 100644 +--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp ++++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp +@@ -77,7 +77,7 @@ class PSMarkSweep : public MarkSweep { + + // Reset time since last full gc + static void reset_millis_since_last_gc(); +- static void ps_marksweep_init(); ++ static void ps_marksweep_init() NOT_ALL_GCS_RETURN; + + public: + static inline PSMarkSweep* the_ps_mark() { return (PSMarkSweep*)_the_ps_mark; } +diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp +index c27a534ef..f75501dba 100644 +--- a/hotspot/src/share/vm/prims/jvm.cpp ++++ b/hotspot/src/share/vm/prims/jvm.cpp +@@ -3303,20 +3303,32 @@ JVM_END + + JVM_ENTRY(void, JVM_AdaptiveHeapSetG1PeriodicGCInterval(JNIEnv *env, jclass klass, jint interval)) + JVMWrapper("JVM_AdaptiveHeapSetG1PeriodicGCInterval"); ++#if INCLUDE_ALL_GCS + G1PeriodicGCInterval = interval; ++#endif + JVM_END + JVM_ENTRY(jint, JVM_AdaptiveHeapGetG1PeriodicGCInterval(JNIEnv *env, jclass klass)) + JVMWrapper("JVM_AdaptiveHeapGetG1PeriodicGCInterval"); ++#if INCLUDE_ALL_GCS + return G1PeriodicGCInterval; ++#else ++ return -1; ++#endif + JVM_END + + JVM_ENTRY(void, JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold(JNIEnv *env, jclass clazz, jint loadThreshold)) + JVMWrapper("JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold"); ++#if INCLUDE_ALL_GCS + G1PeriodicGCLoadThreshold = loadThreshold; ++#endif + JVM_END + JVM_ENTRY(jint, JVM_AdaptiveHeapGetG1PeriodicGCLoadThreshold(JNIEnv *env, jclass clazz)) + JVMWrapper("JVM_AdaptiveHeapgetG1PeriodicGCLoadThreshold"); ++#if INCLUDE_ALL_GCS + return G1PeriodicGCLoadThreshold; ++#else ++ return -1; ++#endif + JVM_END + + JVM_ENTRY(void, JVM_Yield(JNIEnv *env, jclass threadClass)) +diff --git a/hotspot/src/share/vm/runtime/memprofiler.cpp b/hotspot/src/share/vm/runtime/memprofiler.cpp +index ddb22601f..a956c5252 100644 +--- a/hotspot/src/share/vm/runtime/memprofiler.cpp ++++ b/hotspot/src/share/vm/runtime/memprofiler.cpp +@@ -126,7 +126,7 @@ void MemProfiler::do_trace() { + + fprintf(_log_fp, UINTX_FORMAT_W(6) ",", CodeCache::capacity() / K); + +- fprintf(_log_fp, UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) "\n", ++ fprintf(_log_fp, UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",%6ld\n", + handles_memory_usage / K, + resource_memory_usage / K, + 0L); +diff --git a/hotspot/src/share/vm/utilities/taskqueue.cpp b/hotspot/src/share/vm/utilities/taskqueue.cpp +index 120c65a60..7c6849c63 100644 +--- a/hotspot/src/share/vm/utilities/taskqueue.cpp ++++ b/hotspot/src/share/vm/utilities/taskqueue.cpp +@@ -273,10 +273,12 @@ void ParallelTaskTerminator::reset_for_reuse(int n_threads) { + _n_threads = n_threads; + } + ++#if INCLUDE_ALL_GCS + TaskTerminator::TaskTerminator(uint n_threads, TaskQueueSetSuper* queue_set) : + _terminator(UseOWSTTaskTerminator ? new OWSTTaskTerminator(n_threads, queue_set) + : new ParallelTaskTerminator(n_threads, queue_set)) { + } ++#endif + + TaskTerminator::~TaskTerminator() { + if (_terminator != NULL) { +diff --git a/hotspot/src/share/vm/utilities/taskqueue.hpp b/hotspot/src/share/vm/utilities/taskqueue.hpp +index 959d0dd21..284675708 100644 +--- a/hotspot/src/share/vm/utilities/taskqueue.hpp ++++ b/hotspot/src/share/vm/utilities/taskqueue.hpp +@@ -763,7 +763,7 @@ private: + TaskTerminator(const TaskTerminator& o) { } + TaskTerminator& operator=(TaskTerminator& o) { return *this; } + public: +- TaskTerminator(uint n_threads, TaskQueueSetSuper* queue_set); ++ TaskTerminator(uint n_threads, TaskQueueSetSuper* queue_set) NOT_ALL_GCS_RETURN; + ~TaskTerminator(); + + // Move assignment +@@ -929,4 +929,4 @@ typedef OverflowTaskQueue RegionTaskQueue; + typedef GenericTaskQueueSet RegionTaskQueueSet; + + +-#endif // SHARE_VM_UTILITIES_TASKQUEUE_HPP +\ No newline at end of file ++#endif // SHARE_VM_UTILITIES_TASKQUEUE_HPP +diff --git a/jdk/src/share/native/com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.c b/jdk/src/share/native/com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.c +index 99bfff885..0e365d7aa 100644 +--- a/jdk/src/share/native/com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.c ++++ b/jdk/src/share/native/com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.c +@@ -31,7 +31,6 @@ static JNINativeMethod methods[] = { + {"getG1PeriodicGCIntervalImpl", "()I", (void *)&JVM_AdaptiveHeapGetG1PeriodicGCInterval}, + {"setG1PeriodicGCLoadThresholdImpl", "(I)V", (void *)&JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold}, + {"getG1PeriodicGCLoadThresholdImpl", "()I", (void *)&JVM_AdaptiveHeapGetG1PeriodicGCLoadThreshold}, +- + }; + + JNIEXPORT void JNICALL +-- +2.12.3 + diff --git a/improve_algorithmConstraints_checkAlgorithm_performance.patch b/Improve_AlgorithmConstraints_checkAlgorithm_performance.patch old mode 100755 new mode 100644 similarity index 90% rename from improve_algorithmConstraints_checkAlgorithm_performance.patch rename to Improve_AlgorithmConstraints_checkAlgorithm_performance.patch index 025a379bf25ec534b537a9b40c35897e2b2343b9..cf5c5e4aec61758983d6babbaea063ed07d2f9ae --- a/improve_algorithmConstraints_checkAlgorithm_performance.patch +++ b/Improve_AlgorithmConstraints_checkAlgorithm_performance.patch @@ -1,5 +1,17 @@ +From 4e520a51acbb192a0df844fcca247998d7fb8854 Mon Sep 17 00:00:00 2001 +From: wangkun +Date: Thu, 28 Jul 2022 17:19:32 +0800 +Subject: [PATCH 2/3] add + Improve-AlgorithmConstraints-checkAlgorithm-performa.patch + +--- + .../util/AbstractAlgorithmConstraints.java | 30 +++++++------------ + .../util/DisabledAlgorithmConstraints.java | 20 +++++++++---- + .../util/LegacyAlgorithmConstraints.java | 12 ++++++-- + 3 files changed, 35 insertions(+), 27 deletions(-) + diff --git a/jdk/src/share/classes/sun/security/util/AbstractAlgorithmConstraints.java b/jdk/src/share/classes/sun/security/util/AbstractAlgorithmConstraints.java -index 944958de4..5c7602925 100644 +index 944958de..5c760292 100644 --- a/jdk/src/share/classes/sun/security/util/AbstractAlgorithmConstraints.java +++ b/jdk/src/share/classes/sun/security/util/AbstractAlgorithmConstraints.java @@ -77,34 +77,26 @@ public abstract class AbstractAlgorithmConstraints @@ -49,7 +61,7 @@ index 944958de4..5c7602925 100644 return true; diff --git a/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java -index 51e625632..6ff26bf2f 100644 +index 51e62563..6ff26bf2 100644 --- a/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java +++ b/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java @@ -96,7 +96,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { @@ -99,7 +111,7 @@ index 51e625632..6ff26bf2f 100644 /* diff --git a/jdk/src/share/classes/sun/security/util/LegacyAlgorithmConstraints.java b/jdk/src/share/classes/sun/security/util/LegacyAlgorithmConstraints.java -index 4e7502fb5..01d0447ab 100644 +index 4e7502fb..01d0447a 100644 --- a/jdk/src/share/classes/sun/security/util/LegacyAlgorithmConstraints.java +++ b/jdk/src/share/classes/sun/security/util/LegacyAlgorithmConstraints.java @@ -28,6 +28,7 @@ package sun.security.util; @@ -132,3 +144,6 @@ index 4e7502fb5..01d0447ab 100644 } @Override +-- +2.22.0 + diff --git a/The-code-style-is-fixed-and-test-cases-are-added.patch b/The-code-style-is-fixed-and-test-cases-are-added.patch new file mode 100644 index 0000000000000000000000000000000000000000..9219f3dddf289dd403c4ed554b9269d2494aa417 --- /dev/null +++ b/The-code-style-is-fixed-and-test-cases-are-added.patch @@ -0,0 +1,529 @@ +From 0a877e963eeb55b98dcd0194ac44b4f010d382eb Mon Sep 17 00:00:00 2001 +Date: Wed, 21 Sep 2022 09:54:56 +0800 +Subject: The code style is fixed and test cases are added + +--- + hotspot/src/share/vm/cds/archiveBuilder.hpp | 1 - + hotspot/src/share/vm/cds/archiveUtils.hpp | 1 - + hotspot/src/share/vm/cds/dynamicArchive.hpp | 1 - + .../share/vm/classfile/systemDictionary.cpp | 2 +- + .../vm/classfile/systemDictionaryShared.hpp | 1 + + .../shared/parGCAllocBuffer.cpp | 6 +- + hotspot/src/share/vm/memory/filemap.cpp | 7 +- + hotspot/src/share/vm/memory/filemap.hpp | 2 +- + .../src/share/vm/memory/metaspaceClosure.cpp | 25 + + .../src/share/vm/memory/metaspaceClosure.hpp | 25 +- + hotspot/src/share/vm/oops/cpCache.cpp | 1 - + hotspot/src/share/vm/oops/instanceKlass.cpp | 4 - + hotspot/test/runtime/6929067/Test6929067.sh | 2 +- + .../runtime/InitialThreadOverflow/testme.sh | 2 +- + hotspot/test/runtime/Thread/StopAtExit.java | 119 ++++ + jdk/make/profile-rtjar-includes.txt | 7 +- + .../classes/java/io/ObjectInputStream.java | 4 +- + .../classes/java/io/ObjectOutputStream.java | 10 +- + .../classes/sun/awt/FontConfiguration.java | 7 +- + .../security/openssl/kae_cipher_rsa.c | 3 +- + .../security/openssl/kae_keyagreement_dh.c | 4 +- + .../openssl/RSAKeyPairGeneratorBenchmark.java | 2 +- + 23 files changed, 194 insertions(+), 668 deletions(-) + create mode 100644 hotspot/test/runtime/Thread/StopAtExit.java + +diff --git a/hotspot/src/share/vm/cds/archiveBuilder.hpp b/hotspot/src/share/vm/cds/archiveBuilder.hpp +index f7a5c107..93c0e245 100644 +--- a/hotspot/src/share/vm/cds/archiveBuilder.hpp ++++ b/hotspot/src/share/vm/cds/archiveBuilder.hpp +@@ -29,7 +29,6 @@ + #include "cds/archiveUtils.hpp" + #include "cds/dumpAllocStats.hpp" + #include "memory/metaspaceClosure.hpp" +-//#include "oops/array.hpp" + #include "oops/klass.hpp" + #include "runtime/os.hpp" + #include "utilities/align.hpp" +diff --git a/hotspot/src/share/vm/cds/archiveUtils.hpp b/hotspot/src/share/vm/cds/archiveUtils.hpp +index 55c2431a..44f03c8e 100644 +--- a/hotspot/src/share/vm/cds/archiveUtils.hpp ++++ b/hotspot/src/share/vm/cds/archiveUtils.hpp +@@ -133,7 +133,6 @@ public: + _dump_region->append_intptr_t((intptr_t)tag); + } + +- //void do_oop(oop* o); + void do_region(u_char* start, size_t size); + bool reading() const { return false; } + }; +diff --git a/hotspot/src/share/vm/cds/dynamicArchive.hpp b/hotspot/src/share/vm/cds/dynamicArchive.hpp +index 1d5b7122..0e068e65 100644 +--- a/hotspot/src/share/vm/cds/dynamicArchive.hpp ++++ b/hotspot/src/share/vm/cds/dynamicArchive.hpp +@@ -26,7 +26,6 @@ + #ifndef SHARE_VM_CDS_DYNAMICARCHIVE_HPP + #define SHARE_VM_CDS_DYNAMICARCHIVE_HPP + +-//#include "classfile/compactHashtable.hpp" + #include "memory/allocation.hpp" + #include "memory/filemap.hpp" + #include "memory/memRegion.hpp" +diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp +index 2eebdbac..0ea2d9b7 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp ++++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp +@@ -1344,7 +1344,7 @@ instanceKlassHandle SystemDictionary::load_shared_class( + Handle klass_name = java_lang_String::create_from_str(name, CHECK_0); + JavaValue result(T_OBJECT); + +- // load_shared_class need protected domain to handle non-bootstrap loaded class, ++ // load_shared_class need protected domain to handle non-bootstrap loaded class, + // so here call_virtual to call getProtectionDomainInternal function of URLClassLoader.java, + // to get protected domain and save into result. + JavaCalls::call_virtual(&result, +diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +index 36423bee..fb9583d4 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp ++++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +@@ -194,6 +194,7 @@ public: + } + return true; + } ++ + static size_t estimate_size_for_archive(); + static void write_to_archive(); + static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin); +diff --git a/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp b/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp +index bddf14b6..0244bf84 100644 +--- a/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp ++++ b/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp +@@ -98,9 +98,9 @@ void PLABStats::adjust_desired_plab_sz(uint no_of_gc_workers) { + if (_allocated == 0) { + assert(_unused == 0, + err_msg("Inconsistency in PLAB stats: " +- "_allocated: "SIZE_FORMAT", " +- "_wasted: "SIZE_FORMAT", " +- "_unused: "SIZE_FORMAT", " ++ "_allocated: " SIZE_FORMAT ", " ++ "_wasted: " SIZE_FORMAT ", " ++ "_unused: " SIZE_FORMAT ", " + "_used : "SIZE_FORMAT, + _allocated, _wasted, _unused, _used)); + +diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp +index 1891fc80..0682cd67 100644 +--- a/hotspot/src/share/vm/memory/filemap.cpp ++++ b/hotspot/src/share/vm/memory/filemap.cpp +@@ -240,12 +240,7 @@ void FileMapInfo::FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment + _version = current_version(); + _alignment = alignment; + _obj_alignment = ObjectAlignmentInBytes; +- /* TODO +- _compressed_oops = UseCompressedOops; +- _compressed_class_ptrs = UseCompressedClassPointers; +- _max_heap_size = MaxHeapSize; +- _narrow_klass_shift = CompressedKlassPointers::shift(); +- */ ++ + if (!DynamicDumpSharedSpaces) { + _classpath_entry_table_size = mapinfo->_classpath_entry_table_size; + _classpath_entry_table = mapinfo->_classpath_entry_table; +diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp +index 36b27f13..27fff35e 100644 +--- a/hotspot/src/share/vm/memory/filemap.hpp ++++ b/hotspot/src/share/vm/memory/filemap.hpp +@@ -232,7 +232,7 @@ public: + char* region_end(int i) { return region_base(i) + used_aligned(i); } + struct FileMapHeader* header() { return _header; } + struct DynamicArchiveHeader* dynamic_header() { +- // assert(!is_static(), "must be"); ++ + return (struct DynamicArchiveHeader*)header(); + } + +diff --git a/hotspot/src/share/vm/memory/metaspaceClosure.cpp b/hotspot/src/share/vm/memory/metaspaceClosure.cpp +index 00ec8fce..e19402cb 100644 +--- a/hotspot/src/share/vm/memory/metaspaceClosure.cpp ++++ b/hotspot/src/share/vm/memory/metaspaceClosure.cpp +@@ -1,3 +1,28 @@ ++/* ++ * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ + #include "precompiled.hpp" + #include "memory/metaspaceClosure.hpp" + +diff --git a/hotspot/src/share/vm/memory/metaspaceClosure.hpp b/hotspot/src/share/vm/memory/metaspaceClosure.hpp +index f67d8d6f..5422e2a0 100644 +--- a/hotspot/src/share/vm/memory/metaspaceClosure.hpp ++++ b/hotspot/src/share/vm/memory/metaspaceClosure.hpp +@@ -1,4 +1,27 @@ +- ++/* ++ * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ + + #ifndef SHARE_VM_MEMORY_METASPACECLOSURE_HPP + #define SHARE_VM_MEMORY_METASPACECLOSURE_HPP +diff --git a/hotspot/src/share/vm/oops/cpCache.cpp b/hotspot/src/share/vm/oops/cpCache.cpp +index 51f5397b..874cef41 100644 +--- a/hotspot/src/share/vm/oops/cpCache.cpp ++++ b/hotspot/src/share/vm/oops/cpCache.cpp +@@ -610,7 +610,6 @@ void ConstantPoolCache::metaspace_pointers_do(MetaspaceClosure* it) { + dynamic_cds_log->print_cr("Iter(ConstantPoolCache): %p", this); + } + it->push(&_constant_pool); +- // it->push(&_reference_map); + } + + void ConstantPoolCache::remove_unshareable_info() { +diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp +index 9276b895..2a9cd92d 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.cpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.cpp +@@ -526,10 +526,6 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) { + } + } + } +- +- // it->push(&_nest_members); +- // it->push(&_permitted_subclasses); +- // it->push(&_record_components); + } + + klassVtable* InstanceKlass::vtable() const { +diff --git a/hotspot/test/runtime/6929067/Test6929067.sh b/hotspot/test/runtime/6929067/Test6929067.sh +index 438a287c..c78e1787 100644 +--- a/hotspot/test/runtime/6929067/Test6929067.sh ++++ b/hotspot/test/runtime/6929067/Test6929067.sh +@@ -102,7 +102,7 @@ esac + + + if [ "${VM_CPU}" == "aarch64" ]; then +- COMP_FLAG="-mabi=lp64" ++ COMP_FLAG="" + fi + + # VM type: need to know server or client +diff --git a/hotspot/test/runtime/InitialThreadOverflow/testme.sh b/hotspot/test/runtime/InitialThreadOverflow/testme.sh +index ffd7d6e3..cf48c2fe 100644 +--- a/hotspot/test/runtime/InitialThreadOverflow/testme.sh ++++ b/hotspot/test/runtime/InitialThreadOverflow/testme.sh +@@ -52,7 +52,7 @@ fi + CFLAGS="-m${VM_BITS}" + + if [ "${VM_CPU}" == "aarch64" ]; then +- CFLAGS="-mabi=lp64" ++ CFLAGS="" + fi + + LD_LIBRARY_PATH=.:${COMPILEJAVA}/jre/lib/${VM_CPU}/${VM_TYPE}:/usr/lib:$LD_LIBRARY_PATH +diff --git a/hotspot/test/runtime/Thread/StopAtExit.java b/hotspot/test/runtime/Thread/StopAtExit.java +new file mode 100644 +index 00000000..8d6344a6 +--- /dev/null ++++ b/hotspot/test/runtime/Thread/StopAtExit.java +@@ -0,0 +1,119 @@ ++/* ++ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++/** ++ * @test ++ * @bug 8167108 ++ * @summary Stress test java.lang.Thread.stop() at thread exit. ++ * @run main/othervm StopAtExit ++ */ ++ ++import java.util.concurrent.CountDownLatch; ++import java.util.concurrent.TimeUnit; ++ ++public class StopAtExit extends Thread { ++ final static int N_THREADS = 32; ++ final static int N_LATE_CALLS = 1000; ++ ++ public CountDownLatch exitSyncObj = new CountDownLatch(1); ++ public CountDownLatch startSyncObj = new CountDownLatch(1); ++ ++ @Override ++ public void run() { ++ try { ++ // Tell main thread we have started. ++ startSyncObj.countDown(); ++ try { ++ // Wait for main thread to interrupt us so we ++ // can race to exit. ++ exitSyncObj.await(); ++ } catch (InterruptedException e) { ++ // ignore because we expect one ++ } ++ } catch (ThreadDeath td) { ++ // ignore because we're testing Thread.stop() which throws it ++ } catch (NoClassDefFoundError ncdfe) { ++ // ignore because we're testing Thread.stop() which can cause it ++ } ++ } ++ ++ public static void main(String[] args) { ++ StopAtExit threads[] = new StopAtExit[N_THREADS]; ++ ++ for (int i = 0; i < N_THREADS; i++ ) { ++ threads[i] = new StopAtExit(); ++ int late_count = 1; ++ threads[i].start(); ++ try { ++ // Wait for the worker thread to get going. ++ threads[i].startSyncObj.await(); ++ ++ // This interrupt() call will break the worker out ++ // of the exitSyncObj.await() call and the stop() ++ // calls will come in during thread exit. ++ threads[i].interrupt(); ++ for (; late_count <= N_LATE_CALLS; late_count++) { ++ threads[i].stop(); ++ ++ if (!threads[i].isAlive()) { ++ // Done with Thread.stop() calls since ++ // thread is not alive. ++ break; ++ } ++ } ++ } catch (InterruptedException e) { ++ throw new Error("Unexpected: " + e); ++ } catch (NoClassDefFoundError ncdfe) { ++ // Ignore because we're testing Thread.stop() which can ++ // cause it. Yes, a NoClassDefFoundError that happens ++ // in a worker thread can subsequently be seen in the ++ // main thread. ++ } ++ ++ System.out.println("INFO: thread #" + i + ": made " + late_count + ++ " late calls to java.lang.Thread.stop()"); ++ System.out.println("INFO: thread #" + i + ": N_LATE_CALLS==" + ++ N_LATE_CALLS + " value is " + ++ ((late_count >= N_LATE_CALLS) ? "NOT " : "") + ++ "large enough to cause a Thread.stop() " + ++ "call after thread exit."); ++ ++ try { ++ threads[i].join(); ++ } catch (InterruptedException e) { ++ throw new Error("Unexpected: " + e); ++ } ++ threads[i].stop(); ++ if (threads[i].isAlive()) { ++ throw new Error("Expected !Thread.isAlive() after thread #" + ++ i + " has been join()'ed"); ++ } ++ } ++ ++ String cmd = System.getProperty("sun.java.command"); ++ if (cmd != null && !cmd.startsWith("com.sun.javatest.regtest.agent.MainWrapper")) { ++ // Exit with success in a non-JavaTest environment: ++ System.exit(0); ++ } ++ } ++} +diff --git a/jdk/make/profile-rtjar-includes.txt b/jdk/make/profile-rtjar-includes.txt +index f36d1d5c..dd275590 100644 +--- a/jdk/make/profile-rtjar-includes.txt ++++ b/jdk/make/profile-rtjar-includes.txt +@@ -73,8 +73,8 @@ PROFILE_1_RTJAR_INCLUDE_PACKAGES := \ + + PROFILE_1_RTJAR_INCLUDE_TYPES := + +-PROFILE_1_RTJAR_EXCLUDE_TYPES := +- ++PROFILE_1_RTJAR_EXCLUDE_TYPES := \ ++ com/huawei + PROFILE_1_INCLUDE_METAINF_SERVICES := + + +@@ -99,7 +99,8 @@ PROFILE_2_RTJAR_INCLUDE_PACKAGES := \ + + PROFILE_2_RTJAR_INCLUDE_TYPES := + +-PROFILE_2_RTJAR_EXCLUDE_TYPES := ++PROFILE_2_RTJAR_EXCLUDE_TYPES := \ ++ com/huawei + + PROFILE_2_INCLUDE_METAINF_SERVICES := \ + META-INF/services/sun.util.spi.XmlPropertiesProvider +diff --git a/jdk/src/share/classes/java/io/ObjectInputStream.java b/jdk/src/share/classes/java/io/ObjectInputStream.java +index af6c5dd6..85e3958b 100644 +--- a/jdk/src/share/classes/java/io/ObjectInputStream.java ++++ b/jdk/src/share/classes/java/io/ObjectInputStream.java +@@ -768,7 +768,7 @@ public class ObjectInputStream + * Cache the class meta during serialization. + * Only used in FastSerilizer. + */ +- protected static ConcurrentHashMap> nameToClass = new ConcurrentHashMap<>(); ++ private static ConcurrentHashMap> nameToClass = new ConcurrentHashMap<>(); + + /** + * Load the local class equivalent of the specified stream class +@@ -1013,7 +1013,7 @@ public class ObjectInputStream + + if (s0 != STREAM_MAGIC) { + throw new StreamCorruptedException( +- String.format("invalid stream header: %04X%04X, and FastSerializer is activated", s0, s1)); ++ String.format("invalid stream header: %04X%04X", s0, s1)); + } + + if (!fastSerializerEscapeMode) { +diff --git a/jdk/src/share/classes/java/io/ObjectOutputStream.java b/jdk/src/share/classes/java/io/ObjectOutputStream.java +index 840f7fdc..23c1fff5 100644 +--- a/jdk/src/share/classes/java/io/ObjectOutputStream.java ++++ b/jdk/src/share/classes/java/io/ObjectOutputStream.java +@@ -234,11 +234,6 @@ public class ObjectOutputStream + new sun.security.action.GetBooleanAction( + "sun.io.serialization.extendedDebugInfo")).booleanValue(); + +- /** +- * Magic number that is written to the stream header when using fastserilizer. +- */ +- private static final short STREAM_MAGIC_FAST = (short)0xdeca; +- + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + /** +@@ -255,6 +250,11 @@ public class ObjectOutputStream + new sun.security.action.GetBooleanAction( + "printFastSerializer")).booleanValue(); + ++ /** ++ * Magic number that is written to the stream header when using fastserilizer. ++ */ ++ private static final short STREAM_MAGIC_FAST = (short)0xdeca; ++ + /** + * Creates an ObjectOutputStream that writes to the specified OutputStream. + * This constructor writes the serialization stream header to the +diff --git a/jdk/src/share/classes/sun/awt/FontConfiguration.java b/jdk/src/share/classes/sun/awt/FontConfiguration.java +index 93e38e06..c2e94d15 100644 +--- a/jdk/src/share/classes/sun/awt/FontConfiguration.java ++++ b/jdk/src/share/classes/sun/awt/FontConfiguration.java +@@ -300,12 +300,7 @@ public abstract class FontConfiguration { + } + } + foundOsSpecificFile = false; +- +- configFile = findImpl(baseName); +- if (configFile != null) { +- return configFile; +- } +- return null; ++ return (configFile = findImpl(baseName)); + } + + /* Initialize the internal data tables from binary format font +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c +index 73b94cbe..d9b16ab9 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c +@@ -174,6 +174,7 @@ static int RSACryptOAEPPadding(JNIEnv* env, jlong keyAddress, jint inLen, jbyteA + jbyte* inBytes = NULL; + // outLen type should be size_t + // EVP_PKEY_encrypt takes the outLen address as a parameter, and the parameter type is size_t* ++ // You can refer to the issue #2774 to see more content + size_t outLen = 0; + ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); + KAE_TRACE("RSACryptOAEPPadding: kaeEngine => %p", kaeEngine); +@@ -366,7 +367,7 @@ JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeC + } + + // set rsa public key params n and e +- if(RSA_set0_key(rsa, bnN, bnE, NULL) <= 0) { ++ if (RSA_set0_key(rsa, bnN, bnE, NULL) <= 0) { + KAE_ThrowFromOpenssl(env, "RSA_set0_key", KAE_ThrowRuntimeException); + goto cleanup; + } +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keyagreement_dh.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keyagreement_dh.c +index 90b33045..d8d2ee7c 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keyagreement_dh.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keyagreement_dh.c +@@ -131,9 +131,9 @@ cleanup: + if (g_bn != NULL) + KAE_ReleaseBigNumFromByteArray(g_bn); + if (secret != NULL) +- free(secret); ++ free(secret); + if (computeKeyRetBn != NULL) +- BN_free(computeKeyRetBn); ++ BN_free(computeKeyRetBn); + + return retByteArray; + } +diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java +index b1739222..13d3e8cf 100644 +--- a/jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java ++++ b/jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java +@@ -54,7 +54,7 @@ public class RSAKeyPairGeneratorBenchmark extends BenchmarkBase { + public KeyPair generateKeyPair() throws Exception { + return keyPairGenerator.generateKeyPair(); + } +- ++ + private KeyPairGenerator createKeyPairGenerator() throws Exception { + if (prov != null) { + return KeyPairGenerator.getInstance(algorithm, prov); +-- +2.22.0 + diff --git a/add-DumpSharedSpace-guarantee-when-create-anonymous-classes.patch b/add-DumpSharedSpace-guarantee-when-create-anonymous-classes.patch index 85ff56193248923a9450520c194454c86287486c..1a8df78fabbe1177bdc7d95f012ae212dce49756 100644 --- a/add-DumpSharedSpace-guarantee-when-create-anonymous-classes.patch +++ b/add-DumpSharedSpace-guarantee-when-create-anonymous-classes.patch @@ -17,7 +17,7 @@ index f20bf3d2b..3ab82c5c4 100644 + if (DumpSharedSpaces) { + tty->print_cr("failed: must not create anonymous classes when dumping."); -+ JVM_Exit(0); ++ JVM_Halt(0); + } + if (UsePerfData) { diff --git a/add-appcds-file-lock.patch b/add-appcds-file-lock.patch index f422f5469d2bfc53b87b2260b3cbb049f4b3e6f1..b34121e7c043dc09fc893d87ab4fbffb9e2928a5 100644 --- a/add-appcds-file-lock.patch +++ b/add-appcds-file-lock.patch @@ -224,7 +224,7 @@ index 17447587..d2095e63 100644 + tty->print_cr("The lock path is: %s", _appcds_file_lock_path); + tty->print_cr("Failed to create jsa file !\n Please check: \n 1. The directory exists.\n " + "2. You have the permission.\n 3. Make sure no other process using the same lock file.\n"); -+ JVM_Exit(0); ++ JVM_Halt(0); + } + tty->print_cr("You are using file lock %s in concurrent mode", AppCDSLockFile); + } diff --git a/add-configuration-option-of-huawei-internal-version-shown-in-release-file.patch b/add-configuration-option-of-huawei-internal-version-shown-in-release-file.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb2c2625ba5fd3ddb226ba447323b69d9431a2aa --- /dev/null +++ b/add-configuration-option-of-huawei-internal-version-shown-in-release-file.patch @@ -0,0 +1,111 @@ +From 59040a3951dfdf21ba646cc9510739f175751469 Mon Sep 17 00:00:00 2001 +Date: Wed, 21 Sep 2022 09:54:04 +0800 +Subject: [PATCH 2/5] add configuration option of huawei internal version shown in release file + +--- + common/autoconf/generated-configure.sh | 17 +++++++++++++++++ + common/autoconf/jdk-options.m4 | 11 +++++++++++ + common/autoconf/spec.gmk.in | 3 +++ + jdk/make/Images.gmk | 1 + + 4 files changed, 32 insertions(+) + +diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh +index 53e6cf18..a6ba1ac9 100644 +--- a/common/autoconf/generated-configure.sh ++++ b/common/autoconf/generated-configure.sh +@@ -831,6 +831,7 @@ COPYRIGHT_YEAR + VENDOR_URL_VM_BUG + VENDOR_URL_BUG + VENDOR_URL ++INTERNAL_VERSION + COMPANY_NAME + MACOSX_BUNDLE_ID_BASE + MACOSX_BUNDLE_NAME_BASE +@@ -1077,6 +1078,7 @@ with_vendor_url + with_vendor_bug_url + with_vendor_vm_bug_url + with_copyright_year ++with_internal_version + with_boot_jdk + with_boot_jdk_jvmargs + with_add_source_root +@@ -1937,6 +1939,9 @@ Optional Packages: + --with-vendor-vm-bug-url + Sets the bug URL which will be displayed when the VM + crashes [not specified] ++ --with-internal-version ++ Sets the internal version which will be ++ displayed in the release file [not specified] + --with-copyright-year Set copyright year value for build [current year] + --with-boot-jdk path to Boot JDK (used to bootstrap build) [probed] + --with-boot-jdk-jvmargs specify JVM arguments to be passed to all +@@ -20301,6 +20306,18 @@ fi + COPYRIGHT_YEAR=`date +'%Y'` + fi + ++# Check whether --with-internal-version was given. ++if test "${with_internal_version+set}" = set; then : ++ withval=$with_internal_version; ++fi ++ ++ if test "x$with_internal_version" = xyes; then ++ as_fn_error $? "--with-internal-version must have a value" "$LINENO" 5 ++ elif ! [[ $with_internal_version =~ ^[[:print:]]*$ ]] ; then ++ as_fn_error $? "--with-internal-version contains non-printing characters: $with_internal_version" "$LINENO" 5 ++ else ++ INTERNAL_VERSION="$with_internal_version" ++ fi + + if test "x$JDK_UPDATE_VERSION" != x; then + JDK_VERSION="${JDK_MAJOR_VERSION}.${JDK_MINOR_VERSION}.${JDK_MICRO_VERSION}_${JDK_UPDATE_VERSION}" +diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 +index c506086d..b9f25175 100644 +--- a/common/autoconf/jdk-options.m4 ++++ b/common/autoconf/jdk-options.m4 +@@ -627,6 +627,17 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_VERSION_NUMBERS], + fi + AC_SUBST(COPYRIGHT_YEAR) + ++ AC_ARG_WITH(internal-version, [AS_HELP_STRING([--with-internal-version], ++ [Sets the internal version which will be displayed in the release file @<:@not specified@:>@])]) ++ if test "x$with_internal_version" = xyes; then ++ AC_MSG_ERROR([--with-internal-version must have a value]) ++ elif [ ! [[ $with_internal_version =~ ^[[:print:]]*$ ]] ]; then ++ AC_MSG_ERROR([--with-internal-version contains non-printing characters: $with_internal_version]) ++ else ++ INTERNAL_VERSION="$with_internal_version" ++ fi ++ AC_SUBST(INTERNAL_VERSION) ++ + if test "x$JDK_UPDATE_VERSION" != x; then + JDK_VERSION="${JDK_MAJOR_VERSION}.${JDK_MINOR_VERSION}.${JDK_MICRO_VERSION}_${JDK_UPDATE_VERSION}" + else +diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in +index 79248cbf..ca5e2d74 100644 +--- a/common/autoconf/spec.gmk.in ++++ b/common/autoconf/spec.gmk.in +@@ -162,6 +162,9 @@ VENDOR_URL:=@VENDOR_URL@ + VENDOR_URL_BUG:=@VENDOR_URL_BUG@ + VENDOR_URL_VM_BUG:=@VENDOR_URL_VM_BUG@ + ++# Huawei internal version for use in release file. ++INTERNAL_VERSION:=@INTERNAL_VERSION@ ++ + # Location where build customization files may be found + CUSTOM_MAKE_DIR:=@CUSTOM_MAKE_DIR@ + +diff --git a/jdk/make/Images.gmk b/jdk/make/Images.gmk +index ac39ad33..233ce703 100644 +--- a/jdk/make/Images.gmk ++++ b/jdk/make/Images.gmk +@@ -618,6 +618,7 @@ define create-info-file + $(call info-file-item, "OS_ARCH", "$(OPENJDK_TARGET_CPU_LEGACY)") + if [ -n "$(JDK_ARCH_ABI_PROP_NAME)" ]; then $(call info-file-item, "SUN_ARCH_ABI", "$(JDK_ARCH_ABI_PROP_NAME)"); fi + $(call info-file-item, "SOURCE", "$(strip $(SOURCE_REVISION))") ++ if [ -n "$(INTERNAL_VERSION)" ]; then $(call info-file-item, "INTERNAL_VERSION", "$(INTERNAL_VERSION)"); fi + endef + + SOURCE_REVISION = $(shell \ +-- +2.22.0 + diff --git a/add-missing-test-case.patch b/add-missing-test-case.patch index e432247c8161497406d216d9d8cf56f375419caf..ef14a15d5ccea62fb9bef0a245a41ce851f6d82e 100644 --- a/add-missing-test-case.patch +++ b/add-missing-test-case.patch @@ -125,7 +125,7 @@ index 00000000..9b614024 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ -+8.292.8.0.13 ++8.352.8.0.13 -- 2.23.0 diff --git a/change-sa-jdi.jar-make-file-for-BEP.PATCH b/change-sa-jdi.jar-make-file-for-BEP.PATCH new file mode 100644 index 0000000000000000000000000000000000000000..21db586a7f5c20349f465230df7a43b40cd33bf0 --- /dev/null +++ b/change-sa-jdi.jar-make-file-for-BEP.PATCH @@ -0,0 +1,38 @@ +From 980b919fde4e1353a9ff989fb78031a48d395ec0 Mon Sep 17 00:00:00 2001 +From: zhangyipeng +Date: Fri, 6 May 2022 15:23:26 +0800 +Subject: [PATCH 02/10] change sa-jdi.jar make file for BEP + +--- + hotspot/make/linux/makefiles/sa.make | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/hotspot/make/linux/makefiles/sa.make b/hotspot/make/linux/makefiles/sa.make +index cdcb16a1a..6388d95c9 100644 +--- a/hotspot/make/linux/makefiles/sa.make ++++ b/hotspot/make/linux/makefiles/sa.make +@@ -50,6 +50,7 @@ SA_CLASSPATH = $(BOOT_JAVA_HOME)/lib/tools.jar + MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules + + AGENT_FILES_LIST := $(GENERATED)/agent.classes.list ++SA_CLASSDIR_JAR_CONTENTS := $(GENERATED)/sa.jar_contents + + SA_CLASSDIR = $(GENERATED)/saclasses + +@@ -104,8 +105,11 @@ $(GENERATED)/sa-jdi.jar:: $(AGENT_FILES) + $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/* + $(QUIETLY) cp $(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/ + $(QUIETLY) cp -r $(AGENT_SRC_DIR)/images/* $(SA_CLASSDIR)/ +- $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(SA_CLASSDIR)/ . +- $(QUIETLY) $(REMOTE) $(RUN.JAR) uf $@ -C $(AGENT_SRC_DIR) META-INF/services/com.sun.jdi.connect.Connector ++ $(QUIETLY) rm -f $(SA_CLASSDIR_JAR_CONTENTS) && touch $(SA_CLASSDIR_JAR_CONTENTS) ++ $(QUIETLY) find $(SA_CLASSDIR) -type f | sed 's|$(SA_CLASSDIR)/||g' >> $(SA_CLASSDIR_JAR_CONTENTS) ++ $(QUIETLY) cd $(AGENT_SRC_DIR) && $(REMOTE) $(RUN.JAR) cf $@ META-INF/services/com.sun.jdi.connect.Connector ++ $(QUIETLY) cd $(SA_CLASSDIR) && $(REMOTE) $(RUN.JAR) uf $@ @$(SA_CLASSDIR_JAR_CONTENTS) ++ $(QUIETLY) cd $(TOPDIR) + $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.x86.X86ThreadContext + $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext + $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.aarch64.AARCH64ThreadContext +-- +2.22.0 + diff --git a/cve-2022-37434-Fix-a-bug-when-getting-a-gzip-header-extra-field-with-inflate.patch b/cve-2022-37434-Fix-a-bug-when-getting-a-gzip-header-extra-field-with-inflate.patch new file mode 100644 index 0000000000000000000000000000000000000000..f02cbb3dc8f9ba437e6677f522b5922032eb5212 --- /dev/null +++ b/cve-2022-37434-Fix-a-bug-when-getting-a-gzip-header-extra-field-with-inflate.patch @@ -0,0 +1,30 @@ +From fa03b567552ecc1a2a91850c959220ab28f178dd Mon Sep 17 00:00:00 2001 +From: yangyudong +Date: Fri, 21 Oct 2022 12:02:55 +0800 +Subject: cve-2022-37434: Fix a bug when getting a gzip header extra + field with inflate(). + +Bug url: https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2022-37434 +--- + jdk/src/share/native/java/util/zip/zlib/inflate.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/jdk/src/share/native/java/util/zip/zlib/inflate.c b/jdk/src/share/native/java/util/zip/zlib/inflate.c +index ca904e744..63decdb19 100644 +--- a/jdk/src/share/native/java/util/zip/zlib/inflate.c ++++ b/jdk/src/share/native/java/util/zip/zlib/inflate.c +@@ -783,8 +783,9 @@ int flush; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && +- state->head->extra != Z_NULL) { +- len = state->head->extra_len - state->length; ++ state->head->extra != Z_NULL && ++ (len = state->head->extra_len - state->length) < ++ state->head->extra_max) { + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); +-- +2.22.0 + diff --git a/debuginfo.diz-should-not-contain-the-path-after-unzip.patch b/debuginfo.diz-should-not-contain-the-path-after-unzip.patch deleted file mode 100755 index 1f49d5f7761b0de3ef03d69f94a126e675408603..0000000000000000000000000000000000000000 --- a/debuginfo.diz-should-not-contain-the-path-after-unzip.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk -index 0e0346374..2d9bdbeed 100644 ---- a/make/common/NativeCompilation.gmk -+++ b/make/common/NativeCompilation.gmk -@@ -537,7 +537,7 @@ define SetupNativeCompilation - # to be rebuilt properly. - $$($1_DEBUGINFO_ZIP): $$($1_DEBUGINFO_FILES) $$($1_TARGET) - $(CD) $$($1_OBJECT_DIR) \ -- && $(ZIP) -q $$@ $$($1_DEBUGINFO_FILES) -+ && $(ZIP) -q $$@ $$(subst $$($1_OBJECT_DIR)/,,$$($1_DEBUGINFO_FILES)) - endif - else - ifneq ($$($1_STRIP_POLICY), no_strip) --- -2.22.0 - diff --git a/dynamic-cds-_header-and-_fd-handles-are-not-free.patch b/dynamic-cds-_header-and-_fd-handles-are-not-free.patch new file mode 100644 index 0000000000000000000000000000000000000000..e11210e9af5b4197ea704838d66ba9685d264177 --- /dev/null +++ b/dynamic-cds-_header-and-_fd-handles-are-not-free.patch @@ -0,0 +1,34 @@ +From cf12a2fae11baf41773308a48d9cfad9031f5344 Mon Sep 17 00:00:00 2001 +Date: Fri, 9 Sep 2022 11:26:22 +0800 +Subject: dynamic cds _header and _fd handles are not free. + +--- + hotspot/src/share/vm/memory/filemap.cpp | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp +index adb043f77..6549828e3 100644 +--- a/hotspot/src/share/vm/memory/filemap.cpp ++++ b/hotspot/src/share/vm/memory/filemap.cpp +@@ -169,6 +169,18 @@ FileMapInfo::~FileMapInfo() { + assert(_dynamic_archive_info == this, "must be singleton"); // not thread safe + _dynamic_archive_info = NULL; + } ++ ++ if (_header != NULL) { ++ delete _header; ++ } ++ ++ if (_file_open) { ++ if (::close(_fd) < 0) { ++ fail_stop("Unable to close the shared archive file."); ++ } ++ _file_open = false; ++ _fd = -1; ++ } + } + + void FileMapInfo::populate_header(size_t alignment) { +-- +2.22.0 + diff --git a/fix-appcds-s-option-AppCDSLockFile.patch b/fix-appcds-s-option-AppCDSLockFile.patch index 37eae2257c45f2bcc66a120258c935f344c009cd..88b6f4df2562877f78cb56b6e0b43672a8a3db71 100755 --- a/fix-appcds-s-option-AppCDSLockFile.patch +++ b/fix-appcds-s-option-AppCDSLockFile.patch @@ -33,7 +33,7 @@ index 5858c9355..99b1f58d0 100644 - tty->print_cr("The lock path is: %s", _appcds_file_lock_path); tty->print_cr("Failed to create jsa file !\n Please check: \n 1. The directory exists.\n " "2. You have the permission.\n 3. Make sure no other process using the same lock file.\n"); -- JVM_Exit(0); +- JVM_Halt(0); + fail_stop("Failed to create appcds lock file, the lock path is: %s.", _appcds_file_lock_path); } tty->print_cr("You are using file lock %s in concurrent mode", AppCDSLockFile); diff --git a/fix-dumped-heap-using-jhat-parsing-to-appear-failed-to-resolve-object-id-warning-message.patch b/fix-dumped-heap-using-jhat-parsing-to-appear-failed-to-resolve-object-id-warning-message.patch new file mode 100644 index 0000000000000000000000000000000000000000..f26dd692779fa3a48d12f78555f4ec509acb49d9 --- /dev/null +++ b/fix-dumped-heap-using-jhat-parsing-to-appear-failed-to-resolve-object-id-warning-message.patch @@ -0,0 +1,113 @@ +From 68293d50de005b5982a3cce437fc7af807d7264e Mon Sep 17 00:00:00 2001 +Date: Wed, 14 Sep 2022 14:57:25 +0800 +Subject: fix dumped heap using jhat parsing to appear failed to + resolve object id warning message + +--- + hotspot/src/share/vm/services/heapDumper.cpp | 5 -- + .../serviceability/dcmd/gc/HeapDumpTest.java | 77 +++++++++++++++++++ + 2 files changed, 77 insertions(+), 5 deletions(-) + create mode 100644 jdk/test/serviceability/dcmd/gc/HeapDumpTest.java + +diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp +index f7aba2a84..b5915c412 100644 +--- a/hotspot/src/share/vm/services/heapDumper.cpp ++++ b/hotspot/src/share/vm/services/heapDumper.cpp +@@ -984,11 +984,6 @@ void DumperSupport::dump_class_and_array_classes(DumpWriter* writer, Klass* k) { + return; + } + +- // Ignore the class if it hasn't been initialized yet +- if (!ik->is_linked()) { +- return; +- } +- + writer->write_u1(HPROF_GC_CLASS_DUMP); + + // class ID +diff --git a/jdk/test/serviceability/dcmd/gc/HeapDumpTest.java b/jdk/test/serviceability/dcmd/gc/HeapDumpTest.java +new file mode 100644 +index 000000000..7204c2c37 +--- /dev/null ++++ b/jdk/test/serviceability/dcmd/gc/HeapDumpTest.java +@@ -0,0 +1,77 @@ ++/* ++ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++import org.testng.annotations.Test; ++import org.testng.Assert; ++import java.io.File; ++import java.nio.file.Files; ++import java.io.IOException; ++import java.util.List; ++import jdk.test.lib.hprof.HprofParser; ++import jdk.test.lib.hprof.model.Snapshot; ++import jdk.test.lib.JDKToolFinder; ++import jdk.test.lib.process.OutputAnalyzer; ++import jdk.test.lib.dcmd.CommandExecutor; ++import jdk.test.lib.dcmd.PidJcmdExecutor; ++/* ++ * @test ++ * @summary Test of diagnostic command GC.heap_dump ++ * @library /lib ++ * @run testng HeapDumpTest ++ */ ++public class HeapDumpTest { ++ protected String heapDumpArgs = ""; ++ ++ public void run(CommandExecutor executor) throws IOException { ++ File dump = new File("jcmd.gc.heap_dump." + System.currentTimeMillis() + ".hprof"); ++ if (dump.exists()) { ++ dump.delete(); ++ } ++ ++ String cmd = "GC.heap_dump " + heapDumpArgs + " " + dump.getAbsolutePath(); ++ executor.execute(cmd); ++ ++ verifyHeapDump(dump); ++ dump.delete(); ++ } ++ private void verifyHeapDump(File dump) { ++ Assert.assertTrue(dump.exists() && dump.isFile(), "Could not create dump file " + dump.getAbsolutePath()); ++ try { ++ File out = HprofParser.parse(dump); ++ Assert.assertTrue(out != null && out.exists() && out.isFile(), "Could not find hprof parser output file"); ++ List lines = Files.readAllLines(out.toPath()); ++ Assert.assertTrue(lines.size() > 0, "hprof parser output file is empty"); ++ for (String line : lines) { ++ Assert.assertFalse(line.matches(".*WARNING(?!.*Failed to resolve object.*constantPoolOop.*).*")); ++ } ++ out.delete(); ++ } catch (Exception e) { ++ e.printStackTrace(); ++ Assert.fail("Could not parse dump file " + dump.getAbsolutePath()); ++ } ++ } ++ /* GC.heap_dump is not available over JMX, running jcmd pid executor instead */ ++ @Test ++ public void pid() throws IOException { ++ run(new PidJcmdExecutor()); ++ } ++} +-- +2.22.0 + diff --git a/fix-log-bug-enhance-aes-hmac-performance.patch b/fix-log-bug-enhance-aes-hmac-performance.patch index 48da9a117e036e931e20ab491019986206550437..6f42559b23943815edc84ecea5f6e3e1b93d3310 100644 --- a/fix-log-bug-enhance-aes-hmac-performance.patch +++ b/fix-log-bug-enhance-aes-hmac-performance.patch @@ -17,38 +17,10 @@ Signed-off-by: He Dongbo create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh -index 60298422f..bdfdd207b 100644 +index 27cff542..d19c772e 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh -@@ -4288,7 +4288,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" - - ################################################################################ - # The order of these defines the priority by which we try to find them. --VALID_VS_VERSIONS="2010 2012 2013 2015 2017" -+VALID_VS_VERSIONS="2010 2012 2013 2015 2017 2019" - - VS_DESCRIPTION_2010="Microsoft Visual Studio 2010" - VS_VERSION_INTERNAL_2010=100 -@@ -4346,6 +4346,18 @@ VS_SDK_INSTALLDIR_2017= - VS_VS_PLATFORM_NAME_2017="v141" - VS_SDK_PLATFORM_NAME_2017= - -+VS_DESCRIPTION_2019="Microsoft Visual Studio 2019 - CURRENTLY NOT WORKING" -+VS_VERSION_INTERNAL_2019=141 -+VS_MSVCR_2019=vcruntime140.dll -+VS_MSVCP_2019=msvcp140.dll -+VS_ENVVAR_2019="VS150COMNTOOLS" -+VS_USE_UCRT_2019="true" -+VS_VS_INSTALLDIR_2019="Microsoft Visual Studio/2019" -+VS_EDITIONS_2019="Community Professional Enterprise" -+VS_SDK_INSTALLDIR_2019= -+VS_VS_PLATFORM_NAME_2019="v141" -+VS_SDK_PLATFORM_NAME_2019= -+ - ################################################################################ - - -@@ -25694,10 +25706,10 @@ $as_echo "$as_me: Valid Visual Studio versions: $VALID_VS_VERSIONS." >&6;} +@@ -25937,10 +25937,10 @@ $as_echo "$as_me: Valid Visual Studio versions: $VALID_VS_VERSIONS." >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS_BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS_BASE using $METHOD" >&6;} if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then @@ -61,7 +33,7 @@ index 60298422f..bdfdd207b 100644 fi for VCVARSFILE in $VCVARSFILES; do -@@ -25751,10 +25763,10 @@ $as_echo "$as_me: Warning: None of $VCVARSFILES were found, Visual Studio instal +@@ -25994,10 +25994,10 @@ $as_echo "$as_me: Warning: None of $VCVARSFILES were found, Visual Studio instal { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS_BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS_BASE using $METHOD" >&6;} if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then @@ -74,7 +46,7 @@ index 60298422f..bdfdd207b 100644 fi for VCVARSFILE in $VCVARSFILES; do -@@ -25790,8 +25802,6 @@ $as_echo "$as_me: directory within the Visual Studio installation" >&6;} +@@ -26033,8 +26033,6 @@ $as_echo "$as_me: directory within the Visual Studio installation" >&6;} fi fi @@ -83,7 +55,7 @@ index 60298422f..bdfdd207b 100644 if test "x$VS_COMNTOOLS" != x; then if test "x$VS_ENV_CMD" = x; then -@@ -25824,10 +25834,10 @@ $as_echo "$as_me: directory within the Visual Studio installation" >&6;} +@@ -26067,10 +26065,10 @@ $as_echo "$as_me: directory within the Visual Studio installation" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS_BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS_BASE using $METHOD" >&6;} if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then @@ -96,7 +68,7 @@ index 60298422f..bdfdd207b 100644 fi for VCVARSFILE in $VCVARSFILES; do -@@ -25883,10 +25893,10 @@ $as_echo "$as_me: Warning: None of $VCVARSFILES were found, Visual Studio instal +@@ -26126,10 +26124,10 @@ $as_echo "$as_me: Warning: None of $VCVARSFILES were found, Visual Studio instal { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS_BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS_BASE using $METHOD" >&6;} if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then @@ -109,7 +81,7 @@ index 60298422f..bdfdd207b 100644 fi for VCVARSFILE in $VCVARSFILES; do -@@ -25944,10 +25954,10 @@ $as_echo "$as_me: Warning: None of $VCVARSFILES were found, Visual Studio instal +@@ -26187,10 +26185,10 @@ $as_echo "$as_me: Warning: None of $VCVARSFILES were found, Visual Studio instal { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS_BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS_BASE using $METHOD" >&6;} if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then @@ -122,7 +94,7 @@ index 60298422f..bdfdd207b 100644 fi for VCVARSFILE in $VCVARSFILES; do -@@ -26002,10 +26012,10 @@ $as_echo "$as_me: Warning: None of $VCVARSFILES were found, Visual Studio instal +@@ -26245,10 +26243,10 @@ $as_echo "$as_me: Warning: None of $VCVARSFILES were found, Visual Studio instal { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS_BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS_BASE using $METHOD" >&6;} if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then @@ -135,7 +107,7 @@ index 60298422f..bdfdd207b 100644 fi for VCVARSFILE in $VCVARSFILES; do -@@ -26059,10 +26069,10 @@ $as_echo "$as_me: Warning: None of $VCVARSFILES were found, Visual Studio instal +@@ -26302,10 +26300,10 @@ $as_echo "$as_me: Warning: None of $VCVARSFILES were found, Visual Studio instal { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS_BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS_BASE using $METHOD" >&6;} if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then @@ -149,38 +121,10 @@ index 60298422f..bdfdd207b 100644 for VCVARSFILE in $VCVARSFILES; do diff --git a/common/autoconf/toolchain_windows.m4 b/common/autoconf/toolchain_windows.m4 -index a78f9ac66..0b5efdad2 100644 +index 9e617c33..f024da1e 100644 --- a/common/autoconf/toolchain_windows.m4 +++ b/common/autoconf/toolchain_windows.m4 -@@ -25,7 +25,7 @@ - - ################################################################################ - # The order of these defines the priority by which we try to find them. --VALID_VS_VERSIONS="2010 2012 2013 2015 2017" -+VALID_VS_VERSIONS="2010 2012 2013 2015 2017 2019" - - VS_DESCRIPTION_2010="Microsoft Visual Studio 2010" - VS_VERSION_INTERNAL_2010=100 -@@ -83,6 +83,18 @@ VS_SDK_INSTALLDIR_2017= - VS_VS_PLATFORM_NAME_2017="v141" - VS_SDK_PLATFORM_NAME_2017= - -+VS_DESCRIPTION_2019="Microsoft Visual Studio 2019 - CURRENTLY NOT WORKING" -+VS_VERSION_INTERNAL_2019=141 -+VS_MSVCR_2019=vcruntime140.dll -+VS_MSVCP_2019=msvcp140.dll -+VS_ENVVAR_2019="VS150COMNTOOLS" -+VS_USE_UCRT_2019="true" -+VS_VS_INSTALLDIR_2019="Microsoft Visual Studio/2019" -+VS_EDITIONS_2019="Community Professional Enterprise" -+VS_SDK_INSTALLDIR_2019= -+VS_VS_PLATFORM_NAME_2019="v141" -+VS_SDK_PLATFORM_NAME_2019= -+ - ################################################################################ - - AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT], -@@ -107,10 +119,10 @@ AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT], +@@ -121,10 +121,10 @@ AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT], if test -d "$VS_BASE"; then AC_MSG_NOTICE([Found Visual Studio installation at $VS_BASE using $METHOD]) if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then @@ -193,7 +137,7 @@ index a78f9ac66..0b5efdad2 100644 fi for VCVARSFILE in $VCVARSFILES; do -@@ -198,8 +210,6 @@ AC_DEFUN([TOOLCHAIN_FIND_VISUAL_STUDIO_BAT_FILE], +@@ -212,8 +212,6 @@ AC_DEFUN([TOOLCHAIN_FIND_VISUAL_STUDIO_BAT_FILE], fi fi diff --git a/fix-windows-compile-fail.patch b/fix-windows-compile-fail.patch index 196913dee9811bcbe2476244f2780047a6f7afc1..fcc90b7f7151a44431393a9839d168e16d1137e6 100644 --- a/fix-windows-compile-fail.patch +++ b/fix-windows-compile-fail.patch @@ -38,7 +38,7 @@ index 9cfa0451..170f1fd9 100644 if (match_option(option, "-XX:+UseAppCDS", &tail)) { +#ifndef __linux__ + tty->print_cr("failed: must not use AppCDS on non-linux system."); -+ JVM_Exit(0); ++ JVM_Halt(0); +#endif if (!process_argument("+UseAppCDS", args->ignoreUnrecognized, origin)) { return JNI_EINVAL; diff --git a/fix_X509TrustManagerImpl_symantec_distrust.patch b/fix_X509TrustManagerImpl_symantec_distrust.patch new file mode 100644 index 0000000000000000000000000000000000000000..5ff273d601590b1792daf6e352851a4fb7718929 --- /dev/null +++ b/fix_X509TrustManagerImpl_symantec_distrust.patch @@ -0,0 +1,77 @@ +diff --git a/jdk/make/data/cacerts/geotrustglobalca b/jdk/make/data/cacerts/geotrustglobalca +new file mode 100644 +index 000000000..7f8bf9a66 +--- /dev/null ++++ b/jdk/make/data/cacerts/geotrustglobalca +@@ -0,0 +1,27 @@ ++Owner: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US ++Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US ++Serial number: 23456 ++Valid from: Tue May 21 04:00:00 GMT 2002 until: Sat May 21 04:00:00 GMT 2022 ++Signature algorithm name: SHA1withRSA ++Subject Public Key Algorithm: 2048-bit RSA key ++Version: 3 ++-----BEGIN CERTIFICATE----- ++MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT ++MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i ++YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG ++EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg ++R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 ++9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq ++fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv ++iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU ++1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ ++bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW ++MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA ++ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l ++uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn ++Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS ++tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF ++PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un ++hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV ++5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== ++-----END CERTIFICATE----- +diff --git a/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java b/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java +index 54e1bfa0d..c1423dc5b 100644 +--- a/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java ++++ b/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java +@@ -53,12 +53,12 @@ public class VerifyCACerts { + + File.separator + "security" + File.separator + "cacerts"; + + // The numbers of certs now. +- private static final int COUNT = 83; ++ private static final int COUNT = 84; + + // 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 +- = "2D:04:88:6C:52:53:54:EB:38:2D:BC:E0:AF:B7:82:F4:9E:32:A8:1A:1B:A3:AE:CF:25:CB:C2:F6:0F:4E:E1:20"; ++ = "D3:05:21:64:FA:D7:CD:29:E8:CB:57:E7:47:ED:79:9B:47:D8:0E:75:2D:CA:83:BB:86:AF:D9:43:FD:3E:17:85"; + + // map of cert alias to SHA-256 fingerprint + @SuppressWarnings("serial") +@@ -111,7 +111,9 @@ public class VerifyCACerts { + "7E:37:CB:8B:4C:47:09:0C:AB:36:55:1B:A6:F4:5D:B8:40:68:0F:BA:16:6A:95:2D:B1:00:71:7F:43:05:3F:C2"); + put("digicerthighassuranceevrootca [jdk]", + "74:31:E5:F4:C3:C1:CE:46:90:77:4F:0B:61:E0:54:40:88:3B:A9:A0:1E:D0:0B:A6:AB:D7:80:6E:D3:B1:18:CF"); +- put("geotrustprimaryca [jdk]", ++ put("geotrustglobalca [jdk]", ++ "FF:85:6A:2D:25:1D:CD:88:D3:66:56:F4:50:12:67:98:CF:AB:AA:DE:40:79:9C:72:2D:E4:D2:B5:DB:36:A7:3A"); ++ put("geotrustprimaryca [jdk]", + "37:D5:10:06:C5:12:EA:AB:62:64:21:F1:EC:8C:92:01:3F:C5:F8:2A:E9:8E:E5:33:EB:46:19:B8:DE:B4:D0:6C"); + put("geotrustprimarycag2 [jdk]", + "5E:DB:7A:C4:3B:82:A0:6A:87:61:E8:D7:BE:49:79:EB:F2:61:1F:7D:D7:9B:F9:1C:1C:6B:56:6A:21:9E:D7:66"); +@@ -237,7 +239,12 @@ public class VerifyCACerts { + // Exception list to 90 days expiry policy + // No error will be reported if certificate in this list expires + @SuppressWarnings("serial") +- private static final HashSet EXPIRY_EXC_ENTRIES = new HashSet(); ++ private static final HashSet EXPIRY_EXC_ENTRIES = new HashSet() { ++ { ++ // Valid until: Sat May 21 04:00:00 GMT 2022 ++ add("geotrustglobalca [jdk]"); ++ } ++ }; + + // Ninety days in milliseconds + private static final long NINETY_DAYS = 7776000000L; diff --git a/fix_wrap_memcpy_undefined_gcc10_3.patch b/fix_wrap_memcpy_undefined_gcc10_3.patch new file mode 100644 index 0000000000000000000000000000000000000000..9da21e6117853b5d3a5a8c59bc30eafeb337e9aa --- /dev/null +++ b/fix_wrap_memcpy_undefined_gcc10_3.patch @@ -0,0 +1,291 @@ +diff --git a/jdk/make/CompileDemos.gmk b/jdk/make/CompileDemos.gmk +index 763c968e..6c5eb432 100644 +--- a/jdk/make/CompileDemos.gmk ++++ b/jdk/make/CompileDemos.gmk +@@ -250,7 +250,6 @@ define SetupJVMTIDemo + SRC := $(JDK_TOPDIR)/src/share/demo/jvmti/$1 $$(BUILD_DEMO_JVMTI_$1_EXTRA_SRC), \ + LANG := $$(BUILD_DEMO_JVMTI_$1_LANG), \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CXXFLAGS := $$($1_CXXFLAGS), \ + LDFLAGS := $(filter-out -incremental:no -opt:ref, $$(LDFLAGS_JDKLIB)), \ + LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN), \ +diff --git a/jdk/make/CompileLaunchers.gmk b/jdk/make/CompileLaunchers.gmk +index 29211f83..2ac718fc 100644 +--- a/jdk/make/CompileLaunchers.gmk ++++ b/jdk/make/CompileLaunchers.gmk +@@ -512,7 +512,6 @@ $(eval $(call SetupNativeCompilation,BUILD_UNPACKEXE, \ + EXCLUDE_FILES := jni.cpp, \ + LANG := $(UNPACKEXE_LANG), \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(UNPACKEXE_CFLAGS) $(CXXFLAGS_JDKEXE) \ + -DFULL, \ + CFLAGS_release := -DPRODUCT, \ +diff --git a/jdk/make/lib/Awt2dLibraries.gmk b/jdk/make/lib/Awt2dLibraries.gmk +index 71d87c37..9368a9d5 100644 +--- a/jdk/make/lib/Awt2dLibraries.gmk ++++ b/jdk/make/lib/Awt2dLibraries.gmk +@@ -52,7 +52,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBMLIB_IMAGE, \ + EXCLUDE_FILES := awt_ImagingLib.c mlib_c_ImageBlendTable.c, \ + LANG := C, \ + OPTIMIZATION := HIGHEST, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + $(BUILD_LIBMLIB_CFLAGS), \ + MAPFILE := $(BUILD_LIBMLIB_IMAGE_MAPFILE), \ +@@ -471,7 +470,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBAWT, \ + INCLUDE_FILES := $(LIBAWT_FILES), \ + LANG := $(LIBAWT_LANG), \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS), \ + ASFLAGS := $(LIBAWT_ASFLAGS), \ + MAPFILE := $(LIBAWT_MAPFILE), \ +@@ -633,7 +631,6 @@ ifeq ($(findstring $(OPENJDK_TARGET_OS),windows macosx),) + INCLUDE_FILES := $(LIBAWT_XAWT_FILES), \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_XAWT_CFLAGS) \ + $(X_CFLAGS), \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libawt_xawt/mapfile-vers, \ +@@ -675,7 +672,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBLCMS, \ + SRC := $(JDK_TOPDIR)/src/share/native/sun/java2d/cmm/lcms, \ + LANG := C, \ + OPTIMIZATION := HIGHEST, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(filter-out -xc99=%none, $(CFLAGS_JDKLIB)) \ + -DCMS_DONT_USE_FAST_FLOOR \ + $(SHARED_LIBRARY_FLAGS) \ +@@ -743,7 +739,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJPEG, \ + $(JDK_TOPDIR)/src/share/native/sun/awt/image/jpeg, \ + LANG := C, \ + OPTIMIZATION := HIGHEST, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + $(BUILD_LIBJPEG_CLOSED_INCLUDES) \ + -I$(JDK_TOPDIR)/src/share/native/sun/awt/image/jpeg, \ +@@ -919,7 +914,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBFONTMANAGER, \ + EXCLUDE_FILES := $(LIBFONTMANAGER_EXCLUDE_FILES) \ + AccelGlyphCache.c, \ + LANG := C++, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) $(BUILD_LIBFONTMANAGER_CFLAGS_COMMON), \ + CXXFLAGS := $(CXXFLAGS_JDKLIB) $(BUILD_LIBFONTMANAGER_CFLAGS_COMMON), \ + OPTIMIZATION := $(LIBFONTMANAGER_OPTIMIZATION), \ +@@ -1211,7 +1205,6 @@ ifndef BUILD_HEADLESS_ONLY + EXCLUDE_FILES := imageioJPEG.c jpegdecoder.c pngtest.c, \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(LIBSPLASHSCREEN_CFLAGS) $(CFLAGS_JDKLIB) $(GIFLIB_CFLAGS), \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libsplashscreen/mapfile-vers, \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ +diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk +index b444abf9..e43fc2ed 100644 +--- a/jdk/make/lib/CoreLibraries.gmk ++++ b/jdk/make/lib/CoreLibraries.gmk +@@ -113,7 +113,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBVERIFY, \ + INCLUDE_FILES := $(BUILD_LIBVERIFY_SRC), \ + LANG := C, \ + OPTIMIZATION := $(LIBVERIFY_OPTIMIZATION), \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB), \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libverify/mapfile-vers, \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ +@@ -225,7 +224,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJAVA, \ + EXCLUDE_FILES := $(LIBJAVA_EXCLUDE_FILES), \ + LANG := C, \ + OPTIMIZATION := HIGH, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + $(LIBJAVA_CFLAGS), \ + MAPFILE := $(LIBJAVA_MAPFILE), \ +@@ -287,7 +285,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBZIP, \ + OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + SRC := $(JDK_TOPDIR)/src/share/native/java/util/zip, \ + EXCLUDES := $(LIBZIP_EXCLUDES), \ + CFLAGS := $(CFLAGS_JDKLIB) \ +@@ -329,7 +326,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBUNPACK, \ + EXCLUDE_FILES := main.cpp, \ + LANG := C++, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CXXFLAGS_JDKLIB) \ + -DNO_ZLIB -DUNPACK_JNI -DFULL, \ + CFLAGS_release := -DPRODUCT, \ +@@ -442,7 +438,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJLI, \ + INCLUDE_FILES := $(BUILD_LIBJLI_FILES), \ + LANG := C, \ + OPTIMIZATION := HIGH, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(LIBJLI_CFLAGS), \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjli/mapfile-vers, \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ +@@ -544,7 +539,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBNPT, \ + SRC := $(JDK_TOPDIR)/src/share/npt $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/npt, \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + -I$(JDK_TOPDIR)/src/share/npt \ + -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/npt, \ +diff --git a/jdk/make/lib/NetworkingLibraries.gmk b/jdk/make/lib/NetworkingLibraries.gmk +index f826c66d..347c3237 100644 +--- a/jdk/make/lib/NetworkingLibraries.gmk ++++ b/jdk/make/lib/NetworkingLibraries.gmk +@@ -65,7 +65,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBNET, \ + EXCLUDE_FILES := $(LIBNET_EXCLUDE_FILES), \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + $(LIBNET_CFLAGS), \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libnet/mapfile-vers, \ +diff --git a/jdk/make/lib/NioLibraries.gmk b/jdk/make/lib/NioLibraries.gmk +index 54c9c29e..6c9c46a3 100644 +--- a/jdk/make/lib/NioLibraries.gmk ++++ b/jdk/make/lib/NioLibraries.gmk +@@ -181,7 +181,6 @@ ifeq ($(OPENJDK_TARGET_OS_API), posix) + SRC := $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/nio/ch/sctp, \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + -I$(JDK_TOPDIR)/src/share/native/sun/nio/ch \ + -I$(JDK_TOPDIR)/src/share/native/sun/nio/ch/sctp \ +diff --git a/jdk/make/lib/SecurityLibraries.gmk b/jdk/make/lib/SecurityLibraries.gmk +index 10ab8043..5b9ec17f 100644 +--- a/jdk/make/lib/SecurityLibraries.gmk ++++ b/jdk/make/lib/SecurityLibraries.gmk +@@ -196,7 +196,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJ2PKCS11, \ + $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/security/pkcs11/wrapper, \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + -I$(JDK_TOPDIR)/src/share/native/sun/security/pkcs11 \ + -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/security/pkcs11 \ +@@ -242,7 +241,6 @@ ifeq ($(ENABLE_INTREE_EC), yes) + $(JDK_TOPDIR)/src/share/native/sun/security/ec/impl, \ + LANG := C++, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(filter-out $(ECC_JNI_SOLSPARC_FILTER), $(CFLAGS_JDKLIB)) \ + $(BUILD_LIBSUNEC_FLAGS) \ + -DMP_API_COMPATIBLE -DNSS_ECC_MORE_THAN_SUITE_B, \ +@@ -300,7 +298,6 @@ ifeq ($(ENABLE_KAE), true) + SRC := $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/org/openeuler/security/openssl, \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/org/openeuler/security/openssl, \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libj2kae/mapfile-vers, \ +diff --git a/jdk/make/lib/ServiceabilityLibraries.gmk b/jdk/make/lib/ServiceabilityLibraries.gmk +index 2c80ffc0..19c8601d 100644 +--- a/jdk/make/lib/ServiceabilityLibraries.gmk ++++ b/jdk/make/lib/ServiceabilityLibraries.gmk +@@ -83,7 +83,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBDT_SOCKET, \ + $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/transport/socket, \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) -DUSE_MMAP \ + -I$(INCLUDEDIR) -I$(JDK_OUTPUTDIR)/include/$(OPENJDK_TARGET_OS) \ + -I$(JDK_TOPDIR)/src/share/transport/socket \ +@@ -149,7 +148,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJDWP, \ + SRC := $(JDK_TOPDIR)/src/share/back $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/back, \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) -DJDWP_LOGGING \ + -I$(JDK_TOPDIR)/src/share/transport/export \ + -I$(JDK_TOPDIR)/src/share/back/export \ +@@ -255,7 +253,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBINSTRUMENT, \ + INCLUDE_FILES := $(LIBINSTRUMENT_FILES), \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(LIBINSTRUMENT_CFLAGS) $(CFLAGS_WARNINGS_ARE_ERRORS), \ + CFLAGS_debug := -DJPLIS_LOGGING, \ + CFLAGS_release := -DNO_JPLIS_LOGGING, \ +@@ -379,7 +376,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBHPROF, \ + SRC := $(BUILD_LIBHPROF_SRC), \ + LANG := C, \ + OPTIMIZATION := $(LIBHPROF_OPTIMIZATION), \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) \ + $(BUILD_LIBHPROF_CFLAGS), \ + CFLAGS_debug := -DHPROF_LOGGING, \ +@@ -408,7 +404,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJAVA_CRW_DEMO, \ + SRC := $(JDK_TOPDIR)/src/share/demo/jvmti/java_crw_demo, \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) \ + -I$(JDK_TOPDIR)/src/share/demo/jvmti/java_crw_demo, \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjava_crw_demo/mapfile-vers, \ +diff --git a/jdk/make/lib/SoundLibraries.gmk b/jdk/make/lib/SoundLibraries.gmk +index 0ea9ba84..b59a9462 100644 +--- a/jdk/make/lib/SoundLibraries.gmk ++++ b/jdk/make/lib/SoundLibraries.gmk +@@ -201,7 +201,6 @@ ifneq ($(filter jsoundalsa, $(EXTRA_SOUND_JNI_LIBS)), ) + PLATFORM_API_LinuxOS_ALSA_Ports.c, \ + LANG := C, \ + OPTIMIZATION := LOW, \ +- EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) $(ALSA_CFLAGS) \ + $(LIBJSOUND_CFLAGS) \ + -DUSE_DAUDIO=TRUE \ +diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk +index 2d9bdbee..9586d20e 100644 +--- a/make/common/NativeCompilation.gmk ++++ b/make/common/NativeCompilation.gmk +@@ -271,6 +271,7 @@ define SetupNativeCompilation + + # Find all files in the source trees. Sort to remove duplicates. + $1_ALL_SRCS := $$(sort $$(call CacheFind,$$($1_SRC))) ++ + # Extract the C/C++ files. + $1_EXCLUDE_FILES:=$$(foreach i,$$($1_SRC),$$(addprefix $$i/,$$($1_EXCLUDE_FILES))) + $1_INCLUDE_FILES:=$$(foreach i,$$($1_SRC),$$(addprefix $$i/,$$($1_INCLUDE_FILES))) +@@ -281,13 +282,20 @@ define SetupNativeCompilation + ifneq (,$$(strip $$($1_INCLUDE_FILES))) + $1_SRCS := $$(filter $$($1_INCLUDE_FILES),$$($1_SRCS)) + endif ++ ++ # Pickup extra OPENJDK_TARGET_OS_API and/or OPENJDK_TARGET_OS dependent variables ++ # for LDFLAGS and LDFLAGS_SUFFIX ++ $1_EXTRA_LDFLAGS:=$$($1_LDFLAGS_$(OPENJDK_TARGET_OS_API)) $$($1_LDFLAGS_$(OPENJDK_TARGET_OS)) ++ $1_EXTRA_LDFLAGS_SUFFIX:=$$($1_LDFLAGS_SUFFIX_$(OPENJDK_TARGET_OS_API)) $$($1_LDFLAGS_SUFFIX_$(OPENJDK_TARGET_OS)) ++ + ifeq ($(OPENJDK_TARGET_OS), linux) # only on linux +- ifneq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) # not need on the arm arch +- ifneq (,$$(strip $$($1_EXTRA_FILES))) +- $1_SRCS += $$($1_EXTRA_FILES) ++ ifneq ($$(findstring wrap=memcpy, $$($1_LDFLAGS)$$($1_EXTRA_LDFLAGS))$$($1_EXTRA_LDFLAGS_SUFFIX),) ++ ifeq ($$(findstring memcpy.cpp, $$($1_SRCS)),) ++ $1_SRCS += $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp + endif + endif + endif ++ + ifeq (,$$($1_SRCS)) + $$(error No sources found for $1 when looking inside the dirs $$($1_SRC)) + endif +@@ -432,10 +440,6 @@ define SetupNativeCompilation + endif + endif + +- # Pickup extra OPENJDK_TARGET_OS_API and/or OPENJDK_TARGET_OS dependent variables +- # for LDFLAGS and LDFLAGS_SUFFIX +- $1_EXTRA_LDFLAGS:=$$($1_LDFLAGS_$(OPENJDK_TARGET_OS_API)) $$($1_LDFLAGS_$(OPENJDK_TARGET_OS)) +- $1_EXTRA_LDFLAGS_SUFFIX:=$$($1_LDFLAGS_SUFFIX_$(OPENJDK_TARGET_OS_API)) $$($1_LDFLAGS_SUFFIX_$(OPENJDK_TARGET_OS)) + ifneq (,$$($1_REAL_MAPFILE)) + $1_EXTRA_LDFLAGS += $(call SET_SHARED_LIBRARY_MAPFILE,$$($1_REAL_MAPFILE)) + endif diff --git a/implementation_of_Blas_hotspot_function_in_Intrinsics.patch b/implementation_of_Blas_hotspot_function_in_Intrinsics.patch index e731e53bcf5c923cd8c9e7a42c9a1c904bca3dd4..50f26b4fb6e3b488a7d2f8f07451517614c048cd 100755 --- a/implementation_of_Blas_hotspot_function_in_Intrinsics.patch +++ b/implementation_of_Blas_hotspot_function_in_Intrinsics.patch @@ -289,8 +289,8 @@ index c5ec637a1..125983179 100644 + // Search path: /jre/lib///libopenblas.so + if (jvm_offset >= 0) { + if (jvm_offset + strlen(library_name) + strlen(os::dll_file_extension()) < JVM_MAXPATHLEN) { -+ strncpy(&path[jvm_offset], library_name, strlen(library_name)); -+ strncat(&path[jvm_offset], os::dll_file_extension(), strlen(os::dll_file_extension())); ++ strncpy(&path[jvm_offset], library_name, JVM_MAXPATHLEN - jvm_offset); ++ strncat(path, os::dll_file_extension(), strlen(os::dll_file_extension())); + library = (address)os::dll_load(path, err_buf, sizeof(err_buf)); + } + } diff --git a/jdk8u-jdk8u322-b06.tar.xz b/jdk8u-jdk8u352-b08.tar.xz similarity index 82% rename from jdk8u-jdk8u322-b06.tar.xz rename to jdk8u-jdk8u352-b08.tar.xz index 03b30c0cf15b36aef487601269528822ff5cba98..19d13e4a3511e06ec5acd8548c55b253065cffb0 100644 Binary files a/jdk8u-jdk8u322-b06.tar.xz and b/jdk8u-jdk8u352-b08.tar.xz differ diff --git a/kae-usability-enhancement.patch b/kae-usability-enhancement.patch new file mode 100644 index 0000000000000000000000000000000000000000..ec1207a0fd7758557930ae10228489caeccb3f89 --- /dev/null +++ b/kae-usability-enhancement.patch @@ -0,0 +1,3640 @@ +From 8545f560d406db592303b09fc576c13ba9a8caa0 Mon Sep 17 00:00:00 2001 +From: kuenking111 +Date: Sat, 3 Sep 2022 14:18:42 +0000 +Subject: [PATCH 2/6] kae-usability-enhancement + +--- + jdk/make/CopyFiles.gmk | 2 +- + jdk/make/mapfiles/libj2kae/mapfile-vers | 1 + + jdk/src/share/lib/security/kaeprovider.conf | 65 ++- + .../openeuler/security/openssl/KAEConfig.java | 386 ++++++++++++++++++ + .../openeuler/security/openssl/KAELog.java | 183 +++++++++ + .../security/openssl/KAEProvider.java | 151 ++++--- + .../security/openssl/KAESM4Cipher.java | 181 ++++++++ + .../security/openssl/kae_cipher_rsa.c | 13 +- + .../openeuler/security/openssl/kae_digest.c | 9 +- + .../org/openeuler/security/openssl/kae_hmac.c | 9 +- + .../security/openssl/kae_keyagreement_dh.c | 4 +- + .../openssl/kae_keypairgenerator_dh.c | 4 +- + .../openssl/kae_keypairgenerator_rsa.c | 6 +- + .../openeuler/security/openssl/kae_provider.c | 54 ++- + .../security/openssl/kae_signature_rsa.c | 21 +- + .../security/openssl/kae_symmetric_cipher.c | 9 +- + .../org/openeuler/security/openssl/kae_util.c | 138 ++++++- + .../org/openeuler/security/openssl/kae_util.h | 51 ++- + .../openeuler/security/openssl/AESTest.java | 114 ++++++ + .../openeuler/security/openssl/DHTest.java | 9 +- + .../security/openssl/DigestTest.java | 60 +++ + .../openeuler/security/openssl/ECDHTest.java | 1 + + .../openeuler/security/openssl/HmacTest.java | 88 ++++ + .../security/openssl/KAEConfTest.java | 121 ++++++ + .../openssl/KAEDisabledAlgorithmsTest.java | 164 ++++++++ + .../security/openssl/KAEEngineIdTest.java | 76 ++++ + .../security/openssl/KAELogTest.java | 126 ++++++ + .../security/openssl/KAETestHelper.java | 209 ++++++++++ + .../security/openssl/KAEUseEngineTest.java | 262 ++++++++++++ + .../security/openssl/KaeDebugLogTest.java | 88 ++++ + .../security/openssl/KaeProviderTest.java | 170 ++++++++ + .../openeuler/security/openssl/RSATest.java | 137 +++++++ + .../openeuler/security/openssl/SM3Test.java | 54 --- + .../openeuler/security/openssl/SM4Test.java | 62 ++- + 34 files changed, 2844 insertions(+), 184 deletions(-) + create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEConfig.java + create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAELog.java + create mode 100644 jdk/test/org/openeuler/security/openssl/AESTest.java + create mode 100644 jdk/test/org/openeuler/security/openssl/DigestTest.java + create mode 100644 jdk/test/org/openeuler/security/openssl/HmacTest.java + create mode 100644 jdk/test/org/openeuler/security/openssl/KAEConfTest.java + create mode 100644 jdk/test/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java + create mode 100644 jdk/test/org/openeuler/security/openssl/KAEEngineIdTest.java + create mode 100644 jdk/test/org/openeuler/security/openssl/KAELogTest.java + create mode 100644 jdk/test/org/openeuler/security/openssl/KAETestHelper.java + create mode 100644 jdk/test/org/openeuler/security/openssl/KAEUseEngineTest.java + create mode 100644 jdk/test/org/openeuler/security/openssl/KaeDebugLogTest.java + create mode 100644 jdk/test/org/openeuler/security/openssl/KaeProviderTest.java + create mode 100644 jdk/test/org/openeuler/security/openssl/RSATest.java + delete mode 100644 jdk/test/org/openeuler/security/openssl/SM3Test.java + +diff --git a/jdk/make/CopyFiles.gmk b/jdk/make/CopyFiles.gmk +index 2a6fc0932..806d7bec1 100644 +--- a/jdk/make/CopyFiles.gmk ++++ b/jdk/make/CopyFiles.gmk +@@ -634,7 +634,7 @@ endif + ifeq ($(ENABLE_KAE), true) + ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) + +- KAE_CONF_PATH= $(JDK_OUTPUTDIR)/lib/ext ++ KAE_CONF_PATH= $(JDK_OUTPUTDIR)/lib + $(KAE_CONF_PATH)/kaeprovider.conf: $(JDK_TOPDIR)/src/share/lib/security/kaeprovider.conf + $(call install-file) + +diff --git a/jdk/make/mapfiles/libj2kae/mapfile-vers b/jdk/make/mapfiles/libj2kae/mapfile-vers +index 128d1e322..a1bdb830b 100644 +--- a/jdk/make/mapfiles/libj2kae/mapfile-vers ++++ b/jdk/make/mapfiles/libj2kae/mapfile-vers +@@ -27,6 +27,7 @@ SUNWprivate_1.1 { + global: + JNI_OnLoad; + Java_org_openeuler_security_openssl_KAEProvider_initOpenssl; ++ Java_org_openeuler_security_openssl_KAEProvider_getEngineFlags; + Java_org_openeuler_security_openssl_KAEDigest_nativeInit; + Java_org_openeuler_security_openssl_KAEDigest_nativeUpdate; + Java_org_openeuler_security_openssl_KAEDigest_nativeDigest; +diff --git a/jdk/src/share/lib/security/kaeprovider.conf b/jdk/src/share/lib/security/kaeprovider.conf +index a48969669..cc50611d1 100644 +--- a/jdk/src/share/lib/security/kaeprovider.conf ++++ b/jdk/src/share/lib/security/kaeprovider.conf +@@ -1,9 +1,13 @@ + # +-# This is the config file for KAEProvider ++# This is the config file for KAEProvider. ++# These configuration properties support the use of jdk system properties, ++# and jdk system properties take precedence over file configuration properties. ++# For detailed usage, please refer to the user manual: ++# https://gitee.com/openeuler/bishengjdk-8/wikis/%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3/KAE%20Provider%E7%94%A8%E6%88%B7%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C + # +-# Algorithms are enabled by default if KAEProvider is used. +-# Delete # if you want to disable certain algorithm. + ++# Algorithms are enabled by default if KAEProvider is used. ++# Delete # if you want to disable certain algorithm. + # kae.md5=false + # kae.sha256=false + # kae.sha384=false +@@ -15,5 +19,58 @@ + # kae.dh=false + # kae.ec=false + +-# enable KAEProvider log setting ++# Configure engine id, the default value is kae. ++# kae.engine.id=kae ++ ++# Configure whether libcrypto.so uses GLOBAL mode, uses LOCAL mode by default. ++# If you use uadk_engine, you need to enable this option. ++# kae.libcrypto.useGlobalMode=false ++ ++# The following configuration will only take effect when using KAEProvider. ++# Configure whether to enable KAE hardware acceleration for each category of algorithm. ++# The configurable value are as follows: ++# true : enable KAE hardware acceleration by default ++# false: use openssl soft calculation by default ++# The digest/sm4/rsa/dh category algorithm enable KAE hardware acceleration by default. ++# The aes/hmac/ec category algorithm use openssl soft calculation by default. ++# The ec category algorithm configuration does not take effect temporarily. and it ++# currently does not support KAE hardware acceleration, temporarily use openssl soft calculation. ++# kae.digest.useKaeEngine=true ++# kae.aes.useKaeEngine=false ++# kae.sm4.useKaeEngine=true ++# kae.hmac.useKaeEngine=false ++# kae.rsa.useKaeEngine=true ++# kae.dh.useKaeEngine=true ++# kae.ec.useKaeEngine=false ++# ++# Some engines do not fully support certain categories of algorithms, for example, the digest ++# algorithm implemented by kae engine only supports md5 and sm3.For more information, please refer to: ++# KAE : https://github.com/kunpengcompute/KAE#:~:text=Digest%20algorithm%3A%20SM3/MD5 ++# UADK: https://gitee.com/openeuler/uadk/wikis/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3/UADK%20quick%20start#11-uadk ++# ++# Users can disable unsupported algorithms through the following property configuration. ++# Disable algorithm to enable KAE hardware acceleration, use openssl soft algorithm instead. ++# The sha256, sha384 algorithms are disabled by default. ++# digest : md5,sha256,sha384,sm3 ++# aes : aes-128-ecb,aes-128-cbc,aes-128-ctr,aes-128-gcm, ++# aes-192-ecb,aes-192-cbc,aes-192-ctr,aes-192-gcm, ++# aes-256-ecb,aes-256-cbc,aes-256-ctr,aes-256-gcm ++# sm4 : sm4-ecb,sm4-cbc,sm4-ctr,sm4-ofb ++# hmac : hmac-md5,hmac-sha1,hmac-sha224,hmac-sha256,hmac-sha384,hmac-sha512 ++# rsa : rsa ++# dh : dh ++# ec : ec ++# kae.engine.disabledAlgorithms=sha256,sha384 ++ ++# SM4 max chunk size of each encryption or decryption. ++# when input data does not have an accessible byte[]. ++# The default value is 4096, when configuring a non-positive Integer type, use the default value of 4096. ++# kae.sm4.maxChunkSize=4096 ++ ++# Enable engine load log. + # kae.log=true ++# ++# It only takes effect when the property kae.log value is true. ++# Configure log file path, default value is System.getProperty("user.dir") + "/ + "kae.log". ++# kae.log.file=/home/user/kae.log ++ +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEConfig.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEConfig.java +new file mode 100644 +index 000000000..07294dbd6 +--- /dev/null ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEConfig.java +@@ -0,0 +1,386 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.util.Debug; ++ ++import java.io.BufferedInputStream; ++import java.io.File; ++import java.io.FileInputStream; ++import java.io.IOException; ++import java.io.InputStream; ++import java.security.AccessController; ++import java.security.PrivilegedAction; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.Map; ++import java.util.Properties; ++ ++public class KAEConfig { ++ private static final Debug kaeDebug = Debug.getInstance("kae"); ++ ++ // these property names indicates whether each algorithm uses KAEProvider ++ private static final String[] useKaeProviderPropertyNames = new String[]{ ++ "kae.md5", ++ "kae.sha256", ++ "kae.sha384", ++ "kae.sm3", ++ "kae.aes", ++ "kae.sm4", ++ "kae.hmac", ++ "kae.rsa", ++ "kae.dh", ++ "kae.ec" ++ }; ++ ++ // these property names indicate whether KAE hardware acceleration is enabled for each algorithm ++ private static final String[] useKaeEnginePropertyNames = new String[]{ ++ "kae.digest.useKaeEngine", ++ "kae.aes.useKaeEngine", ++ "kae.sm4.useKaeEngine", ++ "kae.hmac.useKaeEngine", ++ "kae.rsa.useKaeEngine", ++ "kae.dh.useKaeEngine", ++ "kae.ec.useKaeEngine" ++ }; ++ ++ // algorithm names ++ private static final String[] algorithmNames = new String[]{ ++ "md5", ++ "sha256", ++ "sha384", ++ "sm3", ++ "aes-128-ecb", ++ "aes-128-cbc", ++ "aes-128-ctr", ++ "aes-128-gcm", ++ "aes-192-ecb", ++ "aes-192-cbc", ++ "aes-192-ctr", ++ "aes-192-gcm", ++ "aes-256-ecb", ++ "aes-256-cbc", ++ "aes-256-ctr", ++ "aes-256-gcm", ++ "sm4-ecb", ++ "sm4-cbc", ++ "sm4-ctr", ++ "sm4-ofb", ++ "hmac-md5", ++ "hmac-sha1", ++ "hmac-sha224", ++ "hmac-sha256", ++ "hmac-sha384", ++ "hmac-sha512", ++ "rsa", ++ "dh", ++ "ec" ++ }; ++ ++ // algorithm name and algorithm index mapping ++ private static final Map algorithmNameIndexMap = new HashMap<>(); ++ ++ // algorithm name and algorithm category index mapping ++ private static final Map algorithmNameCategoryMap = new HashMap<>(); ++ ++ // whether use KAEProvider for each algorithm ++ private static final boolean[] useKaeProviderFlags = new boolean[algorithmNames.length]; ++ ++ // whether use KAEProvider for each category algorithm ++ private static final Map useKaeProviderCategoryMap = new HashMap<>(); ++ ++ // whether enable the Kunpeng acceleration engine for each algorithm ++ private static final boolean[] useKaeEngineFlags = new boolean[algorithmNames.length]; ++ ++ // The kaeprovider.cnf properties ++ private static Properties props; ++ ++ private KAEConfig() { ++ ++ } ++ ++ static { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ public Void run() { ++ initialize(); ++ return null; ++ } ++ }); ++ } ++ ++ private static File kaePropFile(String filename) { ++ String sep = File.separator; ++ String defaultKaeConf = System.getProperty("java.home") + sep + "lib" + sep + filename; ++ String kaeConf = System.getProperty("kae.conf", defaultKaeConf); ++ return new File(kaeConf); ++ } ++ ++ private static void initialize() { ++ initProperties(); ++ initAlgorithmNameMap(); ++ initUseKaeProviderFlags(); ++ initUseKaeEngineFlags(); ++ } ++ ++ private static void initProperties() { ++ props = new Properties(); ++ File propFile = kaePropFile("kaeprovider.conf"); ++ if (propFile.exists()) { ++ InputStream is = null; ++ try { ++ FileInputStream fis = new FileInputStream(propFile); ++ is = new BufferedInputStream(fis); ++ props.load(is); ++ ++ if (kaeDebug != null) { ++ kaeDebug.println("reading kae properties file: " + ++ propFile); ++ } ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("unable to load kae properties from " + ++ propFile); ++ e.printStackTrace(); ++ } ++ } finally { ++ if (is != null) { ++ try { ++ is.close(); ++ } catch (IOException ioe) { ++ if (kaeDebug != null) { ++ kaeDebug.println("unable to close input stream"); ++ } ++ } ++ } ++ } ++ } else { ++ if (kaeDebug != null) { ++ kaeDebug.println("not found kae properties file: " + ++ propFile); ++ } ++ } ++ } ++ ++ public static Boolean useKaeProvider(String key) { ++ return useKaeProviderCategoryMap.getOrDefault(key, Boolean.TRUE); ++ } ++ ++ private static void initUseKaeProviderFlags() { ++ boolean[] categoryFlagsForProvider = new boolean[useKaeProviderPropertyNames.length]; ++ Arrays.fill(categoryFlagsForProvider, true); ++ for (int i = 0; i < useKaeProviderPropertyNames.length; i++) { ++ String configValue = privilegedGetOverridable(useKaeProviderPropertyNames[i]); ++ if (configValue != null) { ++ categoryFlagsForProvider[i] = Boolean.parseBoolean(configValue); ++ } ++ useKaeProviderCategoryMap.put(useKaeProviderPropertyNames[i], categoryFlagsForProvider[i]); ++ } ++ int offset = useKaeProviderPropertyNames.length - useKaeEnginePropertyNames.length; ++ int digestAlgorithmLen = offset + 1; ++ // digest ++ System.arraycopy(categoryFlagsForProvider, 0, useKaeProviderFlags, 0, digestAlgorithmLen); ++ ++ // non-digest ++ for (int i = digestAlgorithmLen; i < useKaeProviderFlags.length; i++) { ++ Integer algorithmCategoryIndex = algorithmNameCategoryMap.get(algorithmNames[i]); ++ if (categoryFlagsForProvider[algorithmCategoryIndex + offset]) { ++ useKaeProviderFlags[i] = true; ++ } ++ } ++ ++ if (kaeDebug != null) { ++ kaeDebug.println("useKaeProviderPropertyNames: "); ++ for (int i = 0; i < categoryFlagsForProvider.length; i++) { ++ kaeDebug.println(useKaeProviderPropertyNames[i] + "=" + categoryFlagsForProvider[i]); ++ } ++ ++ kaeDebug.println("useKaeProviderFlags: "); ++ for (int i = 0; i < useKaeProviderFlags.length; i++) { ++ kaeDebug.println(algorithmNames[i] + "=" + useKaeProviderFlags[i]); ++ } ++ } ++ } ++ ++ public static boolean[] getUseKaeProviderFlags() { ++ return useKaeProviderFlags; ++ } ++ ++ private static void initUseKaeEngineFlags() { ++ boolean[] categoryFlagsForEngine = new boolean[]{ ++ true, // digest ++ false, // aes ++ true, // sm4 ++ false, // hmac ++ true, // rsa ++ true, // dh ++ false // ec ++ }; ++ for (int i = 0; i < useKaeEnginePropertyNames.length; i++) { ++ String configValue = privilegedGetOverridable(useKaeEnginePropertyNames[i]); ++ if (configValue != null) { ++ categoryFlagsForEngine[i] = Boolean.parseBoolean(configValue); ++ } ++ } ++ ++ // EC algorithm currently does not support KAE hardware acceleration, temporarily use openssl soft calculation. ++ categoryFlagsForEngine[useKaeEnginePropertyNames.length - 1] = false; ++ ++ for (int i = 0; i < useKaeEngineFlags.length; i++) { ++ Integer algorithmCategoryIndex = algorithmNameCategoryMap.get(algorithmNames[i]); ++ if (categoryFlagsForEngine[algorithmCategoryIndex]) { ++ useKaeEngineFlags[i] = true; ++ } ++ } ++ ++ String[] disabledAlgorithms = getDisabledAlgorithms(); ++ for (String disabledAlgorithm : disabledAlgorithms) { ++ Integer algorithmIndex = algorithmNameIndexMap.get(disabledAlgorithm); ++ if (algorithmIndex != null) { ++ useKaeEngineFlags[algorithmIndex] = false; ++ } ++ } ++ if (kaeDebug != null) { ++ kaeDebug.println("useKaeEnginePropertyNames: "); ++ for (int i = 0; i < categoryFlagsForEngine.length; i++) { ++ kaeDebug.println(useKaeEnginePropertyNames[i] + "=" + categoryFlagsForEngine[i]); ++ } ++ ++ kaeDebug.println("disabledAlgorithms: "); ++ for (int i = 0; i < disabledAlgorithms.length; i++) { ++ kaeDebug.println(disabledAlgorithms[i]); ++ } ++ ++ kaeDebug.println("useKaeEngineFlags: "); ++ for (int i = 0; i < useKaeEngineFlags.length; i++) { ++ kaeDebug.println(algorithmNames[i] + "=" + useKaeEngineFlags[i]); ++ } ++ } ++ } ++ ++ public static boolean[] getUseKaeEngineFlags() { ++ return useKaeEngineFlags; ++ } ++ ++ private static void initAlgorithmNameIndexMap() { ++ for (int i = 0; i < algorithmNames.length; i++) { ++ algorithmNameIndexMap.put(algorithmNames[i], i); ++ } ++ } ++ ++ /* ++ * 0 : digest ++ * 1 : aes ++ * 2 : sm4 ++ * 3 : hmac ++ * 4 : rsa ++ * 5 : dh ++ * 6 : ec ++ */ ++ private static void initAlgorithmNameCategoryMap() { ++ algorithmNameCategoryMap.put("md5", 0); ++ algorithmNameCategoryMap.put("sha256", 0); ++ algorithmNameCategoryMap.put("sha384", 0); ++ algorithmNameCategoryMap.put("sm3", 0); ++ algorithmNameCategoryMap.put("aes-128-ecb", 1); ++ algorithmNameCategoryMap.put("aes-128-cbc", 1); ++ algorithmNameCategoryMap.put("aes-128-ctr", 1); ++ algorithmNameCategoryMap.put("aes-128-gcm", 1); ++ algorithmNameCategoryMap.put("aes-192-ecb", 1); ++ algorithmNameCategoryMap.put("aes-192-cbc", 1); ++ algorithmNameCategoryMap.put("aes-192-ctr", 1); ++ algorithmNameCategoryMap.put("aes-192-gcm", 1); ++ algorithmNameCategoryMap.put("aes-256-ecb", 1); ++ algorithmNameCategoryMap.put("aes-256-cbc", 1); ++ algorithmNameCategoryMap.put("aes-256-ctr", 1); ++ algorithmNameCategoryMap.put("aes-256-gcm", 1); ++ algorithmNameCategoryMap.put("sm4-ecb", 2); ++ algorithmNameCategoryMap.put("sm4-cbc", 2); ++ algorithmNameCategoryMap.put("sm4-ctr", 2); ++ algorithmNameCategoryMap.put("sm4-ofb", 2); ++ algorithmNameCategoryMap.put("hmac-md5", 3); ++ algorithmNameCategoryMap.put("hmac-sha1", 3); ++ algorithmNameCategoryMap.put("hmac-sha224", 3); ++ algorithmNameCategoryMap.put("hmac-sha256", 3); ++ algorithmNameCategoryMap.put("hmac-sha384", 3); ++ algorithmNameCategoryMap.put("hmac-sha512", 3); ++ algorithmNameCategoryMap.put("rsa", 4); ++ algorithmNameCategoryMap.put("dh", 5); ++ algorithmNameCategoryMap.put("ec", 6); ++ } ++ ++ private static void initAlgorithmNameMap() { ++ initAlgorithmNameIndexMap(); ++ initAlgorithmNameCategoryMap(); ++ } ++ ++ private static String[] getDisabledAlgorithms() { ++ String disabledAlgorithms = privilegedGetOverridable("kae.engine.disabledAlgorithms", ++ "sha256,sha384"); ++ return disabledAlgorithms.replaceAll(" ", "").split("\\,"); ++ } ++ ++ public static String privilegedGetProperty(String key) { ++ if (System.getSecurityManager() == null) { ++ return getProperty(key); ++ } else { ++ return AccessController.doPrivileged((PrivilegedAction) () -> getOverridableProperty(key)); ++ } ++ } ++ ++ public static String privilegedGetOverridable(String key) { ++ if (System.getSecurityManager() == null) { ++ return getOverridableProperty(key); ++ } else { ++ return AccessController.doPrivileged((PrivilegedAction) () -> getOverridableProperty(key)); ++ } ++ } ++ ++ public static String privilegedGetOverridable(String key, String defaultValue) { ++ String val = privilegedGetOverridable(key); ++ return (val == null) ? defaultValue : val; ++ } ++ ++ private static String getProperty(String key) { ++ String val = props.getProperty(key); ++ if (val != null) ++ val = val.trim(); ++ return val; ++ } ++ ++ private static String getOverridableProperty(String key) { ++ String val = System.getProperty(key); ++ if (val == null) { ++ return getProperty(key); ++ } else { ++ return val; ++ } ++ } ++ ++ public static String getAlgorithmName(int index) { ++ if (index < 0 || index >= algorithmNames.length) { ++ throw new IndexOutOfBoundsException(); ++ } ++ return algorithmNames[index]; ++ } ++} +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAELog.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAELog.java +new file mode 100644 +index 000000000..434f773a1 +--- /dev/null ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAELog.java +@@ -0,0 +1,183 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.util.Debug; ++ ++import java.io.BufferedWriter; ++import java.io.File; ++import java.io.IOException; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.StandardOpenOption; ++import java.security.AccessController; ++import java.security.PrivilegedAction; ++import java.text.SimpleDateFormat; ++import java.util.Arrays; ++import java.util.Date; ++ ++public class KAELog { ++ private static final Debug kaeDebug = Debug.getInstance("kae"); ++ private static File logFile; ++ private static boolean exist; ++ ++ private KAELog() { ++ ++ } ++ ++ static { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ public Void run() { ++ initialize(); ++ return null; ++ } ++ }); ++ } ++ ++ private static void initialize() { ++ if (!enableKaeLog()) { ++ if (kaeDebug != null) { ++ kaeDebug.println("kae logging is not enabled"); ++ } ++ return; ++ } ++ ++ logFile = kaeLogFile("kae.log"); ++ File parentFile = logFile.getParentFile(); ++ if (!parentFile.exists()) { ++ try { ++ Files.createDirectories(parentFile.toPath()); ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("failed to create directory :" + parentFile); ++ e.printStackTrace(); ++ } ++ return; ++ } ++ } ++ ++ if (logFile.exists()) { ++ if (kaeDebug != null) { ++ kaeDebug.println("found kae log file :" + logFile); ++ } ++ exist = true; ++ } else { ++ if (kaeDebug != null) { ++ kaeDebug.println("not found kae log file :" + logFile); ++ } ++ try { ++ Path path = Files.createFile(logFile.toPath()); ++ if (path != null) { ++ exist = true; ++ } ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("unable to create new kae log file :" + logFile); ++ e.printStackTrace(); ++ } ++ } ++ ++ if (exist) { ++ if (kaeDebug != null) { ++ kaeDebug.println("create new kae log file :" + logFile); ++ } ++ } ++ } ++ } ++ ++ public static boolean enableKaeLog() { ++ String debug = KAEConfig.privilegedGetOverridable("kae.log"); ++ return Boolean.parseBoolean(debug); ++ } ++ ++ private static File kaeLogFile(String filename) { ++ String sep = File.separator; ++ String defaultKaeLog = System.getProperty("user.dir") + sep + filename; ++ String kaeLog = KAEConfig.privilegedGetOverridable("kae.log.file", defaultKaeLog); ++ return new File(kaeLog); ++ } ++ ++ private static String getLogTime() { ++ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ++ return simpleDateFormat.format(new Date()); ++ } ++ ++ public static void log(String engineId, Throwable throwable, boolean[] engineFlags, boolean[] kaeProviderFlags) { ++ if (engineFlags.length != kaeProviderFlags.length) { ++ if (kaeDebug != null) { ++ kaeDebug.println("The length of engineFlags is not equal to the length of kaeProviderFlags."); ++ kaeDebug.println(String.format("engineFlags : %s", Arrays.toString(engineFlags))); ++ kaeDebug.println(String.format("kaeProviderFlags : %s", Arrays.toString(kaeProviderFlags))); ++ } ++ return; ++ } ++ if (!exist) { ++ return; ++ } ++ ++ try (BufferedWriter writer = Files.newBufferedWriter(logFile.toPath(), ++ StandardOpenOption.APPEND)) { ++ logEngine(writer, engineId, throwable); ++ writer.newLine(); ++ logAlgorithmStrategy(writer, engineFlags, kaeProviderFlags); ++ writer.newLine(); ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("write kae log failed"); ++ e.printStackTrace(); ++ } ++ } ++ } ++ ++ // log engine ++ private static void logEngine(BufferedWriter writer, String engineId, Throwable throwable) throws IOException { ++ writer.write(String.format("[%s] ", getLogTime())); ++ if (throwable == null) { ++ writer.write(String.format("%s engine was found.", engineId)); ++ } else if (throwable instanceof RuntimeException) { ++ writer.write(String.format("%s engine was not found. %s", engineId, throwable.getMessage())); ++ } else { ++ writer.write(throwable.getMessage()); ++ } ++ } ++ ++ // log algorithm strategy ++ private static void logAlgorithmStrategy(BufferedWriter writer, boolean[] engineFlags, boolean[] kaeProviderFlags) ++ throws IOException { ++ writer.write(String.format("[%s] ", getLogTime())); ++ writer.write("The implementation strategy of each algorithm is as follows : "); ++ for (int i = 0; i < engineFlags.length; i++) { ++ writer.newLine(); ++ String algorithmName = KAEConfig.getAlgorithmName(i); ++ String message; ++ if (kaeProviderFlags[i]) { ++ String detail = engineFlags[i] ? "enable KAE hardware acceleration" : "Use openssl soft calculation"; ++ message = String.format(" %-11s => %s: %s", algorithmName, "KAEProvider", detail); ++ } else { ++ message = String.format(" %-11s => %s", algorithmName, "Non-KAEProvider"); ++ } ++ writer.write(message); ++ } ++ } ++} +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java +index 83ed8649c..3e7f54638 100644 +--- a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java +@@ -24,116 +24,103 @@ + + package org.openeuler.security.openssl; + +-import java.io.BufferedWriter; +-import java.io.BufferedInputStream; +-import java.io.File; +-import java.io.FileInputStream; +-import java.io.InputStream; +-import java.io.IOException; +-import java.nio.file.Files; +-import java.nio.file.Path; +-import java.nio.file.Paths; +-import java.nio.file.StandardOpenOption; +-import java.util.Date; +-import java.util.Properties; ++import sun.security.util.Debug; ++ ++import java.security.AccessController; ++import java.security.PrivilegedAction; + import java.security.Provider; + + /** + * KAE Provider + */ + public class KAEProvider extends Provider { +- private static Throwable excp; +- private static boolean needLog = true; ++ private static final Debug kaeDebug = Debug.getInstance("kae"); ++ ++ // default engine id ++ private static final String DEFAULT_ENGINE_ID = "kae"; + + static { +- Throwable status = null; +- try { +- System.loadLibrary("j2kae"); +- initOpenssl(); +- } catch (UnsatisfiedLinkError t) { +- status = t; +- } catch (RuntimeException e) { +- status = e; +- } +- excp = status; ++ initialize(); + } + +- private void logStart(Throwable excp) { +- File file = new File(System.getProperty("user.dir"), "kae.log"); +- Path fpath = file.toPath(); +- if (!Files.exists(fpath)) { +- try { +- file.createNewFile(); +- } catch (IOException e) { +- e.printStackTrace(); +- } +- } ++ private static void initialize() { ++ loadLibrary(); ++ initOpenssl(); ++ } + +- try (BufferedWriter writer = Files.newBufferedWriter(fpath, StandardOpenOption.APPEND)) { +- if (excp != null) { +- writer.write(excp.getMessage()); +- } else { +- writer.write("KAE Engine was found"); ++ // load kae.so ++ private static void loadLibrary() { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ @Override ++ public Object run() { ++ System.loadLibrary("j2kae"); ++ return null; + } +- writer.write(" " + new Date()); +- writer.newLine(); +- } catch (IOException e) { +- e.initCause(excp).printStackTrace(); +- } +- KAEProvider.excp = null; // Exception already logged, clean it. ++ }); + } + +- private Properties getProp() { +- Properties props = new Properties(); +- String sep = File.separator; +- File propFile = new File(System.getProperty("java.home") + sep + "lib" + sep + +- "ext" + sep + "kaeprovider.conf"); +- if (propFile.exists()) { +- try (InputStream is = new BufferedInputStream(new FileInputStream(propFile))) { +- props.load(is); +- } catch (IOException e) { +- e.printStackTrace(); ++ // init openssl ++ private static void initOpenssl() { ++ boolean useGlobalMode = useGlobalMode(); ++ String engineId = getEngineId(); ++ boolean[] algorithmKaeFlags = KAEConfig.getUseKaeEngineFlags(); ++ Throwable throwable = null; ++ try { ++ initOpenssl(useGlobalMode, engineId, algorithmKaeFlags); ++ } catch (Throwable t) { ++ throwable = t; ++ if (kaeDebug != null) { ++ kaeDebug.println("initOpenssl failed : " + throwable.getMessage()); + } + } +- return props; ++ boolean[] engineFlags = getEngineFlags(); ++ boolean[] kaeProviderFlags = KAEConfig.getUseKaeProviderFlags(); ++ KAELog.log(engineId, throwable, engineFlags, kaeProviderFlags); ++ } ++ ++ // get engine id ++ private static String getEngineId() { ++ return KAEConfig.privilegedGetOverridable("kae.engine.id", DEFAULT_ENGINE_ID); ++ } ++ ++ // whether to set libcrypto.so to GLOBAL mode, by default libcrypto.so is LOCAL mode ++ private static boolean useGlobalMode() { ++ String explicitLoad = KAEConfig.privilegedGetOverridable( ++ "kae.libcrypto.useGlobalMode", "false"); ++ return Boolean.parseBoolean(explicitLoad); + } + + public KAEProvider() { + super("KAEProvider", 1.8d, "KAE provider"); +- Properties props = getProp(); +- if (needLog && "true".equalsIgnoreCase(props.getProperty("kae.log"))) { +- logStart(excp); +- needLog = false; // Log only once +- } +- if (!"false".equalsIgnoreCase(props.getProperty("kae.md5"))) { ++ if (KAEConfig.useKaeProvider("kae.md5")) { + putMD5(); + } +- if (!"false".equalsIgnoreCase(props.getProperty("kae.sha256"))) { ++ if (KAEConfig.useKaeProvider("kae.sha256")) { + putSHA256(); + } +- if (!"false".equalsIgnoreCase(props.getProperty("kae.sha384"))) { ++ if (KAEConfig.useKaeProvider("kae.sha384")) { + putSHA384(); + } +- if (!"false".equalsIgnoreCase(props.getProperty("kae.sm3"))) { ++ if (KAEConfig.useKaeProvider("kae.sm3")) { + putSM3(); + } +- if (!"false".equalsIgnoreCase(props.getProperty("kae.aes"))) { ++ if (KAEConfig.useKaeProvider("kae.aes")) { + putAES(); + } +- if (!"false".equalsIgnoreCase(props.getProperty("kae.sm4"))) { ++ if (KAEConfig.useKaeProvider("kae.sm4")) { + putSM4(); + } +- if (!"false".equalsIgnoreCase(props.getProperty("kae.hmac"))) { ++ if (KAEConfig.useKaeProvider("kae.hmac")) { + putHMAC(); + } +- if (!"false".equalsIgnoreCase(props.getProperty("kae.rsa"))) { ++ if (KAEConfig.useKaeProvider("kae.rsa")) { + putRSA(); + putSignatureRSA(); + } +- if (!"false".equalsIgnoreCase(props.getProperty("kae.dh"))) { ++ if (KAEConfig.useKaeProvider("kae.dh")) { + putDH(); + } +- if (!"false".equalsIgnoreCase(props.getProperty("kae.ec"))) { ++ if (KAEConfig.useKaeProvider("kae.ec")) { + putEC(); + } + } +@@ -285,28 +272,28 @@ public class KAEProvider extends Provider { + "org.openeuler.security.openssl.KAERSASignature$SHA512withRSA"); + + // alias +- put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA"); + +- put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA"); +- put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA"); ++ put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA"); + +- put("Alg.Alias.Signature.1.2.840.113549.1.1.14", "SHA224withRSA"); ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.14", "SHA224withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.14", "SHA224withRSA"); + +- put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA"); ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA"); + +- put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA"); ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA"); + +- put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA"); ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA"); + + put("Signature.RSASSA-PSS", "org.openeuler.security.openssl.KAERSAPSSSignature"); + +- put("Alg.Alias.Signature.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.10", "RSASSA-PSS"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); + + // attributes for supported key classes +@@ -326,6 +313,10 @@ public class KAEProvider extends Provider { + put("Alg.Alias.KeyPairGenerator.EllipticCurve", "EC"); + put("KeyAgreement.ECDH", "org.openeuler.security.openssl.KAEECDHKeyAgreement"); + } ++ + // init openssl +- static native void initOpenssl() throws RuntimeException; ++ static native void initOpenssl(boolean useGlobalMode, String engineId, boolean[] algorithmKaeFlags) ++ throws RuntimeException; ++ ++ static native boolean[] getEngineFlags(); + } +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAESM4Cipher.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAESM4Cipher.java +index b189bea3a..cca619e1a 100644 +--- a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAESM4Cipher.java ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAESM4Cipher.java +@@ -26,13 +26,20 @@ + + package org.openeuler.security.openssl; + ++import sun.security.util.Debug; ++ ++import java.nio.ByteBuffer; + import java.security.InvalidAlgorithmParameterException; + import java.security.InvalidKeyException; + import java.security.NoSuchAlgorithmException; + import java.security.Key; ++import java.security.ProviderException; + import java.util.Locale; + ++import javax.crypto.BadPaddingException; ++import javax.crypto.IllegalBlockSizeException; + import javax.crypto.NoSuchPaddingException; ++import javax.crypto.ShortBufferException; + + /* + * This class currently supports: +@@ -46,6 +53,55 @@ import javax.crypto.NoSuchPaddingException; + */ + abstract class KAESM4Cipher extends KAESymmetricCipherBase { + ++ private static final Debug debug = Debug.getInstance("kae"); ++ ++ /* ++ * SM4 max chunk size of each encryption or decryption ++ * when input data does not have an accessible byte[] ++ */ ++ private static final int DEFAULT_KAE_SM4_MAX_CHUNK_SIZE = 4096; ++ private static int KAE_SM4_MAX_CHUNK_SIZE; ++ static { ++ initSM4MaxChunkSize(); ++ } ++ ++ private static void initSM4MaxChunkSize() { ++ String maxChunkSize = KAEConfig.privilegedGetOverridable("kae.sm4.maxChunkSize", ++ DEFAULT_KAE_SM4_MAX_CHUNK_SIZE + ""); ++ try { ++ KAE_SM4_MAX_CHUNK_SIZE = Integer.parseInt(maxChunkSize); ++ } catch (NumberFormatException e) { ++ // When parsing string argument to signed decimal integer fails, uses the default chunk size (4096) ++ KAE_SM4_MAX_CHUNK_SIZE = DEFAULT_KAE_SM4_MAX_CHUNK_SIZE; ++ if (debug != null) { ++ debug.println("The configured block size (" + maxChunkSize + ") cannot be converted to an integer, " + ++ "uses the default chunk size (" + DEFAULT_KAE_SM4_MAX_CHUNK_SIZE + ")"); ++ e.printStackTrace(); ++ } ++ return; ++ } ++ // when the configured chunk size is less than or equal to 0, uses the default chunk size (4096) ++ if (KAE_SM4_MAX_CHUNK_SIZE <= 0) { ++ KAE_SM4_MAX_CHUNK_SIZE = DEFAULT_KAE_SM4_MAX_CHUNK_SIZE; ++ if (debug != null) { ++ debug.println("The configured chunk size (" + KAE_SM4_MAX_CHUNK_SIZE + ") is less than " + ++ "or equal to 0, uses the default chunk size (" + DEFAULT_KAE_SM4_MAX_CHUNK_SIZE + ")"); ++ } ++ return; ++ } ++ if (debug != null) { ++ debug.println("The configured chunk size is " + KAE_SM4_MAX_CHUNK_SIZE); ++ } ++ } ++ ++ /** ++ * Used by the engineUpdate(ByteBuffer, ByteBuffer) and ++ * engineDoFinal(ByteBuffer, ByteBuffer) methods. ++ */ ++ private static int getSM4MaxChunkSize(int totalSize) { ++ return Math.min(KAE_SM4_MAX_CHUNK_SIZE, totalSize); ++ } ++ + public static class Sm4 extends KAESM4Cipher { + public Sm4(Mode mode, Padding padding) { + super(mode, padding, 16); +@@ -170,6 +226,131 @@ abstract class KAESM4Cipher extends KAESymmetricCipherBase { + } + } + ++ @Override ++ protected int engineUpdate(ByteBuffer input, ByteBuffer output) throws ShortBufferException { ++ try { ++ return bufferCrypt(input, output, true); ++ } catch (IllegalBlockSizeException e) { ++ // never thrown for engineUpdate() ++ throw new ProviderException("Internal error in update()"); ++ } catch (BadPaddingException e) { ++ // never thrown for engineUpdate() ++ throw new ProviderException("Internal error in update()"); ++ } ++ } ++ ++ @Override ++ protected int engineDoFinal(ByteBuffer input, ByteBuffer output) ++ throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { ++ return bufferCrypt(input, output, false); ++ } ++ ++ /** ++ * Implementation for encryption using ByteBuffers. Used for both ++ * engineUpdate() and engineDoFinal(). ++ */ ++ private int bufferCrypt(ByteBuffer input, ByteBuffer output, ++ boolean isUpdate) throws ShortBufferException, ++ IllegalBlockSizeException, BadPaddingException { ++ if ((input == null) || (output == null)) { ++ throw new NullPointerException ++ ("Input and output buffers must not be null"); ++ } ++ int inPos = input.position(); ++ int inLimit = input.limit(); ++ int inLen = inLimit - inPos; ++ if (isUpdate && (inLen == 0)) { ++ return 0; ++ } ++ int outLenNeeded = engineGetOutputSize(inLen); ++ ++ if (output.remaining() < outLenNeeded) { ++ throw new ShortBufferException("Need at least " + outLenNeeded ++ + " bytes of space in output buffer"); ++ } ++ ++ // detecting input and output buffer overlap may be tricky ++ // we can only write directly into output buffer when we ++ // are 100% sure it's safe to do so ++ ++ boolean a1 = input.hasArray(); ++ boolean a2 = output.hasArray(); ++ int total = 0; ++ ++ if (a1) { // input has an accessible byte[] ++ byte[] inArray = input.array(); ++ int inOfs = input.arrayOffset() + inPos; ++ ++ byte[] outArray; ++ if (a2) { // output has an accessible byte[] ++ outArray = output.array(); ++ int outPos = output.position(); ++ int outOfs = output.arrayOffset() + outPos; ++ ++ // check array address and offsets and use temp output buffer ++ // if output offset is larger than input offset and ++ // falls within the range of input data ++ boolean useTempOut = false; ++ if (inArray == outArray && ++ ((inOfs < outOfs) && (outOfs < inOfs + inLen))) { ++ useTempOut = true; ++ outArray = new byte[outLenNeeded]; ++ outOfs = 0; ++ } ++ if (isUpdate) { ++ total = engineUpdate(inArray, inOfs, inLen, outArray, outOfs); ++ } else { ++ total = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs); ++ } ++ if (useTempOut) { ++ output.put(outArray, outOfs, total); ++ } else { ++ // adjust output position manually ++ output.position(outPos + total); ++ } ++ } else { // output does not have an accessible byte[] ++ if (isUpdate) { ++ outArray = engineUpdate(inArray, inOfs, inLen); ++ } else { ++ outArray = engineDoFinal(inArray, inOfs, inLen); ++ } ++ if (outArray != null && outArray.length != 0) { ++ output.put(outArray); ++ total = outArray.length; ++ } ++ } ++ // adjust input position manually ++ input.position(inLimit); ++ } else { // input does not have an accessible byte[] ++ // have to assume the worst, since we have no way of determine ++ // if input and output overlaps or not ++ byte[] tempOut = new byte[outLenNeeded]; ++ int outOfs = 0; ++ ++ byte[] tempIn = new byte[getSM4MaxChunkSize(inLen)]; ++ do { ++ int chunk = Math.min(inLen, tempIn.length); ++ if (chunk > 0) { ++ input.get(tempIn, 0, chunk); ++ } ++ int n; ++ if (isUpdate || (inLen > chunk)) { ++ n = engineUpdate(tempIn, 0, chunk, tempOut, outOfs); ++ } else { ++ n = engineDoFinal(tempIn, 0, chunk, tempOut, outOfs); ++ } ++ outOfs += n; ++ total += n; ++ inLen -= chunk; ++ } while (inLen > 0); ++ if (total > 0) { ++ output.put(tempOut, 0, total); ++ } ++ } ++ ++ return total; ++ } ++ + protected void checkIvBytes(byte[] ivBytes) throws InvalidAlgorithmParameterException { + if (ivBytes == null) { + throw new InvalidAlgorithmParameterException("Wrong IV length: iv is null "); +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c +index 80a0e58b9..d9b16ab9d 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c +@@ -24,12 +24,11 @@ + #include + #include + #include ++#include "kae_log.h" + #include "kae_util.h" + #include "kae_exception.h" + #include "org_openeuler_security_openssl_KAERSACipher.h" + +-static ENGINE* kaeEngine = NULL; +- + typedef int RSACryptOperation(int, const unsigned char*, unsigned char*, RSA*, int); + + typedef int EvpPkeyCryptOperation(EVP_PKEY_CTX*, unsigned char*, size_t*, const unsigned char*, size_t); +@@ -176,7 +175,9 @@ static int RSACryptOAEPPadding(JNIEnv* env, jlong keyAddress, jint inLen, jbyteA + // outLen type should be size_t + // EVP_PKEY_encrypt takes the outLen address as a parameter, and the parameter type is size_t* + size_t outLen = 0; +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("RSACryptOAEPPadding: kaeEngine => %p", kaeEngine); ++ + + EVP_PKEY* pkey = (EVP_PKEY*) keyAddress; + +@@ -272,7 +273,8 @@ JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeC + BIGNUM* bnIQMP = NULL; + RSA* rsa = NULL; + EVP_PKEY* pkey = NULL; +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSACipher_nativeCreateRSAPrivateCrtKey: kaeEngine => %p", kaeEngine); + + // convert to big num + if ((bnN = KAE_GetBigNumFromByteArray(env, n)) == NULL || +@@ -334,7 +336,8 @@ JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeC + BIGNUM* bnE = NULL; + RSA* rsa = NULL; + EVP_PKEY* pkey = NULL; +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSACipher_nativeCreateRSAPublicKey: kaeEngine => %p", kaeEngine); + + // get public key param n + bnN = KAE_GetBigNumFromByteArray(env, n); +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c +index f0e7b0be4..23b178978 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c +@@ -42,7 +42,7 @@ JNIEXPORT jlong JNICALL + Java_org_openeuler_security_openssl_KAEDigest_nativeInit(JNIEnv *env, jclass cls, jstring algorithmName) + { + EVP_MD_CTX* ctx = NULL; +- static ENGINE* kaeEngine = NULL; ++ ENGINE* kaeEngine = NULL; + + if (algorithmName == NULL) { + KAE_ThrowNullPointerException(env, "algorithm is null"); +@@ -51,11 +51,8 @@ Java_org_openeuler_security_openssl_KAEDigest_nativeInit(JNIEnv *env, jclass cls + + // EVP_get_digestbyname + const char* algo_utf = (*env)->GetStringUTFChars(env, algorithmName, 0); +- if ((strcasecmp(algo_utf, "md5") == 0) || (strcasecmp(algo_utf, "sm3") == 0)) { +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; +- } else { +- kaeEngine = NULL; +- } ++ kaeEngine = GetDigestEngineByAlgorithmName(algo_utf); ++ KAE_TRACE("KAEDigest_nativeInit: kaeEngine => %p", kaeEngine); + EVP_MD* md = (EVP_MD*) EVP_get_digestbyname(algo_utf); + (*env)->ReleaseStringUTFChars(env, algorithmName, algo_utf); + if (md == NULL) { +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_hmac.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_hmac.c +index 554a9750c..1efacbb5b 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_hmac.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_hmac.c +@@ -73,9 +73,14 @@ JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAEHMac_nativeInit + HMAC_CTX* ctx = NULL; + jbyte* key_buffer = NULL; + const EVP_MD* md = NULL; ++ ENGINE* kaeEngine = NULL; + + const char* algo = (*env)->GetStringUTFChars(env, algoStr, 0); +- md = EVPGetDigestByName(env, algo); ++ md = EVPGetDigestByName(env, algo); ++ ++ kaeEngine = GetHmacEngineByAlgorithmName(algo); ++ KAE_TRACE("KAEHMac_nativeInit: kaeEngine => %p", kaeEngine); ++ + (*env)->ReleaseStringUTFChars(env, algoStr, algo); + if (md == NULL) { + KAE_ThrowRuntimeException(env, "algorithm unsupport"); +@@ -98,7 +103,7 @@ JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAEHMac_nativeInit + } + + // init hmac context with sc_key and evp_md +- int result_code = HMAC_Init_ex(ctx, key_buffer, key_len, md, NULL); ++ int result_code = HMAC_Init_ex(ctx, key_buffer, key_len, md, kaeEngine); + if (result_code == 0) { + KAE_ThrowRuntimeException(env, "Hmac_Init_ex invoked failed"); + goto cleanup; +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keyagreement_dh.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keyagreement_dh.c +index 7cdf790cb..d8d2ee7cb 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keyagreement_dh.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keyagreement_dh.c +@@ -51,8 +51,8 @@ JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAEDHKeyAgreeme + int computekeyLength = 0; + unsigned char* secret = NULL; + jbyteArray retByteArray = NULL; +- static ENGINE* kaeEngine = NULL; +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(DH_INDEX); ++ KAE_TRACE("KAEDHKeyAgreement_nativeComputeKey: kaeEngine => %p", kaeEngine); + + // bits to Bytes + int pSizeInByte = (pSize +7) >> 3; +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_dh.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_dh.c +index 54dc07edd..d16b42b41 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_dh.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_dh.c +@@ -50,8 +50,8 @@ JNIEXPORT jobjectArray JNICALL Java_org_openeuler_security_openssl_KAEDHKeyPairG + jobjectArray keys = NULL; + jbyteArray pri_key = NULL; + jbyteArray pub_key = NULL; +- static ENGINE* kaeEngine = NULL; +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(DH_INDEX); ++ KAE_TRACE("KAEDHKeyPairGenerator_nativeGenerateKeyPair: kaeEngine => %p", kaeEngine); + + KAE_TRACE("Java_org_openeuler_security_openssl_KAEDHKeyPairGenerator_nativeGenerateKeyPair start !"); + +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c +index 2ca978bbe..9251b56c4 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c +@@ -23,6 +23,7 @@ + + #include + #include ++#include "kae_log.h" + #include "kae_util.h" + #include "kae_exception.h" + #include "org_openeuler_security_openssl_KAERSAKeyPairGenerator.h" +@@ -62,8 +63,9 @@ static const BIGNUM* (* GetRSAParamFunctionList[])(const RSA*) = { + * step 3.Generate rsa key, and all key information is stored in RSA + */ + static RSA* NewRSA(JNIEnv* env, jint keySize, jbyteArray publicExponent) { +- static ENGINE* kaeEngine = NULL; +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("NewRSA: kaeEngine => %p", kaeEngine); ++ + // new rsa + RSA* rsa = RSA_new_method(kaeEngine); + if (rsa == NULL) { +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c +index aa46e737e..fca035b04 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c +@@ -24,21 +24,53 @@ + #include + #include + #include ++#include + #include "kae_exception.h" + #include "kae_util.h" + #include "org_openeuler_security_openssl_KAEProvider.h" + ++#define KAE_OPENSSL_LIBRARY "libcrypto.so" ++ + /* + * Class: Java_org_openeuler_security_openssl_KAEProvider + * Method: initOpenssl + * Signature: ()V + */ + JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEProvider_initOpenssl +- (JNIEnv *env, jclass cls) { ++ (JNIEnv *env, jclass cls, jboolean useGlobalMode, jstring engineId, jbooleanArray algorithmKaeFlags) { + SSL_load_error_strings(); + ERR_load_BIO_strings(); + OpenSSL_add_all_algorithms(); + ++ /* ++ * If the same shared object is opened again with dlopen(), the same object handle is returned. ++ * The dynamic linker maintains reference counts for object handles. ++ * An object that was previously opened with RTLD_LOCAL can be promoted to RTLD_GLOBAL in a subsequent dlopen(). ++ * ++ * RTLD_GLOBAL ++ * The symbols defined by this shared object will be made ++ * available for symbol resolution of subsequently loaded ++ * shared objects. ++ * RTLD_LOCAL ++ * This is the converse of RTLD_GLOBAL, and the default if ++ * neither flag is specified. Symbols defined in this shared ++ * object are not made available to resolve references in ++ * subsequently loaded shared objects. ++ * For more information see https://man7.org/linux/man-pages/man3/dlopen.3.html. ++ */ ++ if (useGlobalMode) { ++ char msg[1024]; ++ void *handle = NULL; ++ // Promote the flags of the loaded libcrypto.so library from RTLD_LOCAL to RTLD_GLOBAL ++ handle = dlopen(KAE_OPENSSL_LIBRARY, RTLD_LAZY | RTLD_GLOBAL); ++ if (handle == NULL) { ++ snprintf(msg, sizeof(msg), "Cannot load %s (%s)!", KAE_OPENSSL_LIBRARY, dlerror()); ++ KAE_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg); ++ return; ++ } ++ dlclose(handle); ++ } ++ + // check if KaeEngine holder is already set + ENGINE* e = GetKaeEngine(); + if (e != NULL) { +@@ -47,11 +79,25 @@ JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEProvider_initOpens + } + + // determine whether KAE is loaded successfully +- e = ENGINE_by_id("kae"); ++ const char* id = (*env)->GetStringUTFChars(env, engineId, 0); ++ e = ENGINE_by_id(id); ++ (*env)->ReleaseStringUTFChars(env, engineId, id); + if (e == NULL) { +- ERR_clear_error(); +- KAE_ThrowRuntimeException(env, "kae engine not found"); ++ KAE_ThrowFromOpenssl(env, "ENGINE_by_id", KAE_ThrowRuntimeException); + return; + } + SetKaeEngine(e); ++ ++ // initialize the engine for each algorithm ++ initEngines(env, algorithmKaeFlags); + } ++ ++/* ++ * Class: Java_org_openeuler_security_openssl_KAEProvider ++ * Method: getEngineFlags ++ * Signature: ()V ++ */ ++JNIEXPORT jbooleanArray JNICALL Java_org_openeuler_security_openssl_KAEProvider_getEngineFlags ++ (JNIEnv *env, jclass cls) { ++ return getEngineFlags(env); ++} +\ No newline at end of file +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_signature_rsa.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_signature_rsa.c +index e81dc1406..6c401356d 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_signature_rsa.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_signature_rsa.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include "kae_log.h" + #include "kae_util.h" + #include "kae_exception.h" + +@@ -99,8 +100,9 @@ JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAERSASignature + jbyte* digestBytes = NULL; + jbyte* sigBytes = NULL; + jbyteArray sigByteArray = NULL; +- static ENGINE* kaeEngine = NULL; +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSASignatureNative_rsaSign: kaeEngine => %p", kaeEngine); ++ + // new EVP_PKEY_CTX + if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); +@@ -163,8 +165,9 @@ JNIEXPORT jboolean JNICALL Java_org_openeuler_security_openssl_KAERSASignatureNa + jbyte* digestBytes = NULL; + jbyte* sigBytes = NULL; + jboolean isSuccess = JNI_FALSE; +- static ENGINE* kaeEngine = NULL; +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSASignatureNative_rsaVerify: kaeEngine => %p", kaeEngine); ++ + // new EVP_PKEY_CTX + if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); +@@ -255,8 +258,9 @@ JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAERSASignature + jbyte* digestBytes = NULL; + jbyte* sigBytes = NULL; + jbyteArray sigByteArray = NULL; +- static ENGINE* kaeEngine = NULL; +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSASignatureNative_pssSign: kaeEngine => %p", kaeEngine); ++ + // new EVP_PKEY_CTX + if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); +@@ -320,8 +324,9 @@ JNIEXPORT jboolean JNICALL Java_org_openeuler_security_openssl_KAERSASignatureNa + jbyte* digestBytes = NULL; + jbyte* sigBytes = NULL; + jboolean isSuccess = JNI_FALSE; +- static ENGINE* kaeEngine = NULL; +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSASignatureNative_pssVerify: kaeEngine => %p", kaeEngine); ++ + // new EVP_PKEY_CTX + if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_symmetric_cipher.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_symmetric_cipher.c +index 71c28bdea..43f6326b2 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_symmetric_cipher.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_symmetric_cipher.c +@@ -142,16 +142,19 @@ Java_org_openeuler_security_openssl_KAESymmetricCipherBase_nativeInit(JNIEnv* en + jbyte* keyBytes = NULL; + jbyte* ivBytes = NULL; + const EVP_CIPHER* cipher = NULL; +- static ENGINE* kaeEngine = NULL; ++ ENGINE* kaeEngine = NULL; + + const char* algo = (*env)->GetStringUTFChars(env, cipherType, 0); + if (StartsWith("aes", algo)) { + cipher = EVPGetAesCipherByName(env, algo); +- kaeEngine = NULL; ++ kaeEngine = GetAesEngineByAlgorithmName(algo); + } else { + cipher = EVPGetSm4CipherByName(env, algo); +- kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ kaeEngine = GetSm4EngineByAlgorithmName(algo); + } ++ ++ KAE_TRACE("KAESymmetricCipherBase_nativeInit: kaeEngine => %p", kaeEngine); ++ + (*env)->ReleaseStringUTFChars(env, cipherType, algo); + if (cipher == NULL) { + KAE_ThrowOOMException(env, "create EVP_CIPHER fail"); +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c +index 0e656a834..a16d944c4 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c +@@ -22,6 +22,7 @@ + */ + + #include ++#include + #include "kae_util.h" + #include "kae_exception.h" + +@@ -55,7 +56,7 @@ BIGNUM* KAE_GetBigNumFromByteArray(JNIEnv* env, jbyteArray byteArray) { + + jbyte* bytes = (*env)->GetByteArrayElements(env, byteArray, NULL); + if (bytes == NULL) { +- KAE_ThrowNullPointerException(env,"GetByteArrayElements failed"); ++ KAE_ThrowNullPointerException(env, "GetByteArrayElements failed"); + goto cleanup; + } + BIGNUM* result = BN_bin2bn((const unsigned char*) bytes, len, bn); +@@ -109,3 +110,138 @@ cleanup: + (*env)->ReleaseByteArrayElements(env, javaBytes, bytes, 0); + return javaBytes; + } ++ ++#define ENGINE_LENGTH (EC_INDEX + 1) ++static ENGINE* engines[ENGINE_LENGTH] = {NULL}; ++static jboolean engineFlags[ENGINE_LENGTH] = {JNI_FALSE}; ++static KAEAlgorithm kaeAlgorithms[ENGINE_LENGTH] = { ++ {MD5_INDEX, "md5"}, ++ {SHA256_INDEX, "sha256"}, ++ {SHA384_INDEX, "sha384"}, ++ {SM3_INDEX, "sm3"}, ++ {AES_128_ECB_INDEX, "aes-128-ecb"}, ++ {AES_128_CBC_INDEX, "aes-128-cbc"}, ++ {AES_128_CTR_INDEX, "aes-128-ctr"}, ++ {AES_128_GCM_INDEX, "aes-128-gcm"}, ++ {AES_192_ECB_INDEX, "aes-192-ecb"}, ++ {AES_192_CBC_INDEX, "aes-192-cbc"}, ++ {AES_192_CTR_INDEX, "aes-192-ctr"}, ++ {AES_192_GCM_INDEX, "aes-192-gcm"}, ++ {AES_256_ECB_INDEX, "aes-256-ecb"}, ++ {AES_256_CBC_INDEX, "aes-256-cbc"}, ++ {AES_256_CTR_INDEX, "aes-256-ctr"}, ++ {AES_256_GCM_INDEX, "aes-256-gcm"}, ++ {SM4_ECB_INDEX, "sm4-ecb"}, ++ {SM4_CBC_INDEX, "sm4-cbc"}, ++ {SM4_CTR_INDEX, "sm4-ctr"}, ++ {SM4_OFB_INDEX, "sm4-ofb"}, ++ {HMAC_MD5_INDEX, "hmac-md5"}, ++ {HMAC_SHA1_INDEX, "hmac-sha1"}, ++ {HMAC_SHA224_INDEX, "hmac-sha224"}, ++ {HMAC_SHA256_INDEX, "hmac-sha256"}, ++ {HMAC_SHA384_INDEX, "hmac-sha384"}, ++ {HMAC_SHA512_INDEX, "hmac-sha512"}, ++ {RSA_INDEX, "rsa"}, ++ {DH_INDEX, "dh"}, ++ {EC_INDEX, "ec"} ++}; ++ ++void initEngines(JNIEnv* env, jbooleanArray algorithmKaeFlags) { ++ if (algorithmKaeFlags == NULL) { ++ return; ++ } ++ ++ // get jTemp ++ jboolean* jTemp = NULL; ++ int length = (*env)->GetArrayLength(env, algorithmKaeFlags); ++ jTemp = (jboolean*) malloc(length); ++ if (jTemp == NULL) { ++ KAE_ThrowOOMException(env, "initEngines GetArrayLength error"); ++ return; ++ } ++ (*env)->GetBooleanArrayRegion(env, algorithmKaeFlags, 0, length, jTemp); ++ ++ // assign engines ++ int minLen = length < ENGINE_LENGTH ? length : ENGINE_LENGTH; ++ int i; ++ for (i = 0; i < minLen; i++) { ++ if (jTemp[i]) { ++ engines[i] = kaeEngine; ++ engineFlags[i] = JNI_TRUE; ++ } ++ } ++ if (length < ENGINE_LENGTH) { ++ for (i = minLen; i < ENGINE_LENGTH; i++) { ++ engines[i] = kaeEngine; ++ engineFlags[i] = JNI_TRUE; ++ } ++ } ++ ++ // free jTemp ++ if (jTemp != NULL) { ++ free(jTemp); ++ } ++} ++ ++jbooleanArray getEngineFlags(JNIEnv* env) { ++ jbooleanArray array = (*env)->NewBooleanArray(env, ENGINE_LENGTH); ++ (*env)->SetBooleanArrayRegion(env, array, 0, ENGINE_LENGTH, engineFlags); ++ return array; ++} ++ ++ENGINE* GetEngineByAlgorithmIndex(AlgorithmIndex algorithmIndex) { ++ return engines[algorithmIndex]; ++} ++ ++/* ++ * Get the engine used by the specified algorithm. ++ * @param beginIndex the beginning index, inclusive. ++ * @param endIndex the ending index, exclusive. ++ * @param algorithmName algorithm name ++ * @return engine ++ */ ++ENGINE* GetEngineByBeginIndexAndEndIndex(int beginIndex, int endIndex, ++ const char* algorithmName) { ++ if (beginIndex < 0 || endIndex > ENGINE_LENGTH) { ++ return NULL; ++ } ++ ++ int i; ++ for (i = beginIndex; i < endIndex; i++) { ++ if (strcasecmp(kaeAlgorithms[i].algorithmName, algorithmName) == 0) { ++ return engines[kaeAlgorithms[i].algorithmIndex]; ++ } ++ } ++ return NULL; ++} ++ ++ENGINE* GetHmacEngineByAlgorithmName(const char* algorithmName) { ++ char prefix[] = {"hmac-"}; ++ int len = strlen(algorithmName); ++ int newLen = strlen(algorithmName) + strlen(prefix) + 1; ++ char* newAlgorithmName = NULL; ++ newAlgorithmName = malloc(newLen); ++ if (newAlgorithmName == NULL) { ++ return NULL; ++ } ++ strcpy(newAlgorithmName, prefix); ++ strcat(newAlgorithmName, algorithmName); ++ ENGINE* engine = GetEngineByBeginIndexAndEndIndex(HMAC_MD5_INDEX, HMAC_SHA512_INDEX + 1, newAlgorithmName); ++ if (newAlgorithmName != NULL) { ++ free(newAlgorithmName); ++ } ++ return engine; ++} ++ ++ENGINE* GetDigestEngineByAlgorithmName(const char* algorithmName) { ++ return GetEngineByBeginIndexAndEndIndex(MD5_INDEX, SM3_INDEX + 1, algorithmName); ++} ++ ++ENGINE* GetAesEngineByAlgorithmName(const char* algorithmName) { ++ return GetEngineByBeginIndexAndEndIndex(AES_128_ECB_INDEX, AES_256_GCM_INDEX + 1, algorithmName); ++} ++ ++ENGINE* GetSm4EngineByAlgorithmName(const char* algorithmName) { ++ return GetEngineByBeginIndexAndEndIndex(SM4_ECB_INDEX, SM4_OFB_INDEX + 1, algorithmName); ++} ++ +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h +index 13bd5976d..347337509 100644 +--- a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h +@@ -27,6 +27,43 @@ + #include + #include + ++typedef enum { ++ MD5_INDEX, ++ SHA256_INDEX, ++ SHA384_INDEX, ++ SM3_INDEX, ++ AES_128_ECB_INDEX, ++ AES_128_CBC_INDEX, ++ AES_128_CTR_INDEX, ++ AES_128_GCM_INDEX, ++ AES_192_ECB_INDEX, ++ AES_192_CBC_INDEX, ++ AES_192_CTR_INDEX, ++ AES_192_GCM_INDEX, ++ AES_256_ECB_INDEX, ++ AES_256_CBC_INDEX, ++ AES_256_CTR_INDEX, ++ AES_256_GCM_INDEX, ++ SM4_ECB_INDEX, ++ SM4_CBC_INDEX, ++ SM4_CTR_INDEX, ++ SM4_OFB_INDEX, ++ HMAC_MD5_INDEX, ++ HMAC_SHA1_INDEX, ++ HMAC_SHA224_INDEX, ++ HMAC_SHA256_INDEX, ++ HMAC_SHA384_INDEX, ++ HMAC_SHA512_INDEX, ++ RSA_INDEX, ++ DH_INDEX, ++ EC_INDEX ++} AlgorithmIndex; ++ ++typedef struct { ++ AlgorithmIndex algorithmIndex; ++ const char* algorithmName; ++} KAEAlgorithm; ++ + /* jbyteArray convert to BIGNUM */ + BIGNUM* KAE_GetBigNumFromByteArray(JNIEnv* env, jbyteArray byteArray); + +@@ -40,8 +77,18 @@ void SetKaeEngine(ENGINE* engine); + + ENGINE* GetKaeEngine(); + +-void SetKaeEngine(ENGINE* engine); ++void initEngines(JNIEnv* env, jbooleanArray algorithmKaeFlags); + +-ENGINE* GetKaeEngine(); ++jbooleanArray getEngineFlags(JNIEnv* env); ++ ++ENGINE* GetEngineByAlgorithmIndex(AlgorithmIndex algorithmIndex); ++ ++ENGINE* GetHmacEngineByAlgorithmName(const char* algorithmName); ++ ++ENGINE* GetDigestEngineByAlgorithmName(const char* algorithmName); ++ ++ENGINE* GetAesEngineByAlgorithmName(const char* algorithmName); ++ ++ENGINE* GetSm4EngineByAlgorithmName(const char* algorithmName); + + #endif +diff --git a/jdk/test/org/openeuler/security/openssl/AESTest.java b/jdk/test/org/openeuler/security/openssl/AESTest.java +new file mode 100644 +index 000000000..77da5ecc2 +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/AESTest.java +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.nio.charset.StandardCharsets; ++import java.security.Security; ++import java.security.spec.AlgorithmParameterSpec; ++import javax.crypto.Cipher; ++import javax.crypto.KeyGenerator; ++import javax.crypto.SecretKey; ++import javax.crypto.spec.IvParameterSpec; ++ ++/** ++ * @test ++ * @summary Basic test for AES ++ * @requires os.arch=="aarch64" ++ * @run main AESTest ++ */ ++ ++public class AESTest { ++ private static final String[] ALGORITHM = {"AES", "AES_128", "AES_192", "AES_256"}; ++ private static final String[] MODES = {"ECB", "CBC", "CTR", "GCM"}; ++ private static final String[] PADDING = {"NoPadding", "PKCS5Padding"}; ++ private static final int AES_128_KEY_LENGTH = 128; ++ private static final int AES_192_KEY_LENGTH = 192; ++ private static final int AES_256_KEY_LENGTH = 256; ++ private static String plainText = "helloworldhellow"; // 16bytes for NoPadding ++ private static String shortPlainText = "helloworld"; // 5 bytes for padding ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (String algo : ALGORITHM) { ++ for (String mode : MODES) { ++ int padKinds = 2; ++ if (mode.equalsIgnoreCase("CTR")) { ++ padKinds = 1; ++ } ++ for (int k = 0; k < padKinds; k++) { ++ test(algo, mode, PADDING[k]); ++ } ++ } ++ } ++ } ++ ++ public static void test(String algo, String mo, String pad) throws Exception { ++ AlgorithmParameterSpec aps = null; ++ ++ Cipher cipher = Cipher.getInstance(algo + "/" + mo + "/" + pad); ++ ++ KeyGenerator kg = KeyGenerator.getInstance("AES"); ++ if (algo.equalsIgnoreCase("AES_192")) { ++ kg.init(AES_192_KEY_LENGTH); ++ } else if (algo.equalsIgnoreCase("AES_256")) { ++ kg.init(AES_256_KEY_LENGTH); ++ } else { ++ kg.init(AES_128_KEY_LENGTH); ++ } ++ ++ SecretKey key = kg.generateKey(); ++ ++ // encrypt ++ if (!mo.equalsIgnoreCase("GCM")) { ++ cipher.init(Cipher.ENCRYPT_MODE, key, aps); ++ } else { ++ cipher.init(Cipher.ENCRYPT_MODE, key); ++ } ++ ++ String cipherString = null; ++ if (!pad.equalsIgnoreCase("NoPadding")) { ++ cipherString = shortPlainText; ++ } else { ++ cipherString = plainText; ++ } ++ byte[] cipherText = cipher.doFinal(cipherString.getBytes(StandardCharsets.UTF_8)); ++ if (!mo.equalsIgnoreCase("ECB")) { ++ aps = new IvParameterSpec(cipher.getIV()); ++ } else { ++ aps = null; ++ } ++ ++ if (!mo.equalsIgnoreCase("GCM")) { ++ cipher.init(Cipher.DECRYPT_MODE, key, aps); ++ } else { ++ cipher.init(Cipher.DECRYPT_MODE, key, cipher.getParameters()); ++ } ++ ++ String decryptPlainText = new String(cipher.doFinal(cipherText)); ++ ++ if (!cipherString.equals(decryptPlainText)) { ++ throw new RuntimeException("aes decryption failed, algo = " + algo + ", mo = " + mo + ", pad = " + pad); ++ } ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/DHTest.java b/jdk/test/org/openeuler/security/openssl/DHTest.java +index 6eb5e7c96..ee5d63684 100644 +--- a/jdk/test/org/openeuler/security/openssl/DHTest.java ++++ b/jdk/test/org/openeuler/security/openssl/DHTest.java +@@ -28,7 +28,6 @@ import java.io.Serializable; + import java.math.BigInteger; + import java.security.*; + import java.util.Arrays; +-import java.util.Date; + import javax.crypto.KeyAgreement; + import javax.crypto.spec.*; + import org.openeuler.security.openssl.KAEProvider; +@@ -75,18 +74,16 @@ import org.openeuler.security.openssl.KAEProvider; + /** + * @test + * @summary Basic test for DH ++ * @requires os.arch=="aarch64" + * @run main DHTest + */ + +-final class DHTest implements Serializable { +- private static int bitLength = 8192; ++public class DHTest implements Serializable { + private static BigInteger g512; + private static BigInteger p512; +- Throwable t = null; + + private static volatile Provider sunJceProvider; + private static volatile Provider kaeProvider; +- Date d = new Date(); + + public static void main(String[] args) throws Exception { + Security.addProvider(new KAEProvider()); +@@ -97,8 +94,6 @@ final class DHTest implements Serializable { + + p512 = new BigInteger("27672987386729926592037876826877634387173876890702920770064392919138769821035856568775311919542560094764667151024449425954917954337048895981297730855891532066350935045229294626339548842381843985759061682551900379979643117695834175891578650111093016914264824311693147701566019122696621248493126219217339690346346921463135605151471303957324058301097079967414639146647429422884520134312590056632178576758580657240245655739869017244657144448267757255018625514803292549109401806336918448001843022629625467069714240279603204909633404992842479161100500474744098408277938070656334892106100534117209709263785505019003765693651"); + +- DHTest.bitLength = 0; +- + DHParameterSpec dhParams = new DHParameterSpec(p512, g512); + KeyPairGenerator SunJCEkeyGen = KeyPairGenerator.getInstance("DH", sunJceProvider); + KeyPairGenerator KAEkeyGen = KeyPairGenerator.getInstance("DH", kaeProvider); +diff --git a/jdk/test/org/openeuler/security/openssl/DigestTest.java b/jdk/test/org/openeuler/security/openssl/DigestTest.java +new file mode 100644 +index 000000000..a293f7268 +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/DigestTest.java +@@ -0,0 +1,60 @@ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.nio.charset.StandardCharsets; ++import java.security.MessageDigest; ++import java.security.Security; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.Map; ++ ++/** ++ * @test ++ * @summary Basic test for MD5 SHA256 SHA384 ++ * @requires os.arch=="aarch64" ++ * @run main/othervm DigestTest ++ */ ++public class DigestTest { ++ private static String PLAIN_TEXT = "hello world"; ++ ++ private static Map alg = new HashMap(); ++ ++ static { ++ alg.put("MD5", new byte[] {94, -74, 59, -69, -32, 30, -18, -48, -109, -53, 34, -69, -113, 90, -51, -61}); ++ alg.put( ++ "SHA-256", ++ new byte[] { ++ -71, 77, 39, -71, -109, 77, 62, 8, -91, 46, 82, -41, -38, 125, -85, -6, ++ -60, -124, -17, -29, 122, 83, -128, -18, -112, -120, -9, -84, -30, -17, -51, -23 ++ }); ++ alg.put( ++ "SHA-384", ++ new byte[] { ++ -3, -67, -114, 117, -90, 127, 41, -9, 1, -92, -32, 64, 56, 94, 46, 35, ++ -104, 99, 3, -22, 16, 35, -110, 17, -81, -112, 127, -53, -72, 53, 120, -77, ++ -28, 23, -53, 113, -50, 100, 110, -3, 8, 25, -35, -116, 8, -115, -31, -67 ++ }); ++ alg.put( ++ "SM3", ++ new byte[] { ++ 68, -16, 6, 30, 105, -6, 111, -33, -62, -112, -60, -108, 101, 74, 5, ++ -36, 12, 5, 61, -89, -27, -59, 43, -124, -17, -109, -87, -42, 125, 63, ++ -1, -120 ++ }); ++ } ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (String key : alg.keySet()) { ++ test(PLAIN_TEXT, key, alg.get(key)); ++ } ++ } ++ ++ public static void test(String plainText, String algo, byte[] expectRes) throws Exception { ++ MessageDigest md = MessageDigest.getInstance(algo); ++ md.update(plainText.getBytes(StandardCharsets.UTF_8)); ++ byte[] res = md.digest(); ++ if (!Arrays.equals(res, expectRes)) { ++ throw new RuntimeException(algo + " failed"); ++ } ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/ECDHTest.java b/jdk/test/org/openeuler/security/openssl/ECDHTest.java +index 590c31154..069c32295 100644 +--- a/jdk/test/org/openeuler/security/openssl/ECDHTest.java ++++ b/jdk/test/org/openeuler/security/openssl/ECDHTest.java +@@ -41,6 +41,7 @@ import java.nio.charset.StandardCharsets; + /** + * @test + * @summary Basic test for ECDH ++ * @requires os.arch=="aarch64" + * @run main ECDHTest + */ + +diff --git a/jdk/test/org/openeuler/security/openssl/HmacTest.java b/jdk/test/org/openeuler/security/openssl/HmacTest.java +new file mode 100644 +index 000000000..9ff328629 +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/HmacTest.java +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import javax.crypto.Mac; ++import javax.crypto.spec.SecretKeySpec; ++import java.security.Key; ++import java.security.Security; ++import java.util.Arrays; ++ ++/** ++ * @test ++ * @summary test for Hmac ++ * @requires os.arch=="aarch64" ++ * @run main/othervm HmacTest ++ */ ++public class HmacTest { ++ private static final byte[] PLAIN_BYTES = "hello world".getBytes(); ++ private static final String[] ALGORITHMS = new String[]{ ++ "HmacMD5", ++ "HmacSHA1", ++ "HmacSHA224", ++ "HmacSHA256", ++ "HmacSHA384", ++ "HmacSHA512", ++ }; ++ private static final byte[][] EXPECTED_BYTES = { ++ {-40, 63, -96, 13, 107, -33, -1, -53, -116, 117, 75, -6, 85, -88, -112, -90}, ++ {-68, 104, 112, -36, 123, 123, -92, 104, 89, -90, 63, 56, 84, 45, 12, -7, 41, 103, -105, -27}, ++ {-31, 0, 103, 51, -119, -61, 2, -76, -83, -113, 95, 86, 8, 46, 91, 20, ++ -15, -23, -71, 62, -50, 86, -54, 71, -94, -47, -103, 43}, ++ {-69, -83, -3, 7, 61, 38, -122, -59, 7, -53, 106, 114, 58, 102, 65, -118, ++ 54, -50, 116, -56, 110, 54, -71, 36, 60, 84, 14, 97, 78, 18, -119, -24}, ++ {100, -58, 106, 64, -96, 91, 99, -33, 36, -78, -53, -50, -78, 116, -110, 85, ++ 84, -5, -63, 17, 51, -69, -39, -122, 65, 8, -122, -43, 39, 13, -41, -52, ++ 45, -38, -59, 70, 17, -87, -63, -126, 4, 120, -77, 71, 119, 96, -2, -68}, ++ {-89, 47, -98, -12, 110, -88, 23, 2, 28, 26, -71, 53, -108, 54, -52, 1, ++ -121, -121, 87, 6, -78, 123, -14, -86, 127, 114, 124, -73, -98, 79, -122, 69, ++ -32, 50, 48, -79, -110, 66, 38, 70, -3, -76, 95, 55, 74, 48, 57, -121, ++ 22, 60, -83, -109, 59, 79, 0, -49, 107, 88, -82, -35, 87, -36, 49, -54} ++ }; ++ private static final Key key = new SecretKeySpec("mac".getBytes(), ""); ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (int i = 0; i < ALGORITHMS.length; i++) { ++ test(ALGORITHMS[i], key, PLAIN_BYTES, EXPECTED_BYTES[i]); ++ } ++ } ++ ++ private static void test(String algorithm, Key key, byte[] inputBytes, byte[] expectedBytes) throws Exception { ++ Mac mac = Mac.getInstance(algorithm); ++ mac.init(key); ++ mac.update(inputBytes); ++ byte[] bytes = mac.doFinal(); ++ if (!(mac.getProvider() instanceof KAEProvider)) { ++ throw new RuntimeException(algorithm + " failed," + ++ "provider=" + mac.getProvider().getClass() + "," + ++ "expectedProvider=" + KAEProvider.class); ++ } ++ if (!Arrays.equals(bytes, expectedBytes)) { ++ throw new RuntimeException(algorithm + " failed," + ++ "bytes=" + Arrays.toString(bytes) + "," + ++ "expectedBytes=" + Arrays.toString(expectedBytes)); ++ } ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/KAEConfTest.java b/jdk/test/org/openeuler/security/openssl/KAEConfTest.java +new file mode 100644 +index 000000000..9028d28b5 +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/KAEConfTest.java +@@ -0,0 +1,121 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEConfig; ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.File; ++import java.io.FileWriter; ++import java.io.IOException; ++import java.nio.file.Files; ++import java.util.ArrayList; ++import java.util.List; ++ ++/* ++ * @test ++ * @summary Test KAE Conf ++ * @requires os.arch=="aarch64" ++ * @run main/othervm KAEConfTest DEFAULT ++ * @run main/othervm KAEConfTest SPECIFY ++ */ ++public class KAEConfTest { ++ private static final String DEFAULT_CONF = System.getProperty("java.home") + ++ File.separator + "lib" + File.separator + "kaeprovider.conf"; ++ ++ private static final String SPECIFY_CONF = System.getProperty("user.dir") + ++ File.separator + "kaeprovider.conf"; ++ ++ private static final String SPECIFY_LOG_PATH = System.getProperty("user.dir") + File.separator + "kae.log"; ++ private static final List files = new ArrayList<>(); ++ ++ enum Mode { ++ DEFAULT, ++ SPECIFY ++ } ++ ++ public static void main(String[] args) throws IOException { ++ Mode mode = getMode(args); ++ try { ++ init(mode); ++ new KAEProvider(); ++ test(mode); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static Mode getMode(String[] args) { ++ if (args.length <= 0) { ++ return Mode.DEFAULT; ++ } ++ return Mode.valueOf(args[0]); ++ } ++ ++ private static void init(Mode mode) throws IOException { ++ if (Mode.SPECIFY.equals(mode)) { ++ System.setProperty("kae.conf", SPECIFY_CONF); ++ File file = new File(SPECIFY_CONF); ++ if (!file.exists()) { ++ Files.createFile(file.toPath()); ++ } ++ files.add(file); ++ try (FileWriter fileWriter = new FileWriter(file)) { ++ fileWriter.write("kae.log=true"); ++ fileWriter.flush(); ++ } ++ } ++ } ++ ++ private static void testDefault() { ++ File file = new File(DEFAULT_CONF); ++ if (!file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ } ++ ++ private static void testSpecify() { ++ String value = KAEConfig.privilegedGetOverridable("kae.log"); ++ if (!"true".equals(value)) { ++ throw new RuntimeException("test failed : kae.log=" + value); ++ } ++ File file = new File(SPECIFY_LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException(SPECIFY_LOG_PATH + "does not exist"); ++ } ++ // kae log file ++ files.add(file); ++ } ++ ++ private static void test(Mode mode) { ++ switch (mode) { ++ case DEFAULT: ++ testDefault(); ++ break; ++ case SPECIFY: ++ testSpecify(); ++ break; ++ default: ++ throw new IllegalArgumentException("invalid mode"); ++ } ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java b/jdk/test/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java +new file mode 100644 +index 000000000..6301b6d76 +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEConfig; ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.util.HashSet; ++import java.util.Set; ++ ++/* ++ * @test ++ * @summary Test property kae.engine.disableAlgorithms ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm3 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-ofb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha1 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha224 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha512 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=rsa KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=dh KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=ec KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-gcm,aes-192-gcm,aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=md5,aes-128-ecb,sm4-ecb,hmac-sha1,rsa,dh,ec KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm3 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-ofb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha1 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha224 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha512 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=rsa KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=dh KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=ec KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-gcm,aes-192-gcm,aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=md5,aes-128-ecb,sm4-ecb,hmac-sha1,rsa,dh,ec KAEDisabledAlgorithmsTest ++ */ ++public class KAEDisabledAlgorithmsTest { ++ ++ public static void main(String[] args) { ++ KAETestHelper.Engine engine = KAETestHelper.getEngine(); ++ if (!engine.isValid()) { ++ System.out.println("Skip test, engine " + engine.getEngineId() + " does not exist."); ++ return; ++ } ++ String[] disabledAlgorithms = getDisabledAlgorithms(); ++ init(); ++ new KAEProvider(); ++ test(disabledAlgorithms); ++ } ++ ++ private static final String[] PROPERTY_NAMES = new String[]{ ++ "kae.digest.useKaeEngine", ++ "kae.aes.useKaeEngine", ++ "kae.sm4.useKaeEngine", ++ "kae.hmac.useKaeEngine", ++ "kae.rsa.useKaeEngine", ++ "kae.dh.useKaeEngine", ++ "kae.ec.useKaeEngine" ++ }; ++ ++ private static String[] getDisabledAlgorithms() { ++ String value = System.getProperty("kae.engine.disabledAlgorithms"); ++ if (value == null) { ++ return new String[0]; ++ } ++ return value.split(","); ++ } ++ ++ private static void init() { ++ for (String propertyName : PROPERTY_NAMES) { ++ System.setProperty(propertyName, "true"); ++ } ++ } ++ ++ private static void test(String[] disabledAlgorithms) { ++ boolean[] useKaeEngineFlags = KAEConfig.getUseKaeEngineFlags(); ++ Set disabledAlgorithmIndexSet = new HashSet<>(); ++ ++ // test disabled algorithms ++ for (String disabledAlgorithm : disabledAlgorithms) { ++ Integer index = KAETestHelper.getAlgorithmIndex(disabledAlgorithm); ++ if (index == null || index < 0 || index >= useKaeEngineFlags.length) { ++ continue; ++ } ++ if (useKaeEngineFlags[index]) { ++ throw new RuntimeException("test failed"); ++ } ++ disabledAlgorithmIndexSet.add(index); ++ } ++ ++ // test other algorithms that are not disabled (except ec) ++ for (int i = 0; i < useKaeEngineFlags.length - 1; i++) { ++ if (!disabledAlgorithmIndexSet.contains(i) && !useKaeEngineFlags[i]) { ++ throw new RuntimeException(KAETestHelper.getAlgorithmName(i) + " algorithm is not disabled"); ++ } ++ } ++ ++ // test whether the ec algorithm is disabled by default ++ if (useKaeEngineFlags[useKaeEngineFlags.length - 1]) { ++ throw new RuntimeException(KAETestHelper.getAlgorithmName(useKaeEngineFlags.length - 1) ++ + " algorithm is disabled by default"); ++ } ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/KAEEngineIdTest.java b/jdk/test/org/openeuler/security/openssl/KAEEngineIdTest.java +new file mode 100644 +index 000000000..2ddaf6712 +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/KAEEngineIdTest.java +@@ -0,0 +1,76 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.BufferedReader; ++import java.io.File; ++import java.io.FileReader; ++import java.io.IOException; ++import java.util.ArrayList; ++import java.util.List; ++ ++/* ++ * @test ++ * @summary Test KAE property kae.engine.id and kae.libcrypto.useGlobalMode ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Dkae.log=true KAEEngineIdTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=kae KAEEngineIdTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true KAEEngineIdTest ++ */ ++public class KAEEngineIdTest { ++ ++ private static final String LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "kae.log"; ++ ++ private static final List files = new ArrayList<>(); ++ ++ public static void main(String[] args) throws IOException { ++ KAETestHelper.Engine engine = KAETestHelper.getEngine(); ++ if (!engine.isValid()) { ++ System.out.println("Skip test, engine " + engine.getEngineId() + " does not exist."); ++ return; ++ } ++ ++ try { ++ new KAEProvider(); ++ test(engine); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static void test(KAETestHelper.Engine engine) throws IOException { ++ File file = new File(LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException(LOG_PATH + " does not exist"); ++ } ++ files.add(file); ++ try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) { ++ String s = bufferedReader.readLine(); ++ if (!s.contains(engine.getEngineId() + " engine was found")) { ++ throw new RuntimeException("test failed"); ++ } ++ } ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/KAELogTest.java b/jdk/test/org/openeuler/security/openssl/KAELogTest.java +new file mode 100644 +index 000000000..31c8f5d99 +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/KAELogTest.java +@@ -0,0 +1,126 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.File; ++import java.util.ArrayList; ++import java.util.List; ++ ++/* ++ * @test ++ * @summary Test KAE log ++ * @requires os.arch=="aarch64" ++ * @run main/othervm KAELogTest ++ * @run main/othervm -Dkae.log=false KAELogTest ++ * @run main/othervm -Dkae.log=true KAELogTest ++ * @run main/othervm -Dkae.log=true -Dkae.log.file=./KAELogTest/kae.log KAELogTest ++ */ ++public class KAELogTest { ++ private static final String DEFAULT_LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "kae.log"; ++ ++ private static final String SPECIFY_LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "KAELogTest" + File.separator + "kae.log"; ++ ++ private static final List files = new ArrayList<>(); ++ ++ enum Mode { ++ DEFAULT, ++ DISABLE, ++ ENABLE, ++ SPECIFY ++ } ++ ++ public static void main(String[] args) { ++ Mode mode = getMode(); ++ try { ++ new KAEProvider(); ++ test(mode); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static Mode getMode() { ++ String enableKaeLog = System.getProperty("kae.log"); ++ if (enableKaeLog == null) { ++ return Mode.DEFAULT; ++ } else if ("false".equals(enableKaeLog)) { ++ return Mode.DISABLE; ++ } else { ++ String logPath = System.getProperty("kae.log.file"); ++ if (logPath == null) { ++ return Mode.ENABLE; ++ } ++ return Mode.SPECIFY; ++ } ++ } ++ ++ private static void testDefault() { ++ testDisable(); ++ } ++ ++ private static void testDisable() { ++ File file = new File(DEFAULT_LOG_PATH); ++ if (file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ } ++ ++ private static void testEnable() { ++ File file = new File(DEFAULT_LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ files.add(file); ++ } ++ ++ private static void testSpecify() { ++ File file = new File(KAELogTest.SPECIFY_LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ files.add(file); ++ files.add(file.getParentFile()); ++ } ++ ++ private static void test(Mode mode) { ++ switch (mode) { ++ case DEFAULT: ++ testDefault(); ++ break; ++ case DISABLE: ++ testDisable(); ++ break; ++ case ENABLE: ++ testEnable(); ++ break; ++ case SPECIFY: ++ testSpecify(); ++ break; ++ default: ++ throw new IllegalArgumentException("invalid mode"); ++ } ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/KAETestHelper.java b/jdk/test/org/openeuler/security/openssl/KAETestHelper.java +new file mode 100644 +index 000000000..31e22493a +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/KAETestHelper.java +@@ -0,0 +1,209 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import java.io.BufferedReader; ++import java.io.File; ++import java.io.FileReader; ++import java.io.IOException; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++ ++class KAETestHelper { ++ private static final String KAE_ENGINE_ID = "kae"; ++ private static final String UADK_ENGINE_ID = "uadk_engine"; ++ private static boolean hasKaeEngine; ++ private static boolean hasUadkEngine; ++ ++ private static String engineRootPath; ++ ++ // algorithm names ++ private static final String[] ALGORITHM_NAMES = new String[]{ ++ "md5", ++ "sha256", ++ "sha384", ++ "sm3", ++ "aes-128-ecb", ++ "aes-128-cbc", ++ "aes-128-ctr", ++ "aes-128-gcm", ++ "aes-192-ecb", ++ "aes-192-cbc", ++ "aes-192-ctr", ++ "aes-192-gcm", ++ "aes-256-ecb", ++ "aes-256-cbc", ++ "aes-256-ctr", ++ "aes-256-gcm", ++ "sm4-ecb", ++ "sm4-cbc", ++ "sm4-ctr", ++ "sm4-ofb", ++ "hmac-md5", ++ "hmac-sha1", ++ "hmac-sha224", ++ "hmac-sha256", ++ "hmac-sha384", ++ "hmac-sha512", ++ "rsa", ++ "dh", ++ "ec" ++ }; ++ private static final Map ALGORITHM_NAME_MAP = new HashMap<>(); ++ ++ private static final String PROVIDER_NAME = "KAEProvider"; ++ private static final String USE_OPENSSL_MSG = "Use openssl soft calculation"; ++ private static final String USE_KAE_HARDWARE_MSG = "enable KAE hardware acceleration"; ++ private static final Map ALGORITHM_MSG_MAP = new HashMap<>(); ++ ++ static { ++ init(); ++ } ++ ++ enum Engine { ++ default_engine(hasKaeEngine, KAE_ENGINE_ID), ++ kae(hasKaeEngine, KAE_ENGINE_ID), ++ uadk_engine(hasUadkEngine, UADK_ENGINE_ID); ++ private final boolean isValid; ++ private final String engineId; ++ ++ Engine(boolean isValid, String engineId) { ++ this.isValid = isValid; ++ this.engineId = engineId; ++ } ++ ++ public boolean isValid() { ++ return isValid; ++ } ++ ++ public String getEngineId() { ++ return engineId; ++ } ++ } ++ ++ private static void init() { ++ engineRootPath = System.getenv("OPENSSL_ENGINES"); ++ if (engineRootPath == null || engineRootPath.equals("")) { ++ System.out.println("Environment variable OPENSSL_ENGINES is not configured"); ++ } ++ hasKaeEngine = hasEngine(KAE_ENGINE_ID); ++ hasUadkEngine = hasEngine(UADK_ENGINE_ID); ++ ++ for (int i = 0; i < ALGORITHM_NAMES.length; i++) { ++ ALGORITHM_NAME_MAP.put(ALGORITHM_NAMES[i], i); ++ } ++ ++ ALGORITHM_MSG_MAP.put(USE_OPENSSL_MSG, false); ++ ALGORITHM_MSG_MAP.put(USE_KAE_HARDWARE_MSG, true); ++ } ++ ++ static Integer getAlgorithmIndex(String algorithmName) { ++ return ALGORITHM_NAME_MAP.get(algorithmName); ++ } ++ ++ static String getAlgorithmName(Integer algorithmIndex) { ++ return ALGORITHM_NAMES[algorithmIndex]; ++ } ++ ++ private static boolean hasEngine(String engineId) { ++ String filePath = engineRootPath + File.separator + engineId + ".so"; ++ File file = new File(filePath); ++ return file.exists(); ++ } ++ ++ static boolean hasKaeEngine() { ++ return hasKaeEngine; ++ } ++ ++ static boolean hasUadkEngine() { ++ return hasUadkEngine; ++ } ++ ++ static void cleanUp(List files) { ++ for (File file : files) { ++ System.out.println("delete file : " + file); ++ file.delete(); ++ } ++ } ++ ++ static boolean[] parseLog(Engine engine, File file) throws IOException { ++ boolean[] kaeUseEngineFlags; ++ String expectedEngineMsg = engine.getEngineId() + " engine was found"; ++ try (BufferedReader reader = new BufferedReader(new FileReader(file))) { ++ // load engine message ++ String engineMsg = reader.readLine(); ++ if (engineMsg == null || !engineMsg.contains(expectedEngineMsg)) { ++ throw new RuntimeException("test failed : actual message :" + engineMsg); ++ } ++ ++ // summary message ++ String summaryMessage = reader.readLine(); ++ if (summaryMessage == null) { ++ throw new RuntimeException("test failed : summary message is null"); ++ } ++ ++ kaeUseEngineFlags = new boolean[ALGORITHM_NAMES.length]; ++ // strategy of each algorithm ++ String strategy; ++ while ((strategy = reader.readLine()) != null) { ++ String[] splitArray = strategy.split("=>"); ++ if (splitArray.length < 2) { ++ throw new RuntimeException("test failed : strategy = " + strategy); ++ } ++ ++ // algorithm Index ++ String algorithm = splitArray[0].replace(" ", ""); ++ Integer algorithmIndex = ALGORITHM_NAME_MAP.get(algorithm); ++ if (algorithmIndex == null) { ++ throw new RuntimeException("test failed : illegal algorithm " + algorithm); ++ } ++ ++ // provider and algorithm value ++ String detail = splitArray[1]; ++ String[] detailArray = detail.split(":"); ++ if (detailArray.length < 2) { ++ throw new RuntimeException("test failed : detail=" + strategy); ++ } ++ String provider = detailArray[0].replace(" ", ""); ++ if (!PROVIDER_NAME.equals(provider)) { ++ throw new RuntimeException("test failed : provider= " + provider); ++ } ++ String algorithmMsg = detailArray[1].trim(); ++ Boolean algorithmValue = ALGORITHM_MSG_MAP.get(algorithmMsg); ++ if (algorithmValue == null) { ++ throw new RuntimeException("test failed : algorithmMsg= " + algorithmMsg); ++ } ++ kaeUseEngineFlags[algorithmIndex] = algorithmValue; ++ } ++ } ++ return kaeUseEngineFlags; ++ } ++ ++ static KAETestHelper.Engine getEngine() { ++ String engineId = System.getProperty("kae.engine.id"); ++ if (engineId == null) { ++ return KAETestHelper.Engine.default_engine; ++ } ++ return KAETestHelper.Engine.valueOf(engineId); ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/KAEUseEngineTest.java b/jdk/test/org/openeuler/security/openssl/KAEUseEngineTest.java +new file mode 100644 +index 000000000..4e57f775e +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/KAEUseEngineTest.java +@@ -0,0 +1,262 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.File; ++import java.io.IOException; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++ ++/* ++ * @test ++ * @summary Test KAE property kae..useKaeEngine ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Dkae.log=true -Dall.test=default KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.digest.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=enable -Dkae.digest.useKaeEngine=true -Dkae.aes.useKaeEngine=true -Dkae.sm4.useKaeEngine=true -Dkae.hmac.useKaeEngine=true -Dkae.rsa.useKaeEngine=true -Dkae.dh.useKaeEngine=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.digest.useKaeEngine=false KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=disable -Dkae.digest.useKaeEngine=false -Dkae.aes.useKaeEngine=false -Dkae.sm4.useKaeEngine=false -Dkae.hmac.useKaeEngine=false -Dkae.rsa.useKaeEngine=false -Dkae.dh.useKaeEngine=false -Dkae.ec.useKaeEngine=false KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=default -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=enable -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=true -Dkae.aes.useKaeEngine=true -Dkae.sm4.useKaeEngine=true -Dkae.hmac.useKaeEngine=true -Dkae.rsa.useKaeEngine=true -Dkae.dh.useKaeEngine=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=false KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=disable -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=false -Dkae.aes.useKaeEngine=false -Dkae.sm4.useKaeEngine=false -Dkae.hmac.useKaeEngine=false -Dkae.rsa.useKaeEngine=false -Dkae.dh.useKaeEngine=false -Dkae.ec.useKaeEngine=false KAEUseEngineTest ++ */ ++public class KAEUseEngineTest { ++ enum Mode { ++ DEFAULT(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }), ++ DIGEST_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 0, true), ++ AES_ENABLE(new boolean[]{ ++ true, false, false, true, true, true, true, true, true, true, ++ true, true, true, true, true, true, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 1, true), ++ SM4_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 2, true), ++ HMAC_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ true, true, true, true, true, true, true, true, false ++ }, 3, true), ++ RSA_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 4, true), ++ DH_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 5, true), ++ EC_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 6, true), ++ ALL_ENABLE(new boolean[]{ ++ true, false, false, true, true, true, true, true, true, true, ++ true, true, true, true, true, true, true, true, true, true, ++ true, true, true, true, true, true, true, true, false ++ }, true), ++ DIGEST_DISABLE(new boolean[]{ ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 0, false), ++ AES_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 1, false), ++ SM4_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, false ++ }, 2, false), ++ HMAC_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 3, false), ++ RSA_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, false, true, false ++ }, 4, false), ++ DH_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, false, false ++ }, 5, false), ++ EC_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 6, false), ++ ALL_DISABLE(new boolean[]{ ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, false, false, false ++ }, false); ++ private final boolean[] expectedResult; ++ private final Integer propertyNameIndex; ++ private final boolean enable; ++ private static final Map modeMap = new HashMap<>(); ++ ++ static { ++ Mode[] modes = Mode.values(); ++ for (Mode mode : modes) { ++ if (mode.propertyNameIndex != null) { ++ modeMap.put(PROPERTY_NAMES[mode.propertyNameIndex] + ":" + mode.enable, mode); ++ } ++ } ++ modeMap.put("default", DEFAULT); ++ modeMap.put("disable", ALL_DISABLE); ++ modeMap.put("enable", ALL_ENABLE); ++ } ++ ++ Mode(boolean[] expectedResult) { ++ this(expectedResult, false); ++ } ++ ++ Mode(boolean[] expectedResult, boolean enable) { ++ this(expectedResult, null, enable); ++ } ++ ++ Mode(boolean[] expectedResult, Integer propertyNameIndex, boolean enable) { ++ this.expectedResult = expectedResult; ++ this.propertyNameIndex = propertyNameIndex; ++ this.enable = enable; ++ } ++ ++ static Mode getMode(String name, Boolean enable) { ++ return modeMap.get(name + ":" + enable); ++ } ++ ++ static Mode getMode(String key) { ++ return modeMap.get(key); ++ } ++ } ++ ++ private static final String KAE_LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "kae.log"; ++ ++ private static final String[] PROPERTY_NAMES = new String[]{ ++ "kae.digest.useKaeEngine", ++ "kae.aes.useKaeEngine", ++ "kae.sm4.useKaeEngine", ++ "kae.hmac.useKaeEngine", ++ "kae.rsa.useKaeEngine", ++ "kae.dh.useKaeEngine", ++ "kae.ec.useKaeEngine" ++ }; ++ ++ private static final List files = new ArrayList<>(); ++ ++ public static void main(String[] args) throws IOException { ++ KAETestHelper.Engine engine = KAETestHelper.getEngine(); ++ if (!engine.isValid()) { ++ System.out.println("Skip test, engine " + engine.getEngineId() + " does not exist."); ++ return; ++ } ++ Mode mode = getMode(); ++ if (mode == null) { ++ throw new RuntimeException("test failed: mode is null"); ++ } ++ ++ try { ++ new KAEProvider(); ++ test(mode, engine); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static Mode getMode() { ++ String value = System.getProperty("all.test"); ++ if (value != null) { ++ return Mode.getMode(value); ++ } ++ for (String propertyName : PROPERTY_NAMES) { ++ String property = System.getProperty(propertyName); ++ Boolean enable = null; ++ if (property != null) { ++ enable = Boolean.valueOf(property); ++ } ++ Mode mode = Mode.getMode(propertyName, enable); ++ if (mode != null) { ++ return mode; ++ } ++ } ++ return null; ++ } ++ ++ private static void test(Mode mode, KAETestHelper.Engine engine) throws IOException { ++ File file = new File(KAE_LOG_PATH); ++ files.add(file); ++ boolean[] kaeUseEngineFlags = KAETestHelper.parseLog(engine, file); ++ if (!Arrays.equals(mode.expectedResult, kaeUseEngineFlags)) { ++ throw new RuntimeException("test failed : expected : " + Arrays.toString(mode.expectedResult) + "," + ++ "actual:" + Arrays.toString(kaeUseEngineFlags)); ++ } ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/KaeDebugLogTest.java b/jdk/test/org/openeuler/security/openssl/KaeDebugLogTest.java +new file mode 100644 +index 000000000..bcce9cb8b +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/KaeDebugLogTest.java +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import javax.crypto.Cipher; ++import javax.crypto.spec.SecretKeySpec; ++import java.io.PrintStream; ++import java.nio.charset.StandardCharsets; ++import java.nio.file.Files; ++import java.nio.file.Paths; ++import java.security.Security; ++import java.util.Objects; ++import java.util.stream.Collectors; ++import java.util.stream.Stream; ++ ++/** ++ * @test ++ * @summary test for KaeDebugLogTest ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Djava.security.debug=kae -Dkae.sm4.maxChunkSize=65536 KaeDebugLogTest ++ * @run main/othervm -Djava.security.debug=kae KaeDebugLogTest ++ * @run main/othervm -Djava.security.auth.debug=kae KaeDebugLogTest ++ * @run main/othervm KaeDebugLogTest ++ */ ++ ++public class KaeDebugLogTest { ++ ++ private static final PrintStream err = System.err; ++ ++ public static void main(String[] args) throws Exception { ++ PrintStream printStream = new PrintStream("kaetest.out"); ++ System.setErr(printStream); ++ testDebugLog(); ++ System.setErr(printStream); ++ testSm4ChunkSize(); ++ } ++ ++ public static void testDebugLog() throws Exception { ++ new KAEProvider(); ++ Stream lines = Files.lines(Paths.get("kaetest.out")); ++ System.setErr(err); ++ String content = lines.collect(Collectors.joining(System.lineSeparator())); ++ if(("kae".equals(System.getProperty("java.security.debug")) ++ || "kae".equals(System.getProperty("java.security..auth.debug"))) ++ && !content.contains("reading kae properties file:")){ ++ throw new RuntimeException("KaeDebugLogTest Failed! Failed to set the debug log."); ++ } ++ lines.close(); ++ } ++ ++ public static void testSm4ChunkSize() throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ Cipher cipher = Cipher.getInstance("SM4"); ++ cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("sm4EncryptionKey".getBytes(StandardCharsets.UTF_8), "SM4")); ++ Stream lines = Files.lines(Paths.get("kaetest.out")); ++ System.setErr(err); ++ String content = lines.collect(Collectors.joining(System.lineSeparator())); ++ String log = "The configured chunk size is " + System.getProperty("kae.sm4.maxChunkSize"); ++ if(("kae".equals(System.getProperty("java.security.debug")) ++ || "kae".equals(System.getProperty("java.security..auth.debug"))) ++ && Objects.nonNull(System.getProperty("kae.sm4.maxChunkSize")) &&!content.contains(log)){ ++ throw new RuntimeException("KaeDebugLogTest Failed! Failed to set the kae.sm4.maxChunkSize = " + System.getProperty("kae.sm4.maxChunkSize")); ++ } ++ lines.close(); ++ } ++ ++} +diff --git a/jdk/test/org/openeuler/security/openssl/KaeProviderTest.java b/jdk/test/org/openeuler/security/openssl/KaeProviderTest.java +new file mode 100644 +index 000000000..d8587891b +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/KaeProviderTest.java +@@ -0,0 +1,170 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import javax.crypto.Cipher; ++import javax.crypto.Mac; ++import javax.crypto.NoSuchPaddingException; ++import java.security.KeyPairGenerator; ++import java.security.MessageDigest; ++import java.security.NoSuchAlgorithmException; ++import java.security.Security; ++ ++/** ++ * @test ++ * @requires os.arch=="aarch64" ++ * @summary test for KaeProviderTest ++ * @run main/othervm KaeProviderTest ++ * @run main/othervm KaeProviderTest true ++ * @run main/othervm KaeProviderTest false ++ * @run main/othervm KaeProviderTest wrong ++ */ ++ ++public class KaeProviderTest { ++ ++ private static final String[] algorithmKaeProviderPropertyNames = new String[]{ ++ "kae.md5", ++ "kae.sha256", ++ "kae.sha384", ++ "kae.sm3", ++ "kae.aes", ++ "kae.sm4", ++ "kae.hmac", ++ "kae.rsa", ++ "kae.dh", ++ "kae.ec" ++ }; ++ ++ private static final String KAE = "KAEProvider"; ++ ++ public static void main(String[] args) throws Exception { ++ initProperty(args); ++ Security.insertProviderAt(new KAEProvider(), 1); ++ testALL(); ++ } ++ ++ private static void initProperty(String[] args) { ++ if (args.length <= 0) { ++ return; ++ } ++ String value = args[0]; ++ for (String name : algorithmKaeProviderPropertyNames){ ++ System.setProperty(name,value); ++ } ++ } ++ ++ public static void testALL() throws Exception { ++ testMd5(); ++ testSha256(); ++ testSha384(); ++ testSm3(); ++ testAes(); ++ testSm4(); ++ testHmac(); ++ testRsa(); ++ testDh(); ++ testEc(); ++ } ++ ++ public static void testMd5() throws NoSuchAlgorithmException { ++ MessageDigest messageDigest = MessageDigest.getInstance("MD5"); ++ judge("kae.md5",messageDigest.getProvider().getName()); ++ ++ } ++ ++ public static void testSha256() throws NoSuchAlgorithmException { ++ MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); ++ judge("kae.sha256",messageDigest.getProvider().getName()); ++ } ++ ++ public static void testSha384() throws NoSuchAlgorithmException { ++ MessageDigest messageDigest = MessageDigest.getInstance("SHA-384"); ++ judge("kae.sha384",messageDigest.getProvider().getName()); ++ } ++ ++ public static void testSm3() throws NoSuchAlgorithmException { ++ try{ ++ MessageDigest messageDigest = MessageDigest.getInstance("SM3"); ++ judge("kae.sm3",messageDigest.getProvider().getName()); ++ }catch (NoSuchAlgorithmException e){ ++ if(Boolean.parseBoolean(System.getProperty("kae.sm3"))){ ++ throw e; ++ } ++ } ++ } ++ ++ public static void testAes() throws NoSuchAlgorithmException, NoSuchPaddingException { ++ Cipher cipher = Cipher.getInstance("AES"); ++ judge("kae.aes",cipher.getProvider().getName()); ++ } ++ ++ public static void testSm4() throws NoSuchAlgorithmException, NoSuchPaddingException { ++ try{ ++ Cipher cipher = Cipher.getInstance("SM4"); ++ judge("kae.sm4",cipher.getProvider().getName()); ++ }catch (NoSuchAlgorithmException e){ ++ if(Boolean.parseBoolean(System.getProperty("kae.sm4"))){ ++ throw e; ++ } ++ } ++ } ++ ++ public static void testHmac() throws NoSuchAlgorithmException { ++ Mac mac = Mac.getInstance("HmacMD5"); ++ judge("kae.hmac",mac.getProvider().getName()); ++ } ++ ++ public static void testRsa() throws NoSuchAlgorithmException, NoSuchPaddingException { ++ Cipher cipher = Cipher.getInstance("RSA"); ++ judge("kae.rsa",cipher.getProvider().getName()); ++ } ++ ++ public static void testDh() throws NoSuchAlgorithmException { ++ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH"); ++ judge("kae.dh",keyPairGenerator.getProvider().getName()); ++ } ++ ++ public static void testEc() throws NoSuchAlgorithmException { ++ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); ++ judge("kae.ec",keyPairGenerator.getProvider().getName()); ++ } ++ ++ private static void judge(String algorithm , String providerName){ ++ String value = System.getProperty(algorithm); ++ if (value == null) { ++ if (!KAE.equals(providerName)) { ++ throw new RuntimeException("KaeProviderTest Failed! default Provider.name is not right!"); ++ } ++ } else { ++ if (Boolean.parseBoolean(value) && !KAE.equals(providerName)) { ++ throw new RuntimeException("KaeProviderTest Failed! " + algorithm + " is " + value + "," + ++ " Provider.name is not right!"); ++ } ++ if (!Boolean.parseBoolean(value) && KAE.equals(providerName)) { ++ throw new RuntimeException("KaeProviderTest Failed! " + algorithm + " is " + value + ", " + ++ " Provider.name is not right!"); ++ } ++ } ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/RSATest.java b/jdk/test/org/openeuler/security/openssl/RSATest.java +new file mode 100644 +index 000000000..1f740af0b +--- /dev/null ++++ b/jdk/test/org/openeuler/security/openssl/RSATest.java +@@ -0,0 +1,137 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.nio.charset.StandardCharsets; ++import java.security.*; ++import java.security.spec.*; ++import javax.crypto.Cipher; ++ ++/** ++ * @test ++ * @summary Basic test for RSA ++ * @run main RSATest ++ */ ++ ++public class RSATest { ++ private static final String algorithm = "RSA"; ++ private static KeyPairGenerator keyPairGenerator; ++ private static byte[] privateKey; ++ private static byte[] publicKey; ++ private static String plainText = "helloworld"; ++ // 512, 768, ++ private static int[] keySizes = {1024, 2048, 4096, 5120, 6144}; ++ private static String[] signAlgorithms = { ++ "MD2withRSA", "MD5withRSA", "SHA1withRSA", "SHA224withRSA", "SHA256withRSA", "SHA384withRSA", "SHA512withRSA" ++ }; ++ private static String[] signAlgorithmsPSS = {"SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"}; ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ ++ for (int keySize : keySizes) { ++ testKeyPairByKeySize(keySize); ++ testRSACipher(keySize); ++ testSignature(); ++ testPSSSignature(keySize); ++ } ++ } ++ ++ public static void testKeyPairByKeySize(int keySize) throws Exception { ++ keyPairGenerator = KeyPairGenerator.getInstance(algorithm); ++ keyPairGenerator.initialize(keySize); ++ KeyPair keyPair = keyPairGenerator.generateKeyPair(); ++ ++ PrivateKey pairPrivate = keyPair.getPrivate(); ++ PublicKey pairPublic = keyPair.getPublic(); ++ ++ privateKey = pairPrivate.getEncoded(); ++ publicKey = pairPublic.getEncoded(); ++ } ++ ++ public static void testRSACipher(int keySize) throws Exception { ++ PublicKey pubKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKey)); ++ Cipher cipher = Cipher.getInstance("RSA"); ++ cipher.init(Cipher.ENCRYPT_MODE, pubKey); ++ ++ byte[] cipherText = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); ++ ++ PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKey)); ++ ++ cipher.init(Cipher.DECRYPT_MODE, priKey); ++ ++ String decryptText = new String(cipher.doFinal(cipherText)); ++ ++ if (!plainText.equals(decryptText)) { ++ throw new RuntimeException("rsa decryption failed. keySize = " + keySize); ++ } ++ } ++ ++ public static void testSignature() throws Exception { ++ PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKey)); ++ PublicKey pubKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKey)); ++ ++ for (String algorithm : signAlgorithms) { ++ Signature sign = Signature.getInstance(algorithm); ++ sign.initSign(priKey); ++ sign.update(plainText.getBytes()); ++ byte[] signInfo = sign.sign(); ++ ++ sign.initVerify(pubKey); ++ sign.update(plainText.getBytes()); ++ if (!sign.verify(signInfo)) { ++ throw new RuntimeException("rsa testSignature failed. digest algorithm = " + algorithm); ++ } ++ } ++ } ++ ++ public static void testPSSSignature(int keySize) throws Exception { ++ PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKey)); ++ PublicKey pubKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKey)); ++ ++ Signature sign = Signature.getInstance("RSASSA-PSS"); ++ ++ for (String algorithm : signAlgorithmsPSS) { ++ if (algorithm.equals(signAlgorithmsPSS[4]) && keySize <= 1024) { ++ continue; ++ } ++ sign.initSign(priKey); ++ ++ MessageDigest digest = MessageDigest.getInstance(algorithm); ++ byte[] digestByte = digest.digest(plainText.getBytes()); ++ sign.setParameter( ++ new PSSParameterSpec(algorithm, "MGF1", new MGF1ParameterSpec(algorithm), digestByte.length, 1)); ++ ++ sign.update(plainText.getBytes()); ++ byte[] signInfo = sign.sign(); ++ ++ sign.initVerify(pubKey); ++ ++ sign.update(plainText.getBytes()); ++ if (!sign.verify(signInfo)) { ++ throw new RuntimeException("rsa testPSSSignature failed. digest algorithm = " + algorithm); ++ } ++ } ++ } ++} +diff --git a/jdk/test/org/openeuler/security/openssl/SM3Test.java b/jdk/test/org/openeuler/security/openssl/SM3Test.java +deleted file mode 100644 +index 181f708ff..000000000 +--- a/jdk/test/org/openeuler/security/openssl/SM3Test.java ++++ /dev/null +@@ -1,54 +0,0 @@ +-/* +- * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. +- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +- * +- * This code is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 only, as +- * published by the Free Software Foundation. +- * +- * This code is distributed in the hope that it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +- * version 2 for more details (a copy is included in the LICENSE file that +- * accompanied this code). +- * +- * You should have received a copy of the GNU General Public License version +- * 2 along with this work; if not, write to the Free Software Foundation, +- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +- * or visit www.oracle.com if you need additional information or have any +- * questions. +- */ +- +-import org.openeuler.security.openssl.KAEProvider; +-import java.nio.charset.StandardCharsets; +-import java.util.Arrays; +-import java.security.MessageDigest; +-import java.security.Security; +- +-/** +- * @test +- * @summary Basic test for sm3 +- * @run main SM3Test +- */ +- +-public class SM3Test { +- +- private static String plainText = "helloworldhellow"; +- +- public static void main(String[] args) throws Exception { +- Security.insertProviderAt(new KAEProvider(), 1); +- test(plainText, "SM3", new byte[]{40, -103, -71, 4, -80, -49, 94, 112, 11, -75, -66, 121, 63, 80, 62, -14, -45, -75, -34, 66, -77, -34, -26, 26, 33, -23, 45, 52, -74, 67, -18, 118}); +- } +- +- public static void test(String plainText, String algo, byte[] expectRes) throws Exception { +- MessageDigest md = MessageDigest.getInstance(algo); +- md.update(plainText.getBytes(StandardCharsets.UTF_8)); +- byte[] res = md.digest(); +- if (!Arrays.equals(res, expectRes)) { +- throw new RuntimeException("sm3 failed"); +- } +- } +- +-} +diff --git a/jdk/test/org/openeuler/security/openssl/SM4Test.java b/jdk/test/org/openeuler/security/openssl/SM4Test.java +index 4c28dc5b6..1029fe897 100644 +--- a/jdk/test/org/openeuler/security/openssl/SM4Test.java ++++ b/jdk/test/org/openeuler/security/openssl/SM4Test.java +@@ -22,9 +22,10 @@ + */ + + import org.openeuler.security.openssl.KAEProvider; ++ ++import java.nio.ByteBuffer; + import java.nio.charset.StandardCharsets; + import java.util.Arrays; +-import java.security.NoSuchAlgorithmException; + import java.security.Security; + import javax.crypto.Cipher; + import javax.crypto.spec.IvParameterSpec; +@@ -55,6 +56,25 @@ public class SM4Test { + test(shortPlainText, "SM4/OFB/PKCS5Padding", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110}); + + testCtrShortIv(plainText, "SM4/CTR/NOPADDING", new byte[]{-13, 73, 40, -36, -64, -67, 75, -72, 90, 58, 73, -4, -36, 115, 126, -48}); ++ ++ testByteBuffer(plainText, "SM4/CBC/NOPADDING", new byte[]{86, 69, 47, -115, -63, 54, 35, 24, -2, 114, 113, 102, 82, 20, 69, 59}); ++ testByteBuffer(shortPlainText, "SM4/CBC/PKCS5Padding", new byte[]{10, 105, 75, -80, -85, -68, 13, -53, 42, 91, -64, 99, 104, 35, -85, 8}); ++ testByteBuffer(plainText, "SM4/ECB/NOPADDING", new byte[]{103, 36, -31, -53, -109, -12, -71, -79, -54, 106, 10, -3, -35, -22, -122, -67}); ++ testByteBuffer(shortPlainText, "SM4/ECB/PKCS5Padding", new byte[]{-10, 99, -9, 90, 58, -36, -109, 54, -55, -52, 7, -49, 110, -88, 72, 40}); ++ testByteBuffer(plainText, "SM4/CTR/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(plainText, "SM4/OFB/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(shortPlainText, "SM4/OFB/PKCS5Padding", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110}); ++ ++ System.setProperty("kae.sm4.maxChunkSize", "65536"); ++ testByteBuffer(plainText, "SM4/CBC/NOPADDING", new byte[]{86, 69, 47, -115, -63, 54, 35, 24, -2, 114, 113, 102, 82, 20, 69, 59}); ++ testByteBuffer(shortPlainText, "SM4/CBC/PKCS5Padding", new byte[]{10, 105, 75, -80, -85, -68, 13, -53, 42, 91, -64, 99, 104, 35, -85, 8}); ++ testByteBuffer(plainText, "SM4/ECB/NOPADDING", new byte[]{103, 36, -31, -53, -109, -12, -71, -79, -54, 106, 10, -3, -35, -22, -122, -67}); ++ testByteBuffer(shortPlainText, "SM4/ECB/PKCS5Padding", new byte[]{-10, 99, -9, 90, 58, -36, -109, 54, -55, -52, 7, -49, 110, -88, 72, 40}); ++ testByteBuffer(plainText, "SM4/CTR/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(plainText, "SM4/OFB/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(shortPlainText, "SM4/OFB/PKCS5Padding", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110}); ++ ++ + } + + public static void test(String plainText, String algo, byte[] expectRes) throws Exception { +@@ -92,4 +112,44 @@ public class SM4Test { + throw new RuntimeException("sm4 decryption failed, algo = " + algo); + } + } ++ ++ public static void testByteBuffer(String plainText, String algo, byte[] expectRes) throws Exception { ++ // encrypt ++ Cipher encryptCipher = Cipher.getInstance(algo); ++ if (algo.contains("ECB")) { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks); ++ } else { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, iv); ++ } ++ int inputLen = plainText.length(); ++ ByteBuffer sourceByteBuffer = ByteBuffer.allocateDirect(inputLen); ++ sourceByteBuffer.put(plainText.getBytes()); ++ sourceByteBuffer.flip(); ++ int outputLen = encryptCipher.getOutputSize(inputLen); ++ ByteBuffer encryptedByteBuffer = ByteBuffer.allocate(outputLen); ++ encryptCipher.doFinal(sourceByteBuffer,encryptedByteBuffer); ++ encryptedByteBuffer.flip(); ++ byte[] encryptedBytes = new byte[encryptedByteBuffer.limit()]; ++ encryptedByteBuffer.get(encryptedBytes); ++ if (!Arrays.equals(encryptedBytes, expectRes)) { ++ throw new RuntimeException("sm4 encryption failed, algo = " + algo); ++ } ++ sourceByteBuffer.clear(); ++ encryptedByteBuffer.flip(); ++ ++ // decrypt ++ Cipher decryptCipher = Cipher.getInstance(algo); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ outputLen = decryptCipher.getOutputSize(encryptedBytes.length); ++ ByteBuffer decryptedByteBuffer = ByteBuffer.allocate(outputLen); ++ decryptCipher.doFinal(encryptedByteBuffer, decryptedByteBuffer); ++ decryptedByteBuffer.flip(); ++ byte[] decryptedBytes = new byte[decryptedByteBuffer.limit()]; ++ decryptedByteBuffer.get(decryptedBytes); ++ if (!Arrays.equals(plainText.getBytes(), decryptedBytes)) { ++ throw new RuntimeException("sm4 decryption failed, algo = " + algo); ++ } ++ encryptedByteBuffer.clear(); ++ decryptedByteBuffer.clear(); ++ } + } +-- +2.17.1 + diff --git a/modify_coding_style_and_describe_error.patch b/modify_coding_style_and_describe_error.patch new file mode 100644 index 0000000000000000000000000000000000000000..9464ab21dde76df0e439597cd55f1c8f7caa22cf --- /dev/null +++ b/modify_coding_style_and_describe_error.patch @@ -0,0 +1,56 @@ +From 9d32c786ff6886bcd4b76e0a80eb19ce602dbe42 Mon Sep 17 00:00:00 2001 +From: wangkun +Date: Thu, 28 Jul 2022 17:24:52 +0800 +Subject: [PATCH 3/3] fix xx + +--- + .../classes/org/openeuler/security/openssl/KAEDigest.java | 6 +++--- + .../classes/org/openeuler/security/openssl/KAEProvider.java | 2 -- + jdk/src/solaris/native/java/io/path_util.c | 1 - + 3 files changed, 3 insertions(+), 6 deletions(-) + +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java +index bb5c8681..6ff03241 100644 +--- a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java +@@ -88,9 +88,9 @@ abstract class KAEDigest extends MessageDigestSpi implements Cloneable { + private static class DigestContextRef extends PhantomReference + implements Comparable { + +- private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); +- private static Set referenceList = new ConcurrentSkipListSet<>(); +- private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); ++ private static final ReferenceQueue referenceQueue = new ReferenceQueue<>(); ++ private static final Set referenceList = new ConcurrentSkipListSet<>(); ++ private static final boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); + + private final long ctxAddress; + +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java +index 8ba70200..83ed8649 100644 +--- a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java +@@ -104,8 +104,6 @@ public class KAEProvider extends Provider { + if (needLog && "true".equalsIgnoreCase(props.getProperty("kae.log"))) { + logStart(excp); + needLog = false; // Log only once +- } else { +- KAEProvider.excp = null; // Ignore exception. + } + if (!"false".equalsIgnoreCase(props.getProperty("kae.md5"))) { + putMD5(); +diff --git a/jdk/src/solaris/native/java/io/path_util.c b/jdk/src/solaris/native/java/io/path_util.c +index 8a533f81..4b978206 100644 +--- a/jdk/src/solaris/native/java/io/path_util.c ++++ b/jdk/src/solaris/native/java/io/path_util.c +@@ -116,7 +116,6 @@ collapse(char *path) + int nc; + char **ix; + int i, j; +- char *p, *q; + + nc = collapsible(names); + if (nc < 2) return; /* Nothing to do */ +-- +2.22.0 + diff --git a/openjdk-1.8.0.spec b/openjdk-1.8.0.spec index 6571b1a8bf966fa415faea07576e142d0d23b6eb..8bf06da039f353d141bd27d727e49b4f6baf86bd 100644 --- a/openjdk-1.8.0.spec +++ b/openjdk-1.8.0.spec @@ -146,13 +146,13 @@ %global origin_nice OpenJDK %global top_level_dir_name %{origin} %global repo jdk8u -%global revision jdk8u322-b06 +%global revision jdk8u352-b08 %global full_revision %{repo}-%{revision} # Define IcedTea version used for SystemTap tapsets and desktop files %global icedteaver 3.15.0 -%global updatever 322 -%global buildver b06 +%global updatever 352 +%global buildver b08 # priority must be 7 digits in total. The expression is workarounding tip %global priority 1800%{updatever} @@ -583,7 +583,7 @@ exit 0 %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libnpt.so %ifarch %{aarch64} %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libj2kae.so -%{_jvmdir}/%{jredir -- %{?1}}/lib/ext/kaeprovider.conf +%{_jvmdir}/%{jredir -- %{?1}}/lib/kaeprovider.conf %endif %ifarch %{sa_arches} %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libsaproc.so @@ -820,7 +820,7 @@ Requires: nss-softokn%{?_isa} %{NSSSOFTOKN_BUILDTIME_VERSION} # tool to copy jdk's configs - should be Recommends only, but then only dnf/yum enforce it, # not rpm transaction and so no configs are persisted when pure rpm -u is run. It may be # considered as regression -Requires: copy-jdk-configs >= 3.3 +Requires: copy-jdk-configs >= 3.9 OrderWithRequires: copy-jdk-configs # for printing support Requires: cups-libs @@ -916,7 +916,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 4 +Release: 3 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -993,7 +993,6 @@ Patch58: Reduce-the-probability-of-the-crash-related-to-ciObj.patch Patch62: 8165857.patch Patch63: 8033552.patch Patch67: 8165860.patch -Patch68: 8194154.patch Patch70: 8164948.patch # 8u242 @@ -1030,8 +1029,6 @@ Patch115: 8243670.patch Patch118: Fix-LineBuffer-vappend-when-buffer-too-small.patch Patch121: Remove-unused-GenericTaskQueueSet-T-F-tasks.patch Patch122: optimize-jmap-F-dump-xxx.patch -Patch123: recreate-.java_pid-file-when-deleted-for-attach-mechanism.patch -Patch124: Support-Git-commit-ID-in-the-SOURCE-field-of-the-release.patch Patch125: Extend-CDS-to-support-app-class-metadata-sharing.patch Patch127: add-DumpSharedSpace-guarantee-when-create-anonymous-classes.patch @@ -1046,7 +1043,6 @@ Patch142: 8207160.patch Patch144: add-appcds-test-case.patch # 8u282 -Patch146: 8168926.patch Patch147: 8215047.patch Patch148: 8237894.patch Patch149: Remove-the-parentheses-around-company-name.patch @@ -1077,15 +1073,12 @@ Patch177: downgrade-symver-of-memcpy-GLIBC.patch Patch178: fix-log-bug-enhance-aes-hmac-performance.patch Patch179: keep-the-binary-equal.patch Patch180: link-option-use-rpath-instead-of-runpath.patch -Patch181: remove-gnu-debuglink-when-using-enable-debug-.patch Patch183: revert-windows-bugfix.patch Patch184: set-vm.vendor-by-configure.patch Patch185: update-cacerts-and-VerifyCACerts.java-test.patch Patch186: update-to-keep-same-with-master.patch Patch188: 8247691_incorrect_handling_of_VM_exceptions_in_C1_deopt_stub.patch -Patch189: 8266187_Memory_leak_in_appendBootClassPath.patch Patch192: add_kae_implementation_add_default_conf_file.patch -Patch193: improve_algorithmConstraints_checkAlgorithm_performance.patch Patch194: modify_the_default_iteration_time_and_forks_in_the_JMH_of_KAEProvider.patch Patch195: support_CMS_parallel_inspection.patch Patch196: g1gc-numa-aware-Implementation.patch @@ -1099,17 +1092,14 @@ Patch202: Fix-RSACipher-memory-usage.patch Patch203: fix-lock-ordering-issue-when-calling-JVMTI-GetLoaded.patch Patch204: 8069191.patch Patch205: fix_g1uncommit_ygc_expand_crash.patch -Patch206: 8167014-jdeps-failed-with-Missing-message-warn-skippen-entry.patch Patch207: fix_bug_in_keypairgenerator.patch Patch208: C1-assert-is_virtual-failed-type-check.patch Patch209: 8197387-Run-the-jcmd-tool-as-the-root-user-to-access.patch Patch210: create-jfr-dump-file-with-pid-or-timestamp-if-specif.patch Patch212: enhance-the-TimeZone-s-path-solution-on-Euler.patch -Patch213: fix-wrong-commitID-in-release-file.patch Patch214: fix-appcds-s-option-AppCDSLockFile.patch Patch215: PS-introduce-UsePSRelaxedForwardee-to-enable-using-r.patch Patch216: Parallel-Full-GC-for-G1.patch -Patch217: 8202142-jfr-event-io-TestInstrumentation-is-unstable.patch Patch218: 8143251-Thread-suspend-on-VM_G1IncCollectionPause-do.patch Patch219: G1Uncommit-Introduce-G1PeriodGCNotRetry-control-whet.patch Patch220: JDK-debug-version-crash-when-using-AppCDS.patch @@ -1125,8 +1115,6 @@ Patch229: downgrade-the-symver-of-fcntl64.patch # 8u322 Patch230: add-system-property-swing.JComboBox.useLegacyMode.patch -Patch231: debuginfo.diz-should-not-contain-the-path-after-unzip.patch -Patch232: 8173361-various-crashes-in-JvmtiExport-post_compiled.patch Patch233: fix-TestUseCompressedOopsErgo-run-failed.patch Patch235: fix-testme-Test6929067-run-faild.patch Patch236: penetration_testing_vulnerability_fix.patch @@ -1136,6 +1124,35 @@ Patch239: print-fd-and-file-path-when-a-zip-invalid-loc-header.patch Patch240: 8207011-Remove-uses-of-the-register-storage-class-specifier.patch Patch241: 8268819-SA-Remove-libthread_db-dependency-on-Linux.patch +# 8u332 +Patch243: Fix-compile-and-runtime-failures-for-minimal1-versio.patch +Patch244: fix_X509TrustManagerImpl_symantec_distrust.patch +Patch245: change-sa-jdi.jar-make-file-for-BEP.PATCH +Patch246: 7092821-java.security.Provider.getService-is-synchro.patch +Patch248: 8067941-TESTBUG-Fix-tests-for-OS-with-64K-page-size.patch + +# 8u342 +Patch249: Improve_AlgorithmConstraints_checkAlgorithm_performance.patch +Patch250: modify_coding_style_and_describe_error.patch +Patch251: fix_wrap_memcpy_undefined_gcc10_3.patch +Patch252: 8290705_fix_StringConcat_validate_mem_flow_asserts_with_unexpected_userStoreI.patch +Patch253: 8143925-enhancing-CounterMode.crypt-for-AESCrypt.patch +Patch254: kae-usability-enhancement.patch +Patch255: Dynamic-CDS-Archive.patch +Patch256: 8202951-Support-default-jsa.patch +Patch257: 8200332-Improve-GCM-counting.patch +Patch258: dynamic-cds-_header-and-_fd-handles-are-not-free.patch +Patch259: fix-dumped-heap-using-jhat-parsing-to-appear-failed-to-resolve-object-id-warning-message.patch +Patch260: 8159720-Failure-of-C2-compilation-with-tiered-preven.patch +Patch261: revert-fPIC-and-security-compilation-flag-on.patch +Patch262: add-configuration-option-of-huawei-internal-version-shown-in-release-file.patch +Patch263: The-code-style-is-fixed-and-test-cases-are-added.patch +Patch264: 8287109-Distrust-failed-with-CertificateExpired.patch + +# 8u352 +Patch265: cve-2022-37434-Fix-a-bug-when-getting-a-gzip-header-extra-field-with-inflate.patch +Patch266: 8065895-Synchronous-signals-during-error-reporting-may-terminate-or-hang-vm-process.patch + ############################################# # # Upstreamable patches @@ -1196,6 +1213,7 @@ BuildRequires: cups-devel BuildRequires: desktop-file-utils # elfutils only are OK for build without AOT BuildRequires: elfutils-devel +BuildRequires: elfutils-extra BuildRequires: fontconfig-devel BuildRequires: freetype-devel BuildRequires: giflib-devel @@ -1493,7 +1511,6 @@ pushd %{top_level_dir_name} %patch62 -p1 %patch63 -p1 %patch67 -p1 -%patch68 -p1 %patch70 -p1 %patch75 -p1 %patch83 -p1 @@ -1522,8 +1539,6 @@ pushd %{top_level_dir_name} %patch118 -p1 %patch121 -p1 %patch122 -p1 -%patch123 -p1 -%patch124 -p1 %patch125 -p1 %patch127 -p1 %patch133 -p1 @@ -1534,7 +1549,6 @@ pushd %{top_level_dir_name} %patch141 -p1 %patch142 -p1 %patch144 -p1 -%patch146 -p1 %patch147 -p1 %patch148 -p1 %patch149 -p1 @@ -1563,13 +1577,11 @@ pushd %{top_level_dir_name} %patch178 -p1 %patch179 -p1 %patch180 -p1 -%patch181 -p1 %patch183 -p1 %patch184 -p1 %patch185 -p1 %patch186 -p1 %patch188 -p1 -%patch189 -p1 %patch192 -p1 %patch194 -p1 %patch195 -p1 @@ -1582,17 +1594,14 @@ pushd %{top_level_dir_name} %patch203 -p1 %patch204 -p1 %patch205 -p1 -%patch206 -p1 %patch207 -p1 %patch208 -p1 %patch209 -p1 %patch210 -p1 %patch212 -p1 -%patch213 -p1 %patch214 -p1 %patch215 -p1 %patch216 -p1 -%patch217 -p1 %patch218 -p1 %patch219 -p1 %patch220 -p1 @@ -1604,8 +1613,6 @@ pushd %{top_level_dir_name} %patch228 -p1 %patch229 -p1 %patch230 -p1 -%patch231 -p1 -%patch232 -p1 %patch233 -p1 %patch235 -p1 %patch236 -p1 @@ -1614,6 +1621,29 @@ pushd %{top_level_dir_name} %patch239 -p1 %patch240 -p1 %patch241 -p1 +%patch243 -p1 +%patch244 -p1 +%patch245 -p1 +%patch246 -p1 +%patch248 -p1 +%patch249 -p1 +%patch250 -p1 +%patch251 -p1 +%patch252 -p1 +%patch253 -p1 +%patch254 -p1 +%patch255 -p1 +%patch256 -p1 +%patch257 -p1 +%patch258 -p1 +%patch259 -p1 +%patch260 -p1 +%patch261 -p1 +%patch262 -p1 +%patch263 -p1 +%patch264 -p1 +%patch265 -p1 +%patch266 -p1 popd # System library fixes @@ -2064,7 +2094,13 @@ done -- whether copy-jdk-configs is installed or not. If so, then configs are copied -- (copy_jdk_configs from %%{_libexecdir} used) or not copied at all local posix = require "posix" -local debug = false + +if (os.getenv("debug") == "true") then + debug = true; + print("cjc: in spec debug is on") +else + debug = false; +end SOURCE1 = "%{rpm_state_dir}/copy_jdk_configs.lua" SOURCE2 = "%{_libexecdir}/copy_jdk_configs.lua" @@ -2093,8 +2129,9 @@ else end end -- run content of included file with fake args +cjc = require "copy_jdk_configs.lua" arg = {"--currentjvm", "%{uniquesuffix %{nil}}", "--jvmdir", "%{_jvmdir %{nil}}", "--origname", "%{name}", "--origjavaver", "%{javaver}", "--arch", "%{_arch}", "--temp", "%{rpm_state_dir}/%{name}.%{_arch}"} -require "copy_jdk_configs.lua" +cjc.mainProgram(arg) %post %{post_script %{nil}} @@ -2231,10 +2268,125 @@ require "copy_jdk_configs.lua" %endif %changelog +* Mon Oct 24 2022 kuenking111 - 1:1.8.0.352-b08.3 +- add 8065895-Synchronous-signals-during-error-reporting-may-terminate-or-hang-vm-process.patch + +* Mon Oct 24 2022 kuenking111 - 1:1.8.0.352-b08.2 +- add cve-2022-37434-Fix-a-bug-when-getting-a-gzip-header-extra-field-with-inflate.patch + +* Mon Oct 24 2022 kuenking111 - 1:1.8.0.352-b08.1 +- remove gitattributes gitignore jcheck files + +* Wed Oct 19 2022 kuenking111 - 1:1.8.0.352-b08.0 +- modified add-missing-test-case.patch +- upgrade to jdk8u352-b08 + +* Thu Sep 29 2022 DXwangg - 1:1.8.0.352-b07.0 +- upgrade to jdk8u352-b07 +- deleted Improve_AlgorithmConstraints_checkAlgorithm_performance.patch +- deleted 8173361-various-crashes-in-JvmtiExport-post_compiled.patch +- modified Fix-compile-and-runtime-failures-for-minimal1-versio.patch +- deleted 8173339-AArch64-Fix-minimum-stack-size-computations.patch +- modified add-appcds-file-lock.patch +- modified add-DumpSharedSpace-guarantee-when-create-anonymous-classes.patch +- modified fix-appcds-s-option-AppCDSLockFile.patch +- modified fix-windows-compile-fail.patch + +* Sat Sep 24 2022 kuenking111 - 1:1.8.0.342-b07.15 +- add 8287109-Distrust-failed-with-CertificateExpired.patch + +* Fri Sep 23 2022 kuenking111 - 1:1.8.0.342-b07.14 +- add The-code-style-is-fixed-and-test-cases-are-added.patch + +* Thu Sep 22 2022 kuenking111 - 1:1.8.0.342-b07.13 +- add add-configuration-option-of-huawei-internal-version-shown-in-release-file.patch + +* Wed Sep 21 2022 kuenking111 - 1:1.8.0.342-b07.12 +- add revert-fPIC-and-security-compilation-flag-on.patch + +* Mon Sep 19 2022 zhoulei - 1:1.8.0.342-b07.11 +- add 8159720-Failure-of-C2-compilation-with-tiered-preven.patch + +* Fri Sep 16 2022 kuenking111 - 1:1.8.0.342-b07.10 +- add fix-dumped-heap-using-jhat-parsing-to-appear-failed-to-resolve-object-id-warning-message.patch + +* Fri Sep 16 2022 kuenking111 - 1:1.8.0.342-b07.9 +- add dynamic-cds-_header-and-_fd-handles-are-not-free.patch + +* Fri Sep 16 2022 kuenking111 - 1:1.8.0.342-b07.8 +- add 8200332-Improve-GCM-counting.patch + +* Fri Sep 16 2022 kuenking111 - 1:1.8.0.342-b07.7 +- add 8202951-Support-default-jsa.patch + +* Thu Sep 15 2022 kuenking111 - 1:1.8.0.342-b07.6 +- add Dynamic-CDS-Archive.patch + +* Thu Sep 15 2022 kuenking111 - 1:1.8.0.342-b07.5 +- add kae-usability-enhancement.patch + +* Thu Sep 15 2022 kuenking111 - 1:1.8.0.342-b07.4 +- add 8143925-enhancing-CounterMode.crypt-for-AESCrypt.patch + +* Fri Aug 5 2022 kuenking111 - 1:1.8.0.342-b07.3 +- add 8290705_fix_StringConcat_validate_mem_flow_asserts_with_unexpected_userStoreI.patch +- modified version.txt + +* Thu Jul 28 2022 kuenking111 - 1:1.8.0.342-b07.2 +- add modify_coding_style_and_describe_error.patch +- add Improve_AlgorithmConstraints_checkAlgorithm_performance.patch +- add fix_wrap_memcpy_undefined_gcc10_3.patch +- modified implementation_of_Blas_hotspot_function_in_Intrinsics.patch + +* Thu Jul 28 2022 kuenking111 - 1:1.8.0.342-b07.1 +- del hg git files + +* Fri Jul 22 2022 kuenking111 - 1:1.8.0.342-b07.0 +- del 8168926.patch +- del 8194154.patch +- del 8202142-jfr-event-io-TestInstrumentation-is-unstable.patch +- del 8266187_Memory_leak_in_appendBootClassPath.patch +- del debuginfo.diz-should-not-contain-the-path-after-unzip.patch +- del fix-make-bugs-when-git-and-hg-not-exist.patch +- modified 7092821-java.security.Provider.getService-is-synchro.patch +- modified 8268819-SA-Remove-libthread_db-dependency-on-Linux.patch +- modified fix-log-bug-enhance-aes-hmac-performance.patch + +* Fri Jul 15 2022 kuenking111 - 1:1.8.0.332-b09.7 +- del remove-gnu-debuglink-when-using-enable-debug-.patch + +* Mon Jul 4 2022 kuenking111 - 1:1.8.0.332-b09.6 +- add 8067941-TESTBUG-Fix-tests-for-OS-with-64K-page-size.patch + +* Mon Jul 4 2022 kuenking111 - 1:1.8.0.332-b09.5 +- add 8173339-AArch64-Fix-minimum-stack-size-computations.patch + +* Mon Jul 4 2022 kuenking111 - 1:1.8.0.332-b09.4 +- add 7092821-java.security.Provider.getService-is-synchro.patch + +* Thu Jun 30 2022 kuenking111 - 1:1.8.0.332-b09.3 +- add change-sa-jdi.jar-make-file-for-BEP.PATCH + +* Thu Apr 28 2022 kuenking111 - 1:1.8.0.332-b09.2 +- add fix_X509TrustManagerImpl_symantec_distrust.patch + +* Wed Apr 27 2022 kuenking111 - 1:1.8.0.332-b09.1 +- add Fix-compile-and-runtime-failures-for-minimal1-versio.patch + +* Wed Apr 27 2022 kuenking111 - 1:1.8.0.332-b09.0 +- deleted Support-Git-commit-ID-in-the-SOURCE-field-of-the-release.patch +- deleted 8167014-jdeps-failed-with-Missing-message-warn-skippen-entry.patch +- deleted fix-wrong-commitID-in-release-file.patch +- deleted recreate-.java_pid-file-when-deleted-for-attach-mechanism.patch +- modified update-cacerts-and-VerifyCACerts.java-test.patch +- modified 8194154.patch +- modified add-missing-test-case.patch +- add fix-make-bugs-when-git-and-hg-not-exist.patch + * Wed Mar 2 2022 kuenking111 - 1:1.8.0.322-b06.4 - add 8268819-SA-Remove-libthread_db-dependency-on-Linux.patch -* Thu Mar 1 2022 kuenking111 - 1:1.8.0.322-b06.3 +* Tue Mar 1 2022 kuenking111 - 1:1.8.0.322-b06.3 - modified 8233280-Remove-GCLockerInvokesConcurrent-relative-logic-for-G1.patch * Wed Feb 16 2022 kuenking111 - 1:1.8.0.322-b06.2 @@ -2262,6 +2414,8 @@ require "copy_jdk_configs.lua" - deleted Delete-expired-certificate-globalsignr2ca.patch - deleted inline-optimize-for-aarch64.patch +* Tue Jan 05 2021 noah - 1:1.8.0.312-b07.11 +- adapted to newst cjc to fix issue with rpm 4.17 * Tue Dec 21 2021 kuenking111 - 1:1.8.0.312-b07.10 - delete stack protection @@ -2293,7 +2447,7 @@ require "copy_jdk_configs.lua" * Tue Nov 23 2021 lijingwei - 1:1.8.0.312-b07.1 - correct spec file release number typo -* Mon Nov 11 2021 kuenking111 - 1:1.8.0.312-b07.0 +* Mon Nov 1 2021 kuenking111 - 1:1.8.0.312-b07.0 - update to 8u312-b07(ga) - delete 8194246.patch - delete 8214418-half-closed-SSLEngine-status-may-cause-appli.patch @@ -2349,10 +2503,10 @@ require "copy_jdk_configs.lua" - delete fix-crash-in-JVMTI-debug.patch - other adaptations to jdk8u302 -* Thu Jul 12 2021 noah - 1:1.8.0.292-b10.19 +* Mon Jul 12 2021 noah - 1:1.8.0.292-b10.19 - add Fix-RSACipher-memory-usage.patch -* Thu Jul 12 2021 kuenking111 - 1:1.8.0.292-b10.18 +* Mon Jul 12 2021 kuenking111 - 1:1.8.0.292-b10.18 - fix run SPECjvm2008 failed on 32 bit system * Thu Jul 8 2021 noah - 1:1.8.0.292-b10.17 @@ -2376,7 +2530,7 @@ require "copy_jdk_configs.lua" * Sat Jun 12 2021 kuenking111 - 1:1.8.0.292-b10.11 - add g1gc-numa-aware-Implementation.patch -* Wed Jun 10 2021 hu_bo_dao - 1:1.8.0.292-b10.10 +* Fri Jun 11 2021 hu_bo_dao - 1:1.8.0.292-b10.10 - add support_CMS_parallel_inspection.patch * Wed Jun 9 2021 noah - 1:1.8.0.292-b10.9 @@ -2397,13 +2551,13 @@ require "copy_jdk_configs.lua" * Thu May 27 2021 kuenking111 - 1:1.8.0.292-b10.4 - add 8264640.patch -* Fri May 20 2021 kuenking111 - 1:1.8.0.292-b10.3 +* Fri May 21 2021 kuenking111 - 1:1.8.0.292-b10.3 - add 8266929_huawei_add_oid_mapping_common_sig_types.patch -* Fri May 20 2021 kuenking111 - 1:1.8.0.292-b10.2 +* Fri May 21 2021 kuenking111 - 1:1.8.0.292-b10.2 - add 8266187_Memory_leak_in_appendBootClassPath.patch -* Fri May 20 2021 kuenking111 - 1:1.8.0.292-b10.1 +* Fri May 21 2021 kuenking111 - 1:1.8.0.292-b10.1 - add 8247691_incorrect_handling_of_VM_exceptions_in_C1_deopt_stub.patch * Tue May 18 2021 eapen - 1:1.8.0.292-b10.0 diff --git a/remove-gnu-debuglink-when-using-enable-debug-.patch b/remove-gnu-debuglink-when-using-enable-debug-.patch deleted file mode 100644 index 8d7ff6eb74a3d74bffdb2c935cb3df117a0f1d75..0000000000000000000000000000000000000000 --- a/remove-gnu-debuglink-when-using-enable-debug-.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 39774b66e6b962a89a02504f08c20b309f9eef1f Mon Sep 17 00:00:00 2001 -From: zhangyipeng -Date: Thu, 4 Mar 2021 10:10:30 +0800 -Subject: [PATCH] [Huawei]remove gnu debuglink when using enable debug - symbols - - - -Signed-off-by: Sun Jianye ---- - hotspot/make/linux/makefiles/jsig.make | 1 - - hotspot/make/linux/makefiles/saproc.make | 1 - - hotspot/make/linux/makefiles/vm.make | 1 - - make/common/NativeCompilation.gmk | 2 +- - 4 files changed, 1 insertion(+), 4 deletions(-) - -diff --git a/hotspot/make/linux/makefiles/jsig.make b/hotspot/make/linux/makefiles/jsig.make -index 6290db5af..9838a50aa 100644 ---- a/hotspot/make/linux/makefiles/jsig.make -+++ b/hotspot/make/linux/makefiles/jsig.make -@@ -63,7 +63,6 @@ $(LIBJSIG): $(JSIGSRCDIR)/jsig.c $(LIBJSIG_MAPFILE) - ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifneq ($(STRIP_POLICY),no_strip) - $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJSIG_DEBUGINFO) -- $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJSIG_DEBUGINFO) $@ - endif - ifeq ($(STRIP_POLICY),all_strip) - $(QUIETLY) $(STRIP) $@ -diff --git a/hotspot/make/linux/makefiles/saproc.make b/hotspot/make/linux/makefiles/saproc.make -index ffc0ec5ce..dfeb254da 100644 ---- a/hotspot/make/linux/makefiles/saproc.make -+++ b/hotspot/make/linux/makefiles/saproc.make -@@ -107,7 +107,6 @@ $(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) - ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifneq ($(STRIP_POLICY),no_strip) - $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBSAPROC_DEBUGINFO) -- $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBSAPROC_DEBUGINFO) $@ - endif - ifeq ($(STRIP_POLICY),all_strip) - $(QUIETLY) $(STRIP) $@ -diff --git a/hotspot/make/linux/makefiles/vm.make b/hotspot/make/linux/makefiles/vm.make -index 1985db071..408b0cc9d 100644 ---- a/hotspot/make/linux/makefiles/vm.make -+++ b/hotspot/make/linux/makefiles/vm.make -@@ -359,7 +359,6 @@ $(LIBJVM): $(LIBJVM.o) $(LIBJVM_MAPFILE) $(LD_SCRIPT) - ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifneq ($(STRIP_POLICY),no_strip) - $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJVM_DEBUGINFO) -- $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DEBUGINFO) $@ - endif - ifeq ($(STRIP_POLICY),all_strip) - $(QUIETLY) $(STRIP) $@ -diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk -index 9980e8ab9..4fa9f14cf 100644 ---- a/make/common/NativeCompilation.gmk -+++ b/make/common/NativeCompilation.gmk -@@ -487,7 +487,7 @@ define SetupNativeCompilation - $$($1_DEBUGINFO_FILES): $$($1_TARGET) - $(RM) $$@ - $(OBJCOPY) --only-keep-debug $$< $$@ -- $(CD) $$(@D) && $(OBJCOPY) --add-gnu-debuglink=$$(@F) $$< -+ $(CD) $$(@D) - $(TOUCH) $$@ - endif - else ifeq ($(OPENJDK_TARGET_OS), aix) --- -2.19.0 - diff --git a/revert-fPIC-and-security-compilation-flag-on.patch b/revert-fPIC-and-security-compilation-flag-on.patch new file mode 100644 index 0000000000000000000000000000000000000000..a785c84154e7daba6a202a27a2e6f57dae0cc68f --- /dev/null +++ b/revert-fPIC-and-security-compilation-flag-on.patch @@ -0,0 +1,60 @@ +From 9ffc530e0d34086e68c87306ca0410e5847812d6 Mon Sep 17 00:00:00 2001 +Date: Wed, 21 Sep 2022 09:53:14 +0800 +Subject: revert fPIC and security compilation flag on + +--- + common/autoconf/flags.m4 | 6 +----- + common/autoconf/generated-configure.sh | 6 +----- + hotspot/make/pic.make | 2 +- + 3 files changed, 3 insertions(+), 11 deletions(-) + +diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 +index 69bea78d..71703a15 100644 +--- a/common/autoconf/flags.m4 ++++ b/common/autoconf/flags.m4 +@@ -807,11 +807,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], + LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Xlinker --allow-shlib-undefined" + fi + if test "x$TOOLCHAIN_TYPE" = xgcc; then +- # Enabling pie on 32 bit builds prevents the JVM from allocating a continuous +- # java heap. +- if test "x$OPENJDK_TARGET_CPU_BITS" != "x32"; then +- LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -pie" +- fi ++ LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -pie" + fi + fi + AC_SUBST(LDFLAGS_JDKLIB) +diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh +index f0e49f50..53e6cf18 100644 +--- a/common/autoconf/generated-configure.sh ++++ b/common/autoconf/generated-configure.sh +@@ -43068,11 +43068,7 @@ $as_echo "$supports" >&6; } + LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Xlinker --allow-shlib-undefined" + fi + if test "x$TOOLCHAIN_TYPE" = xgcc; then +- # Enabling pie on 32 bit builds prevents the JVM from allocating a continuous +- # java heap. +- if test "x$OPENJDK_TARGET_CPU_BITS" != "x32"; then +- LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -pie" +- fi ++ LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -pie" + fi + fi + +diff --git a/hotspot/make/pic.make b/hotspot/make/pic.make +index 0e61ad93..3d85546c 100644 +--- a/hotspot/make/pic.make ++++ b/hotspot/make/pic.make +@@ -30,7 +30,7 @@ include $(GAMMADIR)/make/scm.make + + ifneq ($(OSNAME), windows) + ifndef LP64 +- PARTIAL_NONPIC=1 ++ PARTIAL_NONPIC=0 + endif + PIC_ARCH = ppc arm + ifneq ("$(filter $(PIC_ARCH),$(BUILDARCH))","") +-- +2.22.0 + diff --git a/update-cacerts-and-VerifyCACerts.java-test.patch b/update-cacerts-and-VerifyCACerts.java-test.patch index e98895573d7f24ac1232bb22c368420624372274..424d2f552982a1c075673ec11a2466a51f457c0e 100644 --- a/update-cacerts-and-VerifyCACerts.java-test.patch +++ b/update-cacerts-and-VerifyCACerts.java-test.patch @@ -3,6 +3,8 @@ From: zhangyipeng Date: Tue, 20 Apr 2021 10:40:35 +0800 Subject: [PATCH] [Huawei]update cacerts and VerifyCACerts.java test +Offering: Cloud Compiler JDK + Signed-off-by: Wang Kun --- jdk/make/data/cacerts/addtrustexternalca | 32 ----------------- @@ -10,6 +12,7 @@ Signed-off-by: Wang Kun jdk/make/data/cacerts/luxtrustglobalrootca | 28 --------------- jdk/make/data/cacerts/quovadisrootca | 41 ---------------------- jdk/make/data/cacerts/utnuserfirstobjectca | 33 ----------------- + jdk/make/data/cacerts/geotrustglobalca | 27 ------------------- .../sun/security/lib/cacerts/VerifyCACerts.java | 29 ++------------------- 8 files changed, 3 insertions(+), 192 deletions(-) delete mode 100644 jdk/make/data/cacerts/addtrustexternalca @@ -19,6 +22,7 @@ Signed-off-by: Wang Kun delete mode 100644 jdk/make/data/cacerts/thawtepremiumserverca delete mode 100644 jdk/make/data/cacerts/utnuserfirstobjectca delete mode 100644 jdk/make/data/cacerts/verisigntsaca + delete mode 100644 jdk/make/data/cacerts/geotrustglobalca diff --git a/jdk/make/data/cacerts/addtrustexternalca b/jdk/make/data/cacerts/addtrustexternalca deleted file mode 100644 @@ -216,6 +220,39 @@ index 80a0b5c..0000000 -81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR -Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= ------END CERTIFICATE----- +diff --git a/jdk/make/data/cacerts/geotrustglobalca b/jdk/make/data/cacerts/geotrustglobalca +deleted file mode 100644 +index 7f8bf9a6..00000000 +--- a/jdk/make/data/cacerts/geotrustglobalca ++++ /dev/null +@@ -1,27 +0,0 @@ +-Owner: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US +-Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US +-Serial number: 23456 +-Valid from: Tue May 21 04:00:00 GMT 2002 until: Sat May 21 04:00:00 GMT 2022 +-Signature algorithm name: SHA1withRSA +-Subject Public Key Algorithm: 2048-bit RSA key +-Version: 3 +------BEGIN CERTIFICATE----- +-MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +-MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +-YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +-EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +-R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +-9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +-fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +-iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +-1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +-bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +-MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +-ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +-uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +-Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +-tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +-PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +-hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +-5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +------END CERTIFICATE----- diff --git a/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java b/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java index dd107fc..791ddb6 100644 --- a/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java @@ -225,13 +262,13 @@ index dd107fc..791ddb6 100644 // The numbers of certs now. - private static final int COUNT = 89; -+ private static final int COUNT = 84; ++ private static final int COUNT = 83; // 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 - = "CC:AD:BB:49:70:97:3F:42:AD:73:91:A0:A2:C4:B8:AA:D1:95:59:F3:B3:22:09:2A:1F:2C:AB:04:47:08:EF:AA"; -+ = "D3:05:21:64:FA:D7:CD:29:E8:CB:57:E7:47:ED:79:9B:47:D8:0E:75:2D:CA:83:BB:86:AF:D9:43:FD:3E:17:85"; ++ = "2D:04:88:6C:52:53:54:EB:38:2D:BC:E0:AF:B7:82:F4:9E:32:A8:1A:1B:A3:AE:CF:25:CB:C2:F6:0F:4E:E1:20"; // map of cert alias to SHA-256 fingerprint @SuppressWarnings("serial") @@ -248,6 +285,15 @@ index dd107fc..791ddb6 100644 put("baltimorecybertrustca [jdk]", "16:AF:57:A9:F6:76:B0:AB:12:60:95:AA:5E:BA:DE:F2:2A:B3:11:19:D6:44:AC:95:CD:4B:93:DB:F3:F2:6A:EB"); put("digicertglobalrootca [jdk]", +@@ -111,8 +111,6 @@ public class VerifyCACerts { + "7E:37:CB:8B:4C:47:09:0C:AB:36:55:1B:A6:F4:5D:B8:40:68:0F:BA:16:6A:95:2D:B1:00:71:7F:43:05:3F:C2"); + put("digicerthighassuranceevrootca [jdk]", + "74:31:E5:F4:C3:C1:CE:46:90:77:4F:0B:61:E0:54:40:88:3B:A9:A0:1E:D0:0B:A6:AB:D7:80:6E:D3:B1:18:CF"); +- put("geotrustglobalca [jdk]", +- "FF:85:6A:2D:25:1D:CD:88:D3:66:56:F4:50:12:67:98:CF:AB:AA:DE:40:79:9C:72:2D:E4:D2:B5:DB:36:A7:3A"); + put("geotrustprimaryca [jdk]", + "37:D5:10:06:C5:12:EA:AB:62:64:21:F1:EC:8C:92:01:3F:C5:F8:2A:E9:8E:E5:33:EB:46:19:B8:DE:B4:D0:6C"); + put("geotrustprimarycag2 [jdk]", @@ -163,10 +147,6 @@ public class VerifyCACerts { "5D:56:49:9B:E4:D2:E0:8B:CF:CA:D0:8A:3E:38:72:3D:50:50:3B:DE:70:69:48:E4:2F:55:60:30:19:E5:28:AE"); put("letsencryptisrgx1 [jdk]", @@ -259,7 +305,7 @@ index dd107fc..791ddb6 100644 put("quovadisrootca1g3 [jdk]", "8A:86:6F:D1:B2:76:B5:7E:57:8E:92:1C:65:82:8A:2B:ED:58:E9:F2:F2:88:05:41:34:B7:F1:F4:BF:C9:CC:74"); put("quovadisrootca2 [jdk]", -@@ -267,20 +247,7 @@ public class VerifyCACerts { +@@ -267,22 +247,7 @@ public class VerifyCACerts { // Exception list to 90 days expiry policy // No error will be reported if certificate in this list expires @SuppressWarnings("serial") @@ -275,6 +321,8 @@ index dd107fc..791ddb6 100644 - 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 +- add("geotrustglobalca [jdk]"); - } - }; + private static final HashSet EXPIRY_EXC_ENTRIES = new HashSet(); @@ -282,5 +330,4 @@ index dd107fc..791ddb6 100644 // Ninety days in milliseconds private static final long NINETY_DAYS = 7776000000L; -- -1.8.3.1 - +2.19.0