8213033: Archive remaining primitive box caches
authorredestad
Tue, 20 Nov 2018 21:12:46 +0100
changeset 52626 991fe09c698c
parent 52625 5e23b9a66fe6
child 52627 e7d8ea5bfc8f
8213033: Archive remaining primitive box caches Reviewed-by: jiangli, alanb
src/hotspot/share/memory/heapShared.cpp
src/java.base/share/classes/java/lang/Byte.java
src/java.base/share/classes/java/lang/Character.java
src/java.base/share/classes/java/lang/Integer.java
src/java.base/share/classes/java/lang/Long.java
src/java.base/share/classes/java/lang/Short.java
test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/ReplaceCriticalClasses.java
test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedIntegerCacheTest.java
test/hotspot/jtreg/runtime/appcds/cacheObject/CheckIntegerCacheApp.java
--- a/src/hotspot/share/memory/heapShared.cpp	Mon Nov 19 09:57:41 2018 -0800
+++ b/src/hotspot/share/memory/heapShared.cpp	Tue Nov 20 21:12:46 2018 +0100
@@ -64,6 +64,10 @@
 // assigned at runtime.
 static ArchivableStaticFieldInfo closed_archive_subgraph_entry_fields[] = {
   {"java/lang/Integer$IntegerCache",           "archivedCache"},
+  {"java/lang/Long$LongCache",                 "archivedCache"},
+  {"java/lang/Byte$ByteCache",                 "archivedCache"},
+  {"java/lang/Short$ShortCache",               "archivedCache"},
+  {"java/lang/Character$CharacterCache",       "archivedCache"},
 };
 // Entry fields for subgraphs archived in the open archive heap region.
 static ArchivableStaticFieldInfo open_archive_subgraph_entry_fields[] = {
--- a/src/java.base/share/classes/java/lang/Byte.java	Mon Nov 19 09:57:41 2018 -0800
+++ b/src/java.base/share/classes/java/lang/Byte.java	Tue Nov 20 21:12:46 2018 +0100
@@ -26,6 +26,7 @@
 package java.lang;
 
 import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.VM;
 
 /**
  *
@@ -77,13 +78,25 @@
     }
 
     private static class ByteCache {
-        private ByteCache(){}
+        private ByteCache() {}
 
-        static final Byte cache[] = new Byte[-(-128) + 127 + 1];
+        static final Byte[] cache;
+        static Byte[] archivedCache;
 
         static {
-            for(int i = 0; i < cache.length; i++)
-                cache[i] = new Byte((byte)(i - 128));
+            final int size = -(-128) + 127 + 1;
+
+            // Load and use the archived cache if it exists
+            VM.initializeFromArchive(ByteCache.class);
+            if (archivedCache == null || archivedCache.length != size) {
+                Byte[] c = new Byte[size];
+                byte value = (byte)-128;
+                for(int i = 0; i < size; i++) {
+                    c[i] = new Byte(value++);
+                }
+                archivedCache = c;
+            }
+            cache = archivedCache;
         }
     }
 
--- a/src/java.base/share/classes/java/lang/Character.java	Mon Nov 19 09:57:41 2018 -0800
+++ b/src/java.base/share/classes/java/lang/Character.java	Tue Nov 20 21:12:46 2018 +0100
@@ -31,6 +31,7 @@
 import java.util.Locale;
 
 import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.VM;
 
 /**
  * The {@code Character} class wraps a value of the primitive
@@ -7914,11 +7915,22 @@
     private static class CharacterCache {
         private CharacterCache(){}
 
-        static final Character cache[] = new Character[127 + 1];
+        static final Character[] cache;
+        static Character[] archivedCache;
 
         static {
-            for (int i = 0; i < cache.length; i++)
-                cache[i] = new Character((char)i);
+            int size = 127 + 1;
+
+            // Load and use the archived cache if it exists
+            VM.initializeFromArchive(CharacterCache.class);
+            if (archivedCache == null || archivedCache.length != size) {
+                Character[] c = new Character[size];
+                for (int i = 0; i < size; i++) {
+                    c[i] = new Character((char) i);
+                }
+                archivedCache = c;
+            }
+            cache = archivedCache;
         }
     }
 
--- a/src/java.base/share/classes/java/lang/Integer.java	Mon Nov 19 09:57:41 2018 -0800
+++ b/src/java.base/share/classes/java/lang/Integer.java	Tue Nov 20 21:12:46 2018 +0100
@@ -1013,10 +1013,9 @@
                 VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
             if (integerCacheHighPropValue != null) {
                 try {
-                    int i = parseInt(integerCacheHighPropValue);
-                    i = Math.max(i, 127);
+                    h = Math.max(parseInt(integerCacheHighPropValue), 127);
                     // Maximum array size is Integer.MAX_VALUE
-                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
+                    h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
                 } catch( NumberFormatException nfe) {
                     // If the property cannot be parsed into an int, ignore it.
                 }
@@ -1031,8 +1030,9 @@
             if (archivedCache == null || size > archivedCache.length) {
                 Integer[] c = new Integer[size];
                 int j = low;
-                for(int k = 0; k < c.length; k++)
-                    c[k] = new Integer(j++);
+                for(int i = 0; i < c.length; i++) {
+                    c[i] = new Integer(j++);
+                }
                 archivedCache = c;
             }
             cache = archivedCache;
--- a/src/java.base/share/classes/java/lang/Long.java	Mon Nov 19 09:57:41 2018 -0800
+++ b/src/java.base/share/classes/java/lang/Long.java	Tue Nov 20 21:12:46 2018 +0100
@@ -29,6 +29,7 @@
 import java.math.*;
 import java.util.Objects;
 import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.VM;
 
 import static java.lang.String.COMPACT_STRINGS;
 import static java.lang.String.LATIN1;
@@ -1145,13 +1146,25 @@
     }
 
     private static class LongCache {
-        private LongCache(){}
+        private LongCache() {}
 
-        static final Long cache[] = new Long[-(-128) + 127 + 1];
+        static final Long[] cache;
+        static Long[] archivedCache;
 
         static {
-            for(int i = 0; i < cache.length; i++)
-                cache[i] = new Long(i - 128);
+            int size = -(-128) + 127 + 1;
+
+            // Load and use the archived cache if it exists
+            VM.initializeFromArchive(LongCache.class);
+            if (archivedCache == null || archivedCache.length != size) {
+                Long[] c = new Long[size];
+                long value = -128;
+                for(int i = 0; i < size; i++) {
+                    c[i] = new Long(value++);
+                }
+                archivedCache = c;
+            }
+            cache = archivedCache;
         }
     }
 
--- a/src/java.base/share/classes/java/lang/Short.java	Mon Nov 19 09:57:41 2018 -0800
+++ b/src/java.base/share/classes/java/lang/Short.java	Tue Nov 20 21:12:46 2018 +0100
@@ -26,6 +26,7 @@
 package java.lang;
 
 import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.VM;
 
 /**
  * The {@code Short} class wraps a value of primitive type {@code
@@ -203,13 +204,25 @@
     }
 
     private static class ShortCache {
-        private ShortCache(){}
+        private ShortCache() {}
 
-        static final Short cache[] = new Short[-(-128) + 127 + 1];
+        static final Short[] cache;
+        static Short[] archivedCache;
 
         static {
-            for(int i = 0; i < cache.length; i++)
-                cache[i] = new Short((short)(i - 128));
+            int size = -(-128) + 127 + 1;
+
+            // Load and use the archived cache if it exists
+            VM.initializeFromArchive(ShortCache.class);
+            if (archivedCache == null || archivedCache.length != size) {
+                Short[] c = new Short[size];
+                short value = -128;
+                for(int i = 0; i < size; i++) {
+                    c[i] = new Short(value++);
+                }
+                archivedCache = c;
+            }
+            cache = archivedCache;
         }
     }
 
--- a/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/ReplaceCriticalClasses.java	Mon Nov 19 09:57:41 2018 -0800
+++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/ReplaceCriticalClasses.java	Tue Nov 20 21:12:46 2018 +0100
@@ -152,30 +152,11 @@
                        klassName);
 
         final boolean expectDisable = !early.equals("");
-        final boolean checkSubgraph = subgraph;
         CDSTestUtils.run(opts).assertNormalExit(out -> {
                 if (expectDisable) {
                     out.shouldContain("UseSharedSpaces: CDS is disabled because early JVMTI ClassFileLoadHook is in use.");
                     System.out.println("CDS disabled as expected");
                 }
-                if (checkSubgraph) {
-                    // As of 2018/10/21 the classes in the archived subgraphs won't be
-                    // replaced because all archived subgraphs were loaded in JVMTI_PHASE_PRIMORDIAL.
-                    //
-                    // This is the first class to be loaded after JVMTI has exited JVMTI_PHASE_PRIMORDIAL.
-                    // Make sure no subgraphs are loaded afterwards.
-                    //
-                    // Can't use out.shouldNotMatch() because that doesn't match across multiple lines.
-                    String firstNonPrimordialClass = "jdk.jfr.internal.EventWriter";
-                    String regexp = firstNonPrimordialClass + ".*initialize_from_archived_subgraph";
-                    Pattern regex = Pattern.compile(regexp, Pattern.DOTALL);
-                    Matcher matcher = regex.matcher(out.getStdout());
-                    if (matcher.find()) {
-                        out.reportDiagnosticSummary();
-                        throw new RuntimeException("'" + regexp
-                                                   + "' found in stdout: '" + matcher.group() + "' \n");
-                    }
-                }
             });
     }
 
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedIntegerCacheTest.java	Mon Nov 19 09:57:41 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedIntegerCacheTest.java	Tue Nov 20 21:12:46 2018 +0100
@@ -24,7 +24,7 @@
 
 /*
  * @test
- * @summary Test IntegerCache integrity in various scenarios
+ * @summary Test primitive box caches integrity in various scenarios (IntegerCache etc)
  * @requires vm.cds.archived.java.heap
  * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
  * @modules java.base/jdk.internal.misc
@@ -32,7 +32,7 @@
  *          jdk.jartool/sun.tools.jar
  * @build sun.hotspot.WhiteBox
  * @compile CheckIntegerCacheApp.java
- * @run driver ClassFileInstaller -jar integer.jar CheckIntegerCacheApp
+ * @run driver ClassFileInstaller -jar boxCache.jar CheckIntegerCacheApp
  * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
  * @run driver ArchivedIntegerCacheTest
  */
@@ -47,7 +47,7 @@
     public static void main(String[] args) throws Exception {
         String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
         String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
-        String appJar = ClassFileInstaller.getJarPath("integer.jar");
+        String appJar = ClassFileInstaller.getJarPath("boxCache.jar");
 
         Path userDir = Paths.get(System.getProperty("user.dir"));
         Path moduleDir = Files.createTempDirectory(userDir, "mods");
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckIntegerCacheApp.java	Mon Nov 19 09:57:41 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckIntegerCacheApp.java	Tue Nov 20 21:12:46 2018 +0100
@@ -25,11 +25,13 @@
 import sun.hotspot.WhiteBox;
 
 //
-// Help test archived integer cache consistency.
+// Help test archived box cache consistency.
 //
 // Takes two arguments:
-// 0: the expected AutoBoxCacheMax setting
+// 0: the expected maximum value expected to be archived
 // 1: if the values are expected to be retrieved from the archive or not
+//    (only applies to IntegerCache; other caches should always be mapped
+//    from archive)
 //
 public class CheckIntegerCacheApp {
     static WhiteBox wb;
@@ -55,7 +57,31 @@
                 throw new RuntimeException(
                         "FAILED. All values in range [-128, 127] should be interned in cache: " + i);
             }
-            checkArchivedAsExpected(archivedExpected, i);
+            if (Byte.valueOf((byte)i) != Byte.valueOf((byte)i)) {
+                throw new RuntimeException(
+                        "FAILED. All Byte values in range [-128, 127] should be interned in cache: " + (byte)i);
+            }
+            if (Short.valueOf((short)i) != Short.valueOf((short)i)) {
+                throw new RuntimeException(
+                        "FAILED. All Short values in range [-128, 127] should be interned in cache: " + (byte)i);
+            }
+            if (Long.valueOf(i) != Long.valueOf(i)) {
+                throw new RuntimeException(
+                        "FAILED. All Long values in range [-128, 127] should be interned in cache: " + i);
+            }
+            checkArchivedAsExpected(archivedExpected, Integer.valueOf(i));
+            checkArchivedAsExpected(true, Byte.valueOf((byte)i));
+            checkArchivedAsExpected(true, Short.valueOf((short)i));
+            checkArchivedAsExpected(true, Long.valueOf(i));
+
+            // Character cache only values 0 through 127
+            if (i >= 0) {
+                if (Character.valueOf((char)i) != Character.valueOf((char)i)) {
+                    throw new RuntimeException(
+                            "FAILED. All Character values in range [0, 127] should be interned in cache: " + i);
+                }
+                checkArchivedAsExpected(true, Character.valueOf((char)i));
+            }
         }
 
         int high = Integer.parseInt(args[0]);
@@ -70,18 +96,23 @@
                     "FAILED. Value not expected to be retrieved from cache: " + high);
         }
         checkArchivedAsExpected(false, Integer.valueOf(high + 1));
+        checkArchivedAsExpected(false, Short.valueOf((short)128));
+        checkArchivedAsExpected(false, Long.valueOf(128));
+        checkArchivedAsExpected(false, Character.valueOf((char)128));
     }
 
-    private static void checkArchivedAsExpected(boolean archivedExpected, Integer value) {
+    private static void checkArchivedAsExpected(boolean archivedExpected, Object value) {
         if (archivedExpected) {
-            if (!wb.isShared(Integer.valueOf(value))) {
+            if (!wb.isShared(value)) {
                 throw new RuntimeException(
-                        "FAILED. Value expected to be archived: " + value);
+                        "FAILED. Value expected to be archived: " + value +
+                        " of type " + value.getClass().getName());
             }
         } else {
-            if (wb.isShared(Integer.valueOf(value))) {
+            if (wb.isShared(value)) {
                 throw new RuntimeException(
-                        "FAILED. Value not expected to be archived: " + value);
+                        "FAILED. Value not expected to be archived: " + value +
+                        " of type " + value.getClass().getName());
             }
         }
     }