mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-15 08:34:30 +02:00
8209120: Archive the Integer.IntegerCache
Reviewed-by: jiangli, alanb, plevart, iklam, mchung
This commit is contained in:
parent
8044814e30
commit
5c3008fbc4
8 changed files with 272 additions and 5 deletions
|
@ -4251,6 +4251,7 @@ int jdk_internal_module_ArchivedModuleGraph::_archivedSystemModules_offset;
|
||||||
int jdk_internal_module_ArchivedModuleGraph::_archivedModuleFinder_offset;
|
int jdk_internal_module_ArchivedModuleGraph::_archivedModuleFinder_offset;
|
||||||
int jdk_internal_module_ArchivedModuleGraph::_archivedMainModule_offset;
|
int jdk_internal_module_ArchivedModuleGraph::_archivedMainModule_offset;
|
||||||
int jdk_internal_module_ArchivedModuleGraph::_archivedConfiguration_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_lang_module_Configuration::_EMPTY_CONFIGURATION_offset;
|
||||||
int java_util_ImmutableCollections_ListN::_EMPTY_LIST_offset;
|
int java_util_ImmutableCollections_ListN::_EMPTY_LIST_offset;
|
||||||
int java_util_ImmutableCollections_SetN::_EMPTY_SET_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();
|
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) \
|
#define ARCHIVEDMODULEGRAPH_FIELDS_DO(macro) \
|
||||||
macro(_archivedSystemModules_offset, k, "archivedSystemModules", systemModules_signature, true); \
|
macro(_archivedSystemModules_offset, k, "archivedSystemModules", systemModules_signature, true); \
|
||||||
macro(_archivedModuleFinder_offset, k, "archivedModuleFinder", moduleFinder_signature, true); \
|
macro(_archivedModuleFinder_offset, k, "archivedModuleFinder", moduleFinder_signature, true); \
|
||||||
|
@ -4553,6 +4569,7 @@ void JavaClasses::compute_offsets() {
|
||||||
java_lang_LiveStackFrameInfo::compute_offsets();
|
java_lang_LiveStackFrameInfo::compute_offsets();
|
||||||
java_util_concurrent_locks_AbstractOwnableSynchronizer::compute_offsets();
|
java_util_concurrent_locks_AbstractOwnableSynchronizer::compute_offsets();
|
||||||
|
|
||||||
|
java_lang_Integer_IntegerCache::compute_offsets();
|
||||||
java_lang_module_Configuration::compute_offsets();
|
java_lang_module_Configuration::compute_offsets();
|
||||||
java_util_ImmutableCollections_ListN::compute_offsets();
|
java_util_ImmutableCollections_ListN::compute_offsets();
|
||||||
java_util_ImmutableCollections_MapN::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;
|
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 {
|
class jdk_internal_module_ArchivedModuleGraph: AllStatic {
|
||||||
private:
|
private:
|
||||||
static int _archivedSystemModules_offset;
|
static int _archivedSystemModules_offset;
|
||||||
|
|
|
@ -215,6 +215,7 @@ class OopStorage;
|
||||||
do_klass(Byte_klass, java_lang_Byte, Pre ) \
|
do_klass(Byte_klass, java_lang_Byte, Pre ) \
|
||||||
do_klass(Short_klass, java_lang_Short, Pre ) \
|
do_klass(Short_klass, java_lang_Short, Pre ) \
|
||||||
do_klass(Integer_klass, java_lang_Integer, 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 ) \
|
do_klass(Long_klass, java_lang_Long, Pre ) \
|
||||||
\
|
\
|
||||||
/* JVMCI classes. These are loaded on-demand. */ \
|
/* JVMCI classes. These are loaded on-demand. */ \
|
||||||
|
|
|
@ -438,6 +438,7 @@
|
||||||
template(fileToEncodedURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \
|
template(fileToEncodedURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \
|
||||||
template(getProtectionDomain_name, "getProtectionDomain") \
|
template(getProtectionDomain_name, "getProtectionDomain") \
|
||||||
template(getProtectionDomain_signature, "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \
|
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(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \
|
||||||
template(module_entry_name, "module_entry") \
|
template(module_entry_name, "module_entry") \
|
||||||
template(resolved_references_name, "<resolved_references>") \
|
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_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_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::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)
|
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) {
|
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 {
|
private static class IntegerCache {
|
||||||
static final int low = -128;
|
static final int low = -128;
|
||||||
static final int high;
|
static final int high;
|
||||||
static final Integer cache[];
|
static final Integer[] cache;
|
||||||
|
static Integer[] archivedCache;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// high value may be configured by property
|
// high value may be configured by property
|
||||||
|
@ -1016,11 +1017,19 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||||
}
|
}
|
||||||
high = h;
|
high = h;
|
||||||
|
|
||||||
cache = new Integer[(high - low) + 1];
|
// Load IntegerCache.archivedCache from archive, if possible
|
||||||
int j = low;
|
VM.initializeFromArchive(IntegerCache.class);
|
||||||
for(int k = 0; k < cache.length; k++)
|
int size = (high - low) + 1;
|
||||||
cache[k] = new Integer(j++);
|
|
||||||
|
|
||||||
|
// 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)
|
// range [-128, 127] must be interned (JLS7 5.1.7)
|
||||||
assert IntegerCache.high >= 127;
|
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…
Add table
Add a link
Reference in a new issue