diff --git a/src/java.base/share/classes/java/lang/Byte.java b/src/java.base/share/classes/java/lang/Byte.java index c78e11ae067..5835f65366f 100644 --- a/src/java.base/share/classes/java/lang/Byte.java +++ b/src/java.base/share/classes/java/lang/Byte.java @@ -117,7 +117,7 @@ public final class Byte extends Number implements Comparable, Constable { // Load and use the archived cache if it exists CDS.initializeFromArchive(ByteCache.class); - if (archivedCache == null || archivedCache.length != size) { + if (archivedCache == null) { Byte[] c = new Byte[size]; byte value = (byte)-128; for(int i = 0; i < size; i++) { @@ -126,6 +126,7 @@ public final class Byte extends Number implements Comparable, Constable { archivedCache = c; } cache = archivedCache; + assert cache.length == size; } } diff --git a/src/java.base/share/classes/java/lang/Character.java b/src/java.base/share/classes/java/lang/Character.java index 101eabcbcc0..8368adf5403 100644 --- a/src/java.base/share/classes/java/lang/Character.java +++ b/src/java.base/share/classes/java/lang/Character.java @@ -8984,7 +8984,7 @@ class Character implements java.io.Serializable, Comparable, Constabl // Load and use the archived cache if it exists CDS.initializeFromArchive(CharacterCache.class); - if (archivedCache == null || archivedCache.length != size) { + if (archivedCache == null) { Character[] c = new Character[size]; for (int i = 0; i < size; i++) { c[i] = new Character((char) i); @@ -8992,6 +8992,7 @@ class Character implements java.io.Serializable, Comparable, Constabl archivedCache = c; } cache = archivedCache; + assert cache.length == size; } } diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 84fa5303ac7..e666e977c61 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -960,7 +960,17 @@ public final class Integer extends Number if (archivedCache == null || size > archivedCache.length) { Integer[] c = new Integer[size]; int j = low; - for(int i = 0; i < c.length; i++) { + // If archive has Integer cache, we must use all instances from it. + // Otherwise, the identity checks between archived Integers and + // runtime-cached Integers would fail. + int archivedSize = (archivedCache == null) ? 0 : archivedCache.length; + for (int i = 0; i < archivedSize; i++) { + c[i] = archivedCache[i]; + assert j == archivedCache[i]; + j++; + } + // Fill the rest of the cache. + for (int i = archivedSize; i < size; i++) { c[i] = new Integer(j++); } archivedCache = c; diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 78a2402ba0e..8c083b3ec84 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -962,7 +962,7 @@ public final class Long extends Number // Load and use the archived cache if it exists CDS.initializeFromArchive(LongCache.class); - if (archivedCache == null || archivedCache.length != size) { + if (archivedCache == null) { Long[] c = new Long[size]; long value = -128; for(int i = 0; i < size; i++) { @@ -971,6 +971,7 @@ public final class Long extends Number archivedCache = c; } cache = archivedCache; + assert cache.length == size; } } diff --git a/src/java.base/share/classes/java/lang/Short.java b/src/java.base/share/classes/java/lang/Short.java index a2d31ee07c3..57e88442b27 100644 --- a/src/java.base/share/classes/java/lang/Short.java +++ b/src/java.base/share/classes/java/lang/Short.java @@ -244,7 +244,7 @@ public final class Short extends Number implements Comparable, Constable // Load and use the archived cache if it exists CDS.initializeFromArchive(ShortCache.class); - if (archivedCache == null || archivedCache.length != size) { + if (archivedCache == null) { Short[] c = new Short[size]; short value = -128; for(int i = 0; i < size; i++) { @@ -253,6 +253,7 @@ public final class Short extends Number implements Comparable, Constable archivedCache = c; } cache = archivedCache; + assert cache.length == size; } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java index 43d8568fac5..8bf3f9fcd27 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java @@ -27,8 +27,9 @@ * @summary Test primitive box caches integrity in various scenarios (IntegerCache etc) * @requires vm.cds.write.archived.java.heap * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/cds/appcds - * @compile CheckIntegerCacheApp.java + * @compile --add-exports java.base/jdk.internal.misc=ALL-UNNAMED CheckIntegerCacheApp.java ArchivedIntegerHolder.java * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boxCache.jar CheckIntegerCacheApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boxCache-boot.jar ArchivedIntegerHolder * @run driver ArchivedIntegerCacheTest */ @@ -41,6 +42,19 @@ import jdk.test.lib.helpers.ClassFileInstaller; public class ArchivedIntegerCacheTest { + public static String[] mixArgs(String... args) { + String bootJar = ClassFileInstaller.getJarPath("boxCache-boot.jar"); + + String[] newArgs = new String[args.length + 5]; + newArgs[0] = "--add-exports"; + newArgs[1] = "java.base/jdk.internal.misc=ALL-UNNAMED"; + newArgs[2] = "-Xbootclasspath/a:" + bootJar; + newArgs[3] = "-XX:+IgnoreUnrecognizedVMOptions"; + newArgs[4] = "-XX:ArchiveHeapTestClass=ArchivedIntegerHolder"; + System.arraycopy(args, 0, newArgs, 5, args.length); + return newArgs; + } + public static void main(String[] args) throws Exception { String appJar = ClassFileInstaller.getJarPath("boxCache.jar"); @@ -51,15 +65,15 @@ public class ArchivedIntegerCacheTest { // Dump default archive // OutputAnalyzer output = TestCommon.dump(appJar, - TestCommon.list("CheckIntegerCacheApp")); + TestCommon.list("CheckIntegerCacheApp"), + mixArgs()); TestCommon.checkDump(output); // Test case 1) // - Default options System.out.println("----------------------- Test case 1 ----------------------"); output = TestCommon.exec(appJar, - "CheckIntegerCacheApp", - "127"); + mixArgs("CheckIntegerCacheApp", "127")); TestCommon.checkExec(output); // Test case 2) @@ -67,9 +81,8 @@ public class ArchivedIntegerCacheTest { // - Larger -XX:AutoBoxCacheMax System.out.println("----------------------- Test case 2 ----------------------"); output = TestCommon.exec(appJar, - "-XX:AutoBoxCacheMax=20000", - "CheckIntegerCacheApp", - "20000"); + mixArgs("-XX:AutoBoxCacheMax=20000", + "CheckIntegerCacheApp", "20000")); TestCommon.checkExec(output); // @@ -77,7 +90,7 @@ public class ArchivedIntegerCacheTest { // output = TestCommon.dump(appJar, TestCommon.list("CheckIntegerCacheApp"), - "-XX:AutoBoxCacheMax=20000"); + mixArgs("-XX:AutoBoxCacheMax=20000")); TestCommon.checkDump(output); // Test case 3) @@ -85,10 +98,8 @@ public class ArchivedIntegerCacheTest { // - Default options System.out.println("----------------------- Test case 3 ----------------------"); output = TestCommon.exec(appJar, - "--module-path", - moduleDir.toString(), - "CheckIntegerCacheApp", - "127"); + mixArgs("--module-path", moduleDir.toString(), + "CheckIntegerCacheApp", "127")); TestCommon.checkExec(output); @@ -97,11 +108,9 @@ public class ArchivedIntegerCacheTest { // - Matching options System.out.println("----------------------- Test case 4 ----------------------"); output = TestCommon.exec(appJar, - "--module-path", - moduleDir.toString(), - "-XX:AutoBoxCacheMax=20000", - "CheckIntegerCacheApp", - "20000"); + mixArgs("--module-path", moduleDir.toString(), + "-XX:AutoBoxCacheMax=20000", + "CheckIntegerCacheApp", "20000")); TestCommon.checkExec(output); // Test case 5) @@ -109,23 +118,21 @@ public class ArchivedIntegerCacheTest { // - Larger requested cache System.out.println("----------------------- Test case 5 ----------------------"); output = TestCommon.exec(appJar, - "--module-path", - moduleDir.toString(), - "-XX:AutoBoxCacheMax=30000", - "CheckIntegerCacheApp", - "30000"); + mixArgs("--module-path", moduleDir.toString(), + "-XX:AutoBoxCacheMax=30000", + "CheckIntegerCacheApp", "30000")); TestCommon.checkExec(output); // Test case 6) // - Cache is too large to archive output = TestCommon.dump(appJar, TestCommon.list("CheckIntegerCacheApp"), - "-XX:AutoBoxCacheMax=2000000", - "-Xmx1g", - "-XX:NewSize=1g", - "-Xlog:cds+heap=info", - "-Xlog:gc+region+cds", - "-Xlog:gc+region=trace"); + mixArgs("-XX:AutoBoxCacheMax=2000000", + "-Xmx1g", + "-XX:NewSize=1g", + "-Xlog:cds+heap=info", + "-Xlog:gc+region+cds", + "-Xlog:gc+region=trace")); TestCommon.checkDump(output, "Cannot archive the sub-graph referenced from [Ljava.lang.Integer; object"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerHolder.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerHolder.java new file mode 100644 index 00000000000..c8ab0db7d34 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedIntegerHolder.java @@ -0,0 +1,38 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import jdk.internal.misc.CDS; + +public class ArchivedIntegerHolder { + public static Object[] archivedObjects; + static { + CDS.initializeFromArchive(ArchivedIntegerHolder.class); + if (archivedObjects == null) { + archivedObjects = new Object[256]; + for (int i = -128; i <= 127; i++) { + archivedObjects[i + 128] = Integer.valueOf(i); + } + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java index a1d1655b32f..7f66b2339a2 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java @@ -62,6 +62,14 @@ public class CheckIntegerCacheApp { } } + // Check that archived integer cache agrees with runtime integer cache. + for (int i = -128; i <= 127; i++) { + if (ArchivedIntegerHolder.archivedObjects[i + 128] != Integer.valueOf(i)) { + throw new RuntimeException( + "FAILED. Archived and runtime caches disagree for " + i); + } + } + int high = Integer.parseInt(args[0]); if (Integer.valueOf(high) != Integer.valueOf(high)) { throw new RuntimeException(