8209120: Archive the Integer.IntegerCache
Reviewed-by: jiangli, alanb, plevart, iklam, mchung
This commit is contained in:
parent
8044814e30
commit
5c3008fbc4
src
hotspot/share
java.base/share/classes/java/lang
test/hotspot/jtreg/runtime/appcds/cacheObject
@ -4251,6 +4251,7 @@ int jdk_internal_module_ArchivedModuleGraph::_archivedSystemModules_offset;
|
||||
int jdk_internal_module_ArchivedModuleGraph::_archivedModuleFinder_offset;
|
||||
int jdk_internal_module_ArchivedModuleGraph::_archivedMainModule_offset;
|
||||
int jdk_internal_module_ArchivedModuleGraph::_archivedConfiguration_offset;
|
||||
int java_lang_Integer_IntegerCache::_archivedCache_offset;
|
||||
int java_lang_module_Configuration::_EMPTY_CONFIGURATION_offset;
|
||||
int java_util_ImmutableCollections_ListN::_EMPTY_LIST_offset;
|
||||
int java_util_ImmutableCollections_SetN::_EMPTY_SET_offset;
|
||||
@ -4417,6 +4418,21 @@ static int member_offset(int hardcoded_offset) {
|
||||
return (hardcoded_offset * heapOopSize) + instanceOopDesc::base_offset_in_bytes();
|
||||
}
|
||||
|
||||
#define INTEGERCACHE_FIELDS_DO(macro) \
|
||||
macro(_archivedCache_offset, k, "archivedCache", java_lang_Integer_array_signature, true)
|
||||
|
||||
void java_lang_Integer_IntegerCache::compute_offsets() {
|
||||
InstanceKlass* k = SystemDictionary::Integer_IntegerCache_klass();
|
||||
assert(k != NULL, "must be loaded");
|
||||
INTEGERCACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void java_lang_Integer_IntegerCache::serialize(SerializeClosure* f) {
|
||||
INTEGERCACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ARCHIVEDMODULEGRAPH_FIELDS_DO(macro) \
|
||||
macro(_archivedSystemModules_offset, k, "archivedSystemModules", systemModules_signature, true); \
|
||||
macro(_archivedModuleFinder_offset, k, "archivedModuleFinder", moduleFinder_signature, true); \
|
||||
@ -4553,6 +4569,7 @@ void JavaClasses::compute_offsets() {
|
||||
java_lang_LiveStackFrameInfo::compute_offsets();
|
||||
java_util_concurrent_locks_AbstractOwnableSynchronizer::compute_offsets();
|
||||
|
||||
java_lang_Integer_IntegerCache::compute_offsets();
|
||||
java_lang_module_Configuration::compute_offsets();
|
||||
java_util_ImmutableCollections_ListN::compute_offsets();
|
||||
java_util_ImmutableCollections_MapN::compute_offsets();
|
||||
|
@ -1485,6 +1485,15 @@ class java_util_concurrent_locks_AbstractOwnableSynchronizer : AllStatic {
|
||||
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
class java_lang_Integer_IntegerCache: AllStatic {
|
||||
private:
|
||||
static int _archivedCache_offset;
|
||||
public:
|
||||
static int archivedCache_offset() { return _archivedCache_offset; }
|
||||
static void compute_offsets();
|
||||
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
class jdk_internal_module_ArchivedModuleGraph: AllStatic {
|
||||
private:
|
||||
static int _archivedSystemModules_offset;
|
||||
|
@ -215,6 +215,7 @@ class OopStorage;
|
||||
do_klass(Byte_klass, java_lang_Byte, Pre ) \
|
||||
do_klass(Short_klass, java_lang_Short, Pre ) \
|
||||
do_klass(Integer_klass, java_lang_Integer, Pre ) \
|
||||
do_klass(Integer_IntegerCache_klass, java_lang_Integer_IntegerCache, Pre ) \
|
||||
do_klass(Long_klass, java_lang_Long, Pre ) \
|
||||
\
|
||||
/* JVMCI classes. These are loaded on-demand. */ \
|
||||
|
@ -438,6 +438,7 @@
|
||||
template(fileToEncodedURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \
|
||||
template(getProtectionDomain_name, "getProtectionDomain") \
|
||||
template(getProtectionDomain_signature, "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \
|
||||
template(java_lang_Integer_array_signature, "[Ljava/lang/Integer;") \
|
||||
template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \
|
||||
template(module_entry_name, "module_entry") \
|
||||
template(resolved_references_name, "<resolved_references>") \
|
||||
|
@ -510,6 +510,7 @@ void HeapShared::archive_reachable_objects_from_static_field(Klass *k,
|
||||
archive_object_graph_do(SystemDictionary::ImmutableCollections_ListN_klass(), java_util_ImmutableCollections_ListN::EMPTY_LIST_offset(), T_OBJECT, CHECK); \
|
||||
archive_object_graph_do(SystemDictionary::ImmutableCollections_MapN_klass(), java_util_ImmutableCollections_MapN::EMPTY_MAP_offset(), T_OBJECT, CHECK); \
|
||||
archive_object_graph_do(SystemDictionary::ImmutableCollections_SetN_klass(), java_util_ImmutableCollections_SetN::EMPTY_SET_offset(), T_OBJECT, CHECK); \
|
||||
archive_object_graph_do(SystemDictionary::Integer_IntegerCache_klass(), java_lang_Integer_IntegerCache::archivedCache_offset(), T_OBJECT, CHECK); \
|
||||
archive_object_graph_do(SystemDictionary::Configuration_klass(), java_lang_module_Configuration::EMPTY_CONFIGURATION_offset(), T_OBJECT, CHECK)
|
||||
|
||||
void HeapShared::archive_module_graph_objects(Thread* THREAD) {
|
||||
|
@ -997,7 +997,8 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
private static class IntegerCache {
|
||||
static final int low = -128;
|
||||
static final int high;
|
||||
static final Integer cache[];
|
||||
static final Integer[] cache;
|
||||
static Integer[] archivedCache;
|
||||
|
||||
static {
|
||||
// high value may be configured by property
|
||||
@ -1016,11 +1017,19 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
}
|
||||
high = h;
|
||||
|
||||
cache = new Integer[(high - low) + 1];
|
||||
int j = low;
|
||||
for(int k = 0; k < cache.length; k++)
|
||||
cache[k] = new Integer(j++);
|
||||
// Load IntegerCache.archivedCache from archive, if possible
|
||||
VM.initializeFromArchive(IntegerCache.class);
|
||||
int size = (high - low) + 1;
|
||||
|
||||
// Use the archived cache if it exists and is large enough
|
||||
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++);
|
||||
archivedCache = c;
|
||||
}
|
||||
cache = archivedCache;
|
||||
// range [-128, 127] must be interned (JLS7 5.1.7)
|
||||
assert IntegerCache.high >= 127;
|
||||
}
|
||||
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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
|
||||
* @summary Test IntegerCache integrity in various scenarios
|
||||
* @requires vm.cds.archived.java.heap
|
||||
* @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* jdk.jartool/sun.tools.jar
|
||||
* @build sun.hotspot.WhiteBox
|
||||
* @compile CheckIntegerCacheApp.java
|
||||
* @run driver ClassFileInstaller -jar integer.jar CheckIntegerCacheApp
|
||||
* @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
|
||||
* @run main ArchivedIntegerCacheTest
|
||||
*/
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
public class ArchivedIntegerCacheTest {
|
||||
|
||||
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");
|
||||
|
||||
Path userDir = Paths.get(System.getProperty("user.dir"));
|
||||
Path moduleDir = Files.createTempDirectory(userDir, "mods");
|
||||
|
||||
//
|
||||
// Dump default archive
|
||||
//
|
||||
OutputAnalyzer output = TestCommon.dump(appJar,
|
||||
TestCommon.list("CheckIntegerCacheApp"),
|
||||
use_whitebox_jar);
|
||||
TestCommon.checkDump(output);
|
||||
|
||||
// Test case 1)
|
||||
// - Default options
|
||||
System.out.println("----------------------- Test case 1 ----------------------");
|
||||
output = TestCommon.exec(appJar, use_whitebox_jar,
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"CheckIntegerCacheApp",
|
||||
"127",
|
||||
"true");
|
||||
TestCommon.checkExec(output);
|
||||
|
||||
// Test case 2)
|
||||
// - Default archive
|
||||
// - Larger -XX:AutoBoxCacheMax
|
||||
System.out.println("----------------------- Test case 2 ----------------------");
|
||||
output = TestCommon.exec(appJar, use_whitebox_jar,
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-XX:AutoBoxCacheMax=20000",
|
||||
"CheckIntegerCacheApp",
|
||||
"20000",
|
||||
"false");
|
||||
TestCommon.checkExec(output);
|
||||
|
||||
//
|
||||
// Dump with -XX:AutoBoxCacheMax specified
|
||||
//
|
||||
output = TestCommon.dump(appJar,
|
||||
TestCommon.list("CheckIntegerCacheApp"),
|
||||
"-XX:AutoBoxCacheMax=20000",
|
||||
use_whitebox_jar);
|
||||
TestCommon.checkDump(output);
|
||||
|
||||
// Test case 3)
|
||||
// - Large archived cache
|
||||
// - Default options
|
||||
System.out.println("----------------------- Test case 3 ----------------------");
|
||||
output = TestCommon.exec(appJar, use_whitebox_jar,
|
||||
"--module-path",
|
||||
moduleDir.toString(),
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"CheckIntegerCacheApp",
|
||||
"127",
|
||||
"true");
|
||||
TestCommon.checkExec(output);
|
||||
|
||||
|
||||
// Test case 4)
|
||||
// - Large archived cache
|
||||
// - Matching options
|
||||
System.out.println("----------------------- Test case 4 ----------------------");
|
||||
output = TestCommon.exec(appJar, use_whitebox_jar,
|
||||
"--module-path",
|
||||
moduleDir.toString(),
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-XX:AutoBoxCacheMax=20000",
|
||||
"CheckIntegerCacheApp",
|
||||
"20000",
|
||||
"true");
|
||||
TestCommon.checkExec(output);
|
||||
|
||||
// Test case 5)
|
||||
// - Large archived cache
|
||||
// - Larger requested cache
|
||||
System.out.println("----------------------- Test case 5 ----------------------");
|
||||
output = TestCommon.exec(appJar, use_whitebox_jar,
|
||||
"--module-path",
|
||||
moduleDir.toString(),
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-XX:AutoBoxCacheMax=30000",
|
||||
"CheckIntegerCacheApp",
|
||||
"30000",
|
||||
"false");
|
||||
TestCommon.checkExec(output);
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
//
|
||||
// Help test archived integer cache consistency.
|
||||
//
|
||||
// Takes two arguments:
|
||||
// 0: the expected AutoBoxCacheMax setting
|
||||
// 1: if the values are expected to be retrieved from the archive or not
|
||||
//
|
||||
public class CheckIntegerCacheApp {
|
||||
static WhiteBox wb;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
wb = WhiteBox.getWhiteBox();
|
||||
|
||||
if (!wb.areOpenArchiveHeapObjectsMapped()) {
|
||||
System.out.println("This may happen during normal operation. Test Skipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length != 2) {
|
||||
throw new RuntimeException(
|
||||
"FAILED. Incorrect argument length: " + args.length);
|
||||
}
|
||||
|
||||
boolean archivedExpected = Boolean.parseBoolean(args[1]);
|
||||
|
||||
// Base JLS compliance check
|
||||
for (int i = -128; i <= 127; i++) {
|
||||
if (Integer.valueOf(i) != Integer.valueOf(i)) {
|
||||
throw new RuntimeException(
|
||||
"FAILED. All values in range [-128, 127] should be interned in cache: " + i);
|
||||
}
|
||||
checkArchivedAsExpected(archivedExpected, i);
|
||||
}
|
||||
|
||||
int high = Integer.parseInt(args[0]);
|
||||
if (Integer.valueOf(high) != Integer.valueOf(high)) {
|
||||
throw new RuntimeException(
|
||||
"FAILED. Value expected to be retrieved from cache: " + high);
|
||||
}
|
||||
checkArchivedAsExpected(archivedExpected, Integer.valueOf(high));
|
||||
|
||||
if (Integer.valueOf(high + 1) == Integer.valueOf(high + 1)) {
|
||||
throw new RuntimeException(
|
||||
"FAILED. Value not expected to be retrieved from cache: " + high);
|
||||
}
|
||||
checkArchivedAsExpected(false, Integer.valueOf(high + 1));
|
||||
}
|
||||
|
||||
private static void checkArchivedAsExpected(boolean archivedExpected, Integer value) {
|
||||
if (archivedExpected) {
|
||||
if (!wb.isShared(Integer.valueOf(value))) {
|
||||
throw new RuntimeException(
|
||||
"FAILED. Value expected to be archived: " + value);
|
||||
}
|
||||
} else {
|
||||
if (wb.isShared(Integer.valueOf(value))) {
|
||||
throw new RuntimeException(
|
||||
"FAILED. Value not expected to be archived: " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user