mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
8373392: Replace CDS object subgraphs with @AOTSafeClassInitializer
Reviewed-by: liach, heidinga
This commit is contained in:
parent
b3fab41460
commit
232b41b222
@ -145,7 +145,7 @@ void AOTArtifactFinder::find_artifacts() {
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
// Keep scanning until we discover no more class that need to be AOT-initialized.
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
if (CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
while (_pending_aot_inited_classes->length() > 0) {
|
||||
InstanceKlass* ik = _pending_aot_inited_classes->pop();
|
||||
HeapShared::copy_and_rescan_aot_inited_mirror(ik);
|
||||
@ -188,7 +188,7 @@ void AOTArtifactFinder::end_scanning_for_oops() {
|
||||
}
|
||||
|
||||
void AOTArtifactFinder::add_aot_inited_class(InstanceKlass* ik) {
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
if (CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
if (RegeneratedClasses::is_regenerated_object(ik)) {
|
||||
precond(RegeneratedClasses::get_original_object(ik)->is_initialized());
|
||||
} else {
|
||||
@ -258,7 +258,7 @@ void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) {
|
||||
return;
|
||||
}
|
||||
scan_oops_in_instance_class(ik);
|
||||
if (ik->is_hidden() && CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
if (ik->is_hidden() && CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
bool succeed = AOTClassLinker::try_add_candidate(ik);
|
||||
guarantee(succeed, "All cached hidden classes must be aot-linkable");
|
||||
add_aot_inited_class(ik);
|
||||
|
||||
@ -40,7 +40,7 @@ DEBUG_ONLY(InstanceKlass* _aot_init_class = nullptr;)
|
||||
|
||||
bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
|
||||
assert(!ArchiveBuilder::is_active() || !ArchiveBuilder::current()->is_in_buffer_space(ik), "must be source klass");
|
||||
if (!CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
if (!CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
|
||||
// Automatic selection for aot-inited classes
|
||||
// ==========================================
|
||||
//
|
||||
// When CDSConfig::is_initing_classes_at_dump_time is enabled,
|
||||
// When CDSConfig::is_dumping_aot_linked_classes is enabled,
|
||||
// AOTArtifactFinder::find_artifacts() finds the classes of all
|
||||
// heap objects that are reachable from HeapShared::_run_time_special_subgraph,
|
||||
// and mark these classes as aot-inited. This preserves the initialized
|
||||
@ -310,7 +310,7 @@ void AOTClassInitializer::init_test_class(TRAPS) {
|
||||
//
|
||||
// -XX:AOTInitTestClass is NOT a general mechanism for including user-defined objects into
|
||||
// the AOT cache. Therefore, this option is NOT available in product JVM.
|
||||
if (AOTInitTestClass != nullptr && CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
if (AOTInitTestClass != nullptr && CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
log_info(aot)("Debug build only: force initialization of AOTInitTestClass %s", AOTInitTestClass);
|
||||
TempNewSymbol class_name = SymbolTable::new_symbol(AOTInitTestClass);
|
||||
Handle app_loader(THREAD, SystemDictionary::java_system_loader());
|
||||
|
||||
@ -1141,7 +1141,7 @@ void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS
|
||||
AOTReferenceObjSupport::initialize(CHECK);
|
||||
AOTReferenceObjSupport::stabilize_cached_reference_objects(CHECK);
|
||||
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
if (CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
// java.lang.Class::reflectionFactory cannot be archived yet. We set this field
|
||||
// to null, and it will be initialized again at runtime.
|
||||
log_debug(aot)("Resetting Class::reflectionFactory");
|
||||
|
||||
@ -1026,23 +1026,19 @@ void CDSConfig::set_has_aot_linked_classes(bool has_aot_linked_classes) {
|
||||
_has_aot_linked_classes |= has_aot_linked_classes;
|
||||
}
|
||||
|
||||
bool CDSConfig::is_initing_classes_at_dump_time() {
|
||||
return is_dumping_heap() && is_dumping_aot_linked_classes();
|
||||
}
|
||||
|
||||
bool CDSConfig::is_dumping_invokedynamic() {
|
||||
// Requires is_dumping_aot_linked_classes(). Otherwise the classes of some archived heap
|
||||
// objects used by the archive indy callsites may be replaced at runtime.
|
||||
return AOTInvokeDynamicLinking && is_dumping_aot_linked_classes() && is_dumping_heap();
|
||||
}
|
||||
|
||||
// When we are dumping aot-linked classes and we are able to write archived heap objects, we automatically
|
||||
// enable the archiving of MethodHandles. This will in turn enable the archiving of MethodTypes and hidden
|
||||
// When we are dumping aot-linked classes, we automatically enable the archiving of MethodHandles.
|
||||
// This will in turn enable the archiving of MethodTypes and hidden
|
||||
// classes that are used in the implementation of MethodHandles.
|
||||
// Archived MethodHandles are required for higher-level optimizations such as AOT resolution of invokedynamic
|
||||
// and dynamic proxies.
|
||||
bool CDSConfig::is_dumping_method_handles() {
|
||||
return is_initing_classes_at_dump_time();
|
||||
return is_dumping_aot_linked_classes();
|
||||
}
|
||||
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
@ -187,7 +187,6 @@ public:
|
||||
static void disable_heap_dumping() { CDS_ONLY(_disable_heap_dumping = true); }
|
||||
static bool is_dumping_heap() NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
static bool is_loading_heap() NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
static bool is_initing_classes_at_dump_time() NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
|
||||
static bool is_dumping_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
static bool is_dumping_method_handles() NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
|
||||
@ -40,7 +40,7 @@ bool CDSEnumKlass::is_enum_obj(oop orig_obj) {
|
||||
}
|
||||
|
||||
// !!! This is legacy support for enum classes before JEP 483. This file is not used when
|
||||
// !!! CDSConfig::is_initing_classes_at_dump_time()==true.
|
||||
// !!! CDSConfig::is_dumping_aot_linked_classes()==true.
|
||||
//
|
||||
// Java Enum classes have synthetic <clinit> methods that look like this
|
||||
// enum MyEnum {FOO, BAR}
|
||||
@ -63,7 +63,7 @@ bool CDSEnumKlass::is_enum_obj(oop orig_obj) {
|
||||
void CDSEnumKlass::handle_enum_obj(int level,
|
||||
KlassSubGraphInfo* subgraph_info,
|
||||
oop orig_obj) {
|
||||
assert(!CDSConfig::is_initing_classes_at_dump_time(), "only for legacy support of enums");
|
||||
assert(!CDSConfig::is_dumping_aot_linked_classes(), "only for legacy support of enums");
|
||||
assert(level > 1, "must never be called at the first (outermost) level");
|
||||
assert(is_enum_obj(orig_obj), "must be");
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ class JavaFieldStream;
|
||||
class KlassSubGraphInfo;
|
||||
|
||||
// This is legacy support for enum classes before JEP 483. This code is not needed when
|
||||
// CDSConfig::is_initing_classes_at_dump_time()==true.
|
||||
// CDSConfig::is_dumping_aot_linked_classes()==true.
|
||||
class CDSEnumKlass: AllStatic {
|
||||
public:
|
||||
static bool is_enum_obj(oop orig_obj);
|
||||
|
||||
@ -156,7 +156,7 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
|
||||
|
||||
# undef ADD_EXCL
|
||||
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
if (CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
add_shared_secret_accessors();
|
||||
}
|
||||
ClassLoaderDataGraph::classes_do(this);
|
||||
|
||||
@ -206,6 +206,8 @@ void FinalImageRecipes::load_all_classes(TRAPS) {
|
||||
|
||||
if (ik->has_aot_safe_initializer() && (flags & WAS_INITED) != 0) {
|
||||
assert(ik->class_loader() == nullptr, "supported only for boot classes for now");
|
||||
ResourceMark rm(THREAD);
|
||||
log_info(aot, init)("Initializing %s", ik->external_name());
|
||||
ik->initialize(CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,8 +209,14 @@ static bool is_subgraph_root_class_of(ArchivableStaticFieldInfo fields[], Instan
|
||||
}
|
||||
|
||||
bool HeapShared::is_subgraph_root_class(InstanceKlass* ik) {
|
||||
return is_subgraph_root_class_of(archive_subgraph_entry_fields, ik) ||
|
||||
is_subgraph_root_class_of(fmg_archive_subgraph_entry_fields, ik);
|
||||
assert(CDSConfig::is_dumping_heap(), "dump-time only");
|
||||
if (!CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
// Legacy CDS archive support (to be deprecated)
|
||||
return is_subgraph_root_class_of(archive_subgraph_entry_fields, ik) ||
|
||||
is_subgraph_root_class_of(fmg_archive_subgraph_entry_fields, ik);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
oop HeapShared::CachedOopInfo::orig_referrer() const {
|
||||
@ -934,12 +940,16 @@ void HeapShared::scan_java_class(Klass* orig_k) {
|
||||
void HeapShared::archive_subgraphs() {
|
||||
assert(CDSConfig::is_dumping_heap(), "must be");
|
||||
|
||||
archive_object_subgraphs(archive_subgraph_entry_fields,
|
||||
false /* is_full_module_graph */);
|
||||
if (!CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
archive_object_subgraphs(archive_subgraph_entry_fields,
|
||||
false /* is_full_module_graph */);
|
||||
if (CDSConfig::is_dumping_full_module_graph()) {
|
||||
archive_object_subgraphs(fmg_archive_subgraph_entry_fields,
|
||||
true /* is_full_module_graph */);
|
||||
}
|
||||
}
|
||||
|
||||
if (CDSConfig::is_dumping_full_module_graph()) {
|
||||
archive_object_subgraphs(fmg_archive_subgraph_entry_fields,
|
||||
true /* is_full_module_graph */);
|
||||
Modules::verify_archived_modules();
|
||||
}
|
||||
}
|
||||
@ -1295,8 +1305,10 @@ void HeapShared::resolve_classes(JavaThread* current) {
|
||||
if (!is_archived_heap_in_use()) {
|
||||
return; // nothing to do
|
||||
}
|
||||
resolve_classes_for_subgraphs(current, archive_subgraph_entry_fields);
|
||||
resolve_classes_for_subgraphs(current, fmg_archive_subgraph_entry_fields);
|
||||
if (!CDSConfig::is_using_aot_linked_classes()) {
|
||||
resolve_classes_for_subgraphs(current, archive_subgraph_entry_fields);
|
||||
resolve_classes_for_subgraphs(current, fmg_archive_subgraph_entry_fields);
|
||||
}
|
||||
}
|
||||
|
||||
void HeapShared::resolve_classes_for_subgraphs(JavaThread* current, ArchivableStaticFieldInfo fields[]) {
|
||||
@ -1734,13 +1746,13 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap
|
||||
}
|
||||
}
|
||||
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
if (CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
if (java_lang_Class::is_instance(orig_obj)) {
|
||||
orig_obj = scratch_java_mirror(orig_obj);
|
||||
assert(orig_obj != nullptr, "must be archived");
|
||||
}
|
||||
} else if (java_lang_Class::is_instance(orig_obj) && subgraph_info != _dump_time_special_subgraph) {
|
||||
// Without CDSConfig::is_initing_classes_at_dump_time(), we only allow archived objects to
|
||||
// Without CDSConfig::is_dumping_aot_linked_classes(), we only allow archived objects to
|
||||
// point to the mirrors of (1) j.l.Object, (2) primitive classes, and (3) box classes. These are initialized
|
||||
// very early by HeapShared::init_box_classes().
|
||||
if (orig_obj == vmClasses::Object_klass()->java_mirror()
|
||||
@ -1808,9 +1820,9 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap
|
||||
orig_obj->oop_iterate(&pusher);
|
||||
}
|
||||
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
// The classes of all archived enum instances have been marked as aot-init,
|
||||
// so there's nothing else to be done in the production run.
|
||||
if (CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
// The enum klasses are archived with aot-initialized mirror.
|
||||
// See AOTClassInitializer::can_archive_initialized_mirror().
|
||||
} else {
|
||||
// This is legacy support for enum classes before JEP 483 -- we cannot rerun
|
||||
// the enum's <clinit> in the production run, so special handling is needed.
|
||||
@ -1949,7 +1961,7 @@ void HeapShared::verify_reachable_objects_from(oop obj) {
|
||||
#endif
|
||||
|
||||
void HeapShared::check_special_subgraph_classes() {
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
if (CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
// We can have aot-initialized classes (such as Enums) that can reference objects
|
||||
// of arbitrary types. Currently, we trust the JEP 483 implementation to only
|
||||
// aot-initialize classes that are "safe".
|
||||
@ -2136,9 +2148,11 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
|
||||
void HeapShared::init_subgraph_entry_fields(TRAPS) {
|
||||
assert(CDSConfig::is_dumping_heap(), "must be");
|
||||
_dump_time_subgraph_info_table = new (mtClass)DumpTimeKlassSubGraphInfoTable();
|
||||
init_subgraph_entry_fields(archive_subgraph_entry_fields, CHECK);
|
||||
if (CDSConfig::is_dumping_full_module_graph()) {
|
||||
init_subgraph_entry_fields(fmg_archive_subgraph_entry_fields, CHECK);
|
||||
if (!CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
init_subgraph_entry_fields(archive_subgraph_entry_fields, CHECK);
|
||||
if (CDSConfig::is_dumping_full_module_graph()) {
|
||||
init_subgraph_entry_fields(fmg_archive_subgraph_entry_fields, CHECK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
package java.lang;
|
||||
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
@ -103,6 +104,7 @@ public final class Byte extends Number implements Comparable<Byte>, Constable {
|
||||
return Optional.of(DynamicConstantDesc.ofNamed(BSM_EXPLICIT_CAST, DEFAULT_NAME, CD_byte, intValue()));
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
private static final class ByteCache {
|
||||
private ByteCache() {}
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
package java.lang;
|
||||
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
@ -9379,6 +9380,7 @@ class Character implements java.io.Serializable, Comparable<Character>, Constabl
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
private static final class CharacterCache {
|
||||
private CharacterCache(){}
|
||||
|
||||
|
||||
@ -28,6 +28,8 @@ package java.lang;
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.util.DecimalDigits;
|
||||
import jdk.internal.vm.annotation.AOTRuntimeSetup;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
@ -891,15 +893,20 @@ public final class Integer extends Number
|
||||
* with new Integer object(s) after initialization.
|
||||
*/
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
private static final class IntegerCache {
|
||||
static final int low = -128;
|
||||
static final int high;
|
||||
@Stable static int high;
|
||||
|
||||
@Stable
|
||||
static final Integer[] cache;
|
||||
@Stable static Integer[] cache;
|
||||
static Integer[] archivedCache;
|
||||
|
||||
static {
|
||||
runtimeSetup();
|
||||
}
|
||||
|
||||
@AOTRuntimeSetup
|
||||
private static void runtimeSetup() {
|
||||
// high value may be configured by property
|
||||
int h = 127;
|
||||
String integerCacheHighPropValue =
|
||||
@ -915,34 +922,50 @@ public final class Integer extends Number
|
||||
}
|
||||
high = h;
|
||||
|
||||
// Load IntegerCache.archivedCache from archive, if possible
|
||||
CDS.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;
|
||||
// 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;
|
||||
Integer[] precomputed = null;
|
||||
if (cache != null) {
|
||||
// IntegerCache has been AOT-initialized.
|
||||
precomputed = cache;
|
||||
} else {
|
||||
// Legacy CDS archive support (to be deprecated):
|
||||
// Load IntegerCache.archivedCache from archive, if possible
|
||||
CDS.initializeFromArchive(IntegerCache.class);
|
||||
precomputed = archivedCache;
|
||||
}
|
||||
cache = archivedCache;
|
||||
|
||||
cache = loadOrInitializeCache(precomputed);
|
||||
archivedCache = cache; // Legacy CDS archive support (to be deprecated)
|
||||
// range [-128, 127] must be interned (JLS7 5.1.7)
|
||||
assert IntegerCache.high >= 127;
|
||||
}
|
||||
|
||||
private static Integer[] loadOrInitializeCache(Integer[] precomputed) {
|
||||
int size = (high - low) + 1;
|
||||
|
||||
// Use the precomputed cache if it exists and is large enough
|
||||
if (precomputed != null && size <= precomputed.length) {
|
||||
return precomputed;
|
||||
}
|
||||
|
||||
Integer[] c = new Integer[size];
|
||||
int j = low;
|
||||
// If we loading a precomputed cache (from AOT cache or CDS archive),
|
||||
// we must use all instances from it.
|
||||
// Otherwise, the Integers from the AOT cache (or CDS archive) will not
|
||||
// have the same object identity as items in IntegerCache.cache[].
|
||||
int precomputedSize = (precomputed == null) ? 0 : precomputed.length;
|
||||
for (int i = 0; i < precomputedSize; i++) {
|
||||
c[i] = precomputed[i];
|
||||
assert j == precomputed[i];
|
||||
j++;
|
||||
}
|
||||
// Fill the rest of the cache.
|
||||
for (int i = precomputedSize; i < size; i++) {
|
||||
c[i] = new Integer(j++);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private IntegerCache() {}
|
||||
}
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@ import java.util.Optional;
|
||||
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.util.DecimalDigits;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
@ -911,6 +912,7 @@ public final class Long extends Number
|
||||
return Long.valueOf(parseLong(s, 10));
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
private static final class LongCache {
|
||||
private LongCache() {}
|
||||
|
||||
|
||||
@ -69,6 +69,7 @@ import jdk.internal.module.ServicesCatalog;
|
||||
import jdk.internal.module.Resources;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
/**
|
||||
@ -391,6 +392,7 @@ public final class Module implements AnnotatedElement {
|
||||
private static final Module EVERYONE_MODULE;
|
||||
private static final Set<Module> EVERYONE_SET;
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
private static class ArchivedData {
|
||||
private static ArchivedData archivedData;
|
||||
private final Module allUnnamedModule;
|
||||
|
||||
@ -53,6 +53,7 @@ import jdk.internal.module.ServicesCatalog;
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
/**
|
||||
@ -145,6 +146,7 @@ import jdk.internal.vm.annotation.Stable;
|
||||
* @see Module#getLayer()
|
||||
*/
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
public final class ModuleLayer {
|
||||
|
||||
// the empty layer (may be initialized from the CDS archive)
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
package java.lang;
|
||||
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
@ -230,6 +231,7 @@ public final class Short extends Number implements Comparable<Short>, Constable
|
||||
return Optional.of(DynamicConstantDesc.ofNamed(BSM_EXPLICIT_CAST, DEFAULT_NAME, CD_short, intValue()));
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
private static final class ShortCache {
|
||||
private ShortCache() {}
|
||||
|
||||
|
||||
@ -44,6 +44,7 @@ import java.util.stream.Stream;
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.module.ModuleReferenceImpl;
|
||||
import jdk.internal.module.ModuleTarget;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
/**
|
||||
@ -155,6 +156,7 @@ import jdk.internal.vm.annotation.Stable;
|
||||
* @since 9
|
||||
* @see java.lang.ModuleLayer
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public final class Configuration {
|
||||
|
||||
// @see Configuration#empty()
|
||||
|
||||
@ -42,6 +42,9 @@ import java.util.function.UnaryOperator;
|
||||
import jdk.internal.access.JavaUtilCollectionAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.vm.annotation.AOTRuntimeSetup;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
/**
|
||||
@ -52,6 +55,7 @@ import jdk.internal.vm.annotation.Stable;
|
||||
* classes use a serial proxy and thus have no need to declare serialVersionUID.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
@AOTSafeClassInitializer
|
||||
class ImmutableCollections {
|
||||
/**
|
||||
* A "salt" value used for randomizing iteration order. This is initialized once
|
||||
@ -59,14 +63,20 @@ class ImmutableCollections {
|
||||
* it needs to vary sufficiently from one run to the next so that iteration order
|
||||
* will vary between JVM runs.
|
||||
*/
|
||||
private static final long SALT32L;
|
||||
@Stable private static long SALT32L;
|
||||
|
||||
/**
|
||||
* For set and map iteration, we will iterate in "reverse" stochastically,
|
||||
* decided at bootstrap time.
|
||||
*/
|
||||
private static final boolean REVERSE;
|
||||
@Stable private static boolean REVERSE;
|
||||
|
||||
static {
|
||||
runtimeSetup();
|
||||
}
|
||||
|
||||
@AOTRuntimeSetup
|
||||
private static void runtimeSetup() {
|
||||
// to generate a reasonably random and well-mixed SALT, use an arbitrary
|
||||
// value (a slice of pi), multiply with a random seed, then pick
|
||||
// the mid 32-bits from the product. By picking a SALT value in the
|
||||
@ -102,6 +112,7 @@ class ImmutableCollections {
|
||||
static final MapN<?,?> EMPTY_MAP;
|
||||
|
||||
static {
|
||||
// Legacy CDS archive support (to be deprecated)
|
||||
CDS.initializeFromArchive(ImmutableCollections.class);
|
||||
if (archivedObjects == null) {
|
||||
EMPTY = new Object();
|
||||
|
||||
@ -36,6 +36,7 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import sun.nio.cs.UTF_8;
|
||||
@ -60,6 +61,7 @@ import sun.util.logging.PlatformLogger;
|
||||
* @see Manifest
|
||||
* @since 1.2
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public class Attributes implements Map<Object,Object>, Cloneable {
|
||||
/**
|
||||
* The attribute name-value mappings.
|
||||
@ -450,6 +452,7 @@ public class Attributes implements Map<Object,Object>, Cloneable {
|
||||
*
|
||||
* @spec jar/jar.html JAR File Specification
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public static class Name {
|
||||
private final String name;
|
||||
private final int hashCode;
|
||||
@ -669,6 +672,7 @@ public class Attributes implements Map<Object,Object>, Cloneable {
|
||||
|
||||
static {
|
||||
|
||||
// Legacy CDS archive support (to be deprecated)
|
||||
CDS.initializeFromArchive(Attributes.Name.class);
|
||||
|
||||
if (KNOWN_NAMES == null) {
|
||||
|
||||
@ -27,11 +27,13 @@ package jdk.internal.loader;
|
||||
import java.util.Map;
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.module.ServicesCatalog;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
|
||||
/**
|
||||
* Used to archive the built-in class loaders, their services catalogs, and the
|
||||
* package-to-module map used by the built-in class loaders.
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
class ArchivedClassLoaders {
|
||||
private static ArchivedClassLoaders archivedClassLoaders;
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
package jdk.internal.math;
|
||||
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -33,6 +34,7 @@ import java.util.Arrays;
|
||||
/**
|
||||
* A simple big integer class specifically for floating point base conversion.
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
final class FDBigInteger {
|
||||
|
||||
@Stable
|
||||
@ -53,6 +55,7 @@ final class FDBigInteger {
|
||||
|
||||
// Initialize FDBigInteger cache of powers of 5.
|
||||
static {
|
||||
// Legacy CDS archive support (to be deprecated)
|
||||
CDS.initializeFromArchive(FDBigInteger.class);
|
||||
Object[] caches = archivedCaches;
|
||||
if (caches == null) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2025, 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
|
||||
@ -25,10 +25,12 @@
|
||||
package jdk.internal.module;
|
||||
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
|
||||
/**
|
||||
* Used by ModuleBootstrap for archiving the boot layer.
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
class ArchivedBootLayer {
|
||||
private static ArchivedBootLayer archivedBootLayer;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2025, 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
|
||||
@ -30,11 +30,13 @@ import java.util.function.Function;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
|
||||
/**
|
||||
* Used by ModuleBootstrap for archiving the configuration for the boot layer,
|
||||
* and the system module finder.
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
class ArchivedModuleGraph {
|
||||
private static ArchivedModuleGraph archivedModuleGraph;
|
||||
|
||||
@ -126,6 +128,7 @@ class ArchivedModuleGraph {
|
||||
}
|
||||
|
||||
static {
|
||||
// Legacy CDS archive support (to be deprecated)
|
||||
CDS.initializeFromArchive(ArchivedModuleGraph.class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,11 +34,14 @@ package sun.util.locale;
|
||||
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.util.ReferencedKeySet;
|
||||
import jdk.internal.vm.annotation.AOTRuntimeSetup;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
public final class BaseLocale {
|
||||
|
||||
public static @Stable BaseLocale[] constantBaseLocales;
|
||||
@ -63,6 +66,7 @@ public final class BaseLocale {
|
||||
CANADA_FRENCH = 18,
|
||||
NUM_CONSTANTS = 19;
|
||||
static {
|
||||
// Legacy CDS archive support (to be deprecated)
|
||||
CDS.initializeFromArchive(BaseLocale.class);
|
||||
BaseLocale[] baseLocales = constantBaseLocales;
|
||||
if (baseLocales == null) {
|
||||
@ -91,13 +95,21 @@ public final class BaseLocale {
|
||||
}
|
||||
|
||||
// Interned BaseLocale cache
|
||||
private static final LazyConstant<ReferencedKeySet<BaseLocale>> CACHE =
|
||||
@Stable private static LazyConstant<ReferencedKeySet<BaseLocale>> CACHE;
|
||||
static {
|
||||
runtimeSetup();
|
||||
}
|
||||
|
||||
@AOTRuntimeSetup
|
||||
private static void runtimeSetup() {
|
||||
CACHE =
|
||||
LazyConstant.of(new Supplier<>() {
|
||||
@Override
|
||||
public ReferencedKeySet<BaseLocale> get() {
|
||||
return ReferencedKeySet.create(true, ReferencedKeySet.concurrentHashMapSupplier());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static final String SEP = "_";
|
||||
|
||||
|
||||
@ -522,6 +522,7 @@ hotspot_aot_classlinking = \
|
||||
-runtime/cds/appcds/aotFlags \
|
||||
-runtime/cds/appcds/aotProfile \
|
||||
-runtime/cds/appcds/BadBSM.java \
|
||||
-runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java \
|
||||
-runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java \
|
||||
-runtime/cds/appcds/cacheObject/ArchivedModuleCompareTest.java \
|
||||
-runtime/cds/appcds/CDSandJFR.java \
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2025, 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,8 @@
|
||||
* java.management
|
||||
*/
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import jdk.test.lib.cds.CDSTestUtils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
@ -43,8 +45,44 @@ public class SharedSymbolTableBucketSize {
|
||||
+ Integer.valueOf(bucket_size));
|
||||
CDSTestUtils.checkMappingFailure(output);
|
||||
|
||||
String regex = "Average bucket size : ([0-9]+\\.[0-9]+).*";
|
||||
String s = output.firstMatch(regex, 1);
|
||||
/* [1] There may be other table stats that precede the symbol tabble.
|
||||
Skip all thse until we find this:
|
||||
|
||||
[0.677s][info][aot,hashtables] Shared symbol table stats -------- base: 0x0000000800000000
|
||||
[0.677s][info][aot,hashtables] Number of entries : 46244
|
||||
[0.677s][info][aot,hashtables] Total bytes used : 393792
|
||||
[0.677s][info][aot,hashtables] Average bytes per entry : 8.516
|
||||
[0.677s][info][aot,hashtables] Average bucket size : 7.734
|
||||
[0.677s][info][aot,hashtables] Variance of bucket size : 7.513
|
||||
[0.677s][info][aot,hashtables] Std. dev. of bucket size: 2.741
|
||||
[0.677s][info][aot,hashtables] Maximum bucket size : 20
|
||||
[0.677s][info][aot,hashtables] Empty buckets : 2
|
||||
[0.677s][info][aot,hashtables] Value_Only buckets : 24
|
||||
[0.677s][info][aot,hashtables] Other buckets : 5953
|
||||
....
|
||||
*/
|
||||
Pattern pattern0 = Pattern.compile("Shared symbol table stats.*", Pattern.DOTALL);
|
||||
Matcher matcher0 = pattern0.matcher(output.getStdout());
|
||||
String stat = null;
|
||||
if (matcher0.find()) {
|
||||
stat = matcher0.group(0);
|
||||
}
|
||||
if (stat == null) {
|
||||
throw new Exception("FAILED: pattern \"" + pattern0 + "\" not found");
|
||||
}
|
||||
|
||||
/* (2) The first "Average bucket size" line in the remaining output is for the
|
||||
shared symbol table */
|
||||
Pattern pattern = Pattern.compile("Average bucket size *: *([0-9]+\\.[0-9]+).*", Pattern.MULTILINE);
|
||||
Matcher matcher = pattern.matcher(stat);
|
||||
String s = null;
|
||||
if (matcher.find()) {
|
||||
s = matcher.group(1);
|
||||
}
|
||||
if (s == null) {
|
||||
throw new Exception("FAILED: pattern \"" + pattern + "\" not found");
|
||||
}
|
||||
|
||||
Float f = Float.parseFloat(s);
|
||||
int size = Math.round(f);
|
||||
if (size != bucket_size) {
|
||||
|
||||
@ -83,17 +83,6 @@ public class AOTLoggingTag {
|
||||
out.shouldContain("[aot] Opened AOT cache hello.aot");
|
||||
out.shouldHaveExitValue(0);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
printTestCase("All old -Xlog:cds+heap logs have been changed to -Xlog:aot+heap should alias to -Xlog:cds+heap");
|
||||
pb = ProcessTools.createLimitedTestJavaProcessBuilder(
|
||||
"-XX:AOTCache=" + aotCacheFile,
|
||||
"-Xlog:aot+heap",
|
||||
"-cp", appJar, helloClass);
|
||||
out = CDSTestUtils.executeAndLog(pb, "prod");
|
||||
out.shouldNotContain("No tag set matches selection: aot+heap");
|
||||
out.shouldContain("[aot,heap] resolve subgraph java.lang.Integer$IntegerCache");
|
||||
out.shouldHaveExitValue(0);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
printTestCase("Production Run: errors should be printed with [aot] decoration");
|
||||
pb = ProcessTools.createLimitedTestJavaProcessBuilder(
|
||||
|
||||
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 AOT cache should preserve heap object identity when required by JLS. For example, Enums and Integers.
|
||||
* @requires vm.cds
|
||||
* @requires vm.cds.supports.aot.class.linking
|
||||
* @requires vm.debug
|
||||
* @library /test/lib
|
||||
* @build HeapObjectIdentity
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar dummy.jar
|
||||
* Dummy
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boot.jar
|
||||
* HeapObjectIdentityApp
|
||||
* MyAOTInitedClass
|
||||
* MyAOTInitedClass$MyEnum
|
||||
* MyAOTInitedClass$Wrapper
|
||||
* @run driver HeapObjectIdentity AOT --two-step-training
|
||||
*/
|
||||
|
||||
import jdk.test.lib.cds.CDSAppTester;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.helpers.ClassFileInstaller;
|
||||
|
||||
public class HeapObjectIdentity {
|
||||
static final String appJar = ClassFileInstaller.getJarPath("dummy.jar");
|
||||
static final String bootJar = ClassFileInstaller.getJarPath("boot.jar");
|
||||
static final String mainClass = "HeapObjectIdentityApp"; // Loaded from boot.jar
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Tester t = new Tester();
|
||||
t.run(args);
|
||||
|
||||
// Integer$IntegerCache should preserve the object identity of cached Integer objects,
|
||||
// even when the cache size is different between assembly and production.
|
||||
t.productionRun(new String[] {
|
||||
"-XX:AutoBoxCacheMax=2048"
|
||||
});
|
||||
}
|
||||
|
||||
static class Tester extends CDSAppTester {
|
||||
public Tester() {
|
||||
super(mainClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String classpath(RunMode runMode) {
|
||||
return appJar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] vmArgs(RunMode runMode) {
|
||||
String bootcp = "-Xbootclasspath/a:" + bootJar;
|
||||
if (runMode == RunMode.ASSEMBLY) {
|
||||
return new String[] {
|
||||
"-Xlog:aot+class=debug",
|
||||
"-XX:AOTInitTestClass=MyAOTInitedClass",
|
||||
bootcp
|
||||
};
|
||||
} else {
|
||||
return new String[] {bootcp};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] appCommandLine(RunMode runMode) {
|
||||
return new String[] {
|
||||
mainClass,
|
||||
runMode.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {
|
||||
if (runMode == RunMode.ASSEMBLY) {
|
||||
out.shouldContain("MyAOTInitedClass aot-linked inited");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HeapObjectIdentityApp {
|
||||
public static void main(String... args) {
|
||||
MyAOTInitedClass.test();
|
||||
}
|
||||
}
|
||||
|
||||
// This class is loaded by the boot loader, as -XX:AOTInitTestClass is not too friendly
|
||||
// with classes by other loaders.
|
||||
class MyAOTInitedClass {
|
||||
static Object[] archivedObjects;
|
||||
static {
|
||||
if (archivedObjects == null) {
|
||||
archivedObjects = new Object[14];
|
||||
archivedObjects[0] = Wrapper.BOOLEAN;
|
||||
archivedObjects[1] = Wrapper.INT.zero();
|
||||
archivedObjects[2] = Wrapper.DOUBLE.zero();
|
||||
archivedObjects[3] = MyEnum.DUMMY1;
|
||||
|
||||
archivedObjects[4] = Boolean.class;
|
||||
archivedObjects[5] = Byte.class;
|
||||
archivedObjects[6] = Character.class;
|
||||
archivedObjects[7] = Short.class;
|
||||
archivedObjects[8] = Integer.class;
|
||||
archivedObjects[9] = Long.class;
|
||||
archivedObjects[10] = Float.class;
|
||||
archivedObjects[11] = Double.class;
|
||||
archivedObjects[12] = Void.class;
|
||||
|
||||
archivedObjects[13] = Integer.valueOf(1);
|
||||
} else {
|
||||
System.out.println("Initialized from CDS");
|
||||
}
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
if (archivedObjects[0] != Wrapper.BOOLEAN) {
|
||||
throw new RuntimeException("Huh 0");
|
||||
}
|
||||
|
||||
if (archivedObjects[1] != Wrapper.INT.zero()) {
|
||||
throw new RuntimeException("Huh 1");
|
||||
}
|
||||
|
||||
if (archivedObjects[2] != Wrapper.DOUBLE.zero()) {
|
||||
throw new RuntimeException("Huh 2");
|
||||
}
|
||||
|
||||
if (archivedObjects[3] != MyEnum.DUMMY1) {
|
||||
throw new RuntimeException("Huh 3");
|
||||
}
|
||||
|
||||
if (MyEnum.BOOLEAN != true) {
|
||||
throw new RuntimeException("Huh 10.1");
|
||||
}
|
||||
if (MyEnum.BYTE != -128) {
|
||||
throw new RuntimeException("Huh 10.2");
|
||||
}
|
||||
if (MyEnum.CHAR != 'c') {
|
||||
throw new RuntimeException("Huh 10.3");
|
||||
}
|
||||
if (MyEnum.SHORT != -12345) {
|
||||
throw new RuntimeException("Huh 10.4");
|
||||
}
|
||||
if (MyEnum.INT != -123456) {
|
||||
throw new RuntimeException("Huh 10.5");
|
||||
}
|
||||
if (MyEnum.LONG != 0x1234567890L) {
|
||||
throw new RuntimeException("Huh 10.6");
|
||||
}
|
||||
if (MyEnum.LONG2 != -0x1234567890L) {
|
||||
throw new RuntimeException("Huh 10.7");
|
||||
}
|
||||
if (MyEnum.FLOAT != 567891.0f) {
|
||||
throw new RuntimeException("Huh 10.8");
|
||||
}
|
||||
if (MyEnum.DOUBLE != 12345678905678.890) {
|
||||
throw new RuntimeException("Huh 10.9");
|
||||
}
|
||||
|
||||
checkClass(4, Boolean.class);
|
||||
checkClass(5, Byte.class);
|
||||
checkClass(6, Character.class);
|
||||
checkClass(7, Short.class);
|
||||
checkClass(8, Integer.class);
|
||||
checkClass(9, Long.class);
|
||||
checkClass(10, Float.class);
|
||||
checkClass(11, Double.class);
|
||||
checkClass(12, Void.class);
|
||||
|
||||
if (archivedObjects[13] != Integer.valueOf(1)) {
|
||||
throw new RuntimeException("Integer cache identity test failed");
|
||||
}
|
||||
|
||||
System.out.println("Success!");
|
||||
}
|
||||
|
||||
static void checkClass(int index, Class c) {
|
||||
if (archivedObjects[index] != c) {
|
||||
throw new RuntimeException("archivedObjects[" + index + "] should be " + c);
|
||||
}
|
||||
}
|
||||
|
||||
// Simplified version of sun.invoke.util.Wrapper
|
||||
public enum Wrapper {
|
||||
// wrapperType simple primitiveType simple char emptyArray
|
||||
BOOLEAN( Boolean.class, "Boolean", boolean.class, "boolean", 'Z', new boolean[0]),
|
||||
INT ( Integer.class, "Integer", int.class, "int", 'I', new int[0]),
|
||||
DOUBLE ( Double.class, "Double", double.class, "double", 'D', new double[0])
|
||||
;
|
||||
|
||||
public static final int COUNT = 10;
|
||||
private static final Object DOUBLE_ZERO = (Double)(double)0;
|
||||
|
||||
private final Class<?> wrapperType;
|
||||
private final Class<?> primitiveType;
|
||||
private final char basicTypeChar;
|
||||
private final String basicTypeString;
|
||||
private final Object emptyArray;
|
||||
|
||||
Wrapper(Class<?> wtype,
|
||||
String wtypeName,
|
||||
Class<?> ptype,
|
||||
String ptypeName,
|
||||
char tchar,
|
||||
Object emptyArray) {
|
||||
this.wrapperType = wtype;
|
||||
this.primitiveType = ptype;
|
||||
this.basicTypeChar = tchar;
|
||||
this.basicTypeString = String.valueOf(this.basicTypeChar);
|
||||
this.emptyArray = emptyArray;
|
||||
}
|
||||
|
||||
public Object zero() {
|
||||
return switch (this) {
|
||||
case BOOLEAN -> Boolean.FALSE;
|
||||
case INT -> (Integer)0;
|
||||
case DOUBLE -> DOUBLE_ZERO;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum MyEnum {
|
||||
DUMMY1,
|
||||
DUMMY2;
|
||||
|
||||
static final boolean BOOLEAN = true;
|
||||
static final byte BYTE = -128;
|
||||
static final short SHORT = -12345;
|
||||
static final char CHAR = 'c';
|
||||
static final int INT = -123456;
|
||||
static final long LONG = 0x1234567890L;
|
||||
static final long LONG2 = -0x1234567890L;
|
||||
static final float FLOAT = 567891.0f;
|
||||
static final double DOUBLE = 12345678905678.890;
|
||||
}
|
||||
}
|
||||
|
||||
class Dummy {}
|
||||
@ -36,7 +36,7 @@
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boot.jar
|
||||
* CDSTestClassA CDSTestClassA$XX CDSTestClassA$YY
|
||||
* CDSTestClassB CDSTestClassC CDSTestClassD
|
||||
* CDSTestClassE CDSTestClassF CDSTestClassG CDSTestClassG$MyEnum CDSTestClassG$Wrapper
|
||||
* CDSTestClassE CDSTestClassF
|
||||
* pkg.ClassInPackage
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar Hello
|
||||
* @run driver ArchiveHeapTestClass
|
||||
@ -58,7 +58,6 @@ public class ArchiveHeapTestClass {
|
||||
static final String CDSTestClassD_name = CDSTestClassD.class.getName();
|
||||
static final String CDSTestClassE_name = CDSTestClassE.class.getName();
|
||||
static final String CDSTestClassF_name = CDSTestClassF.class.getName();
|
||||
static final String CDSTestClassG_name = CDSTestClassG.class.getName();
|
||||
static final String ClassInPackage_name = pkg.ClassInPackage.class.getName().replace('.', '/');
|
||||
static final String ARCHIVE_TEST_FIELD_NAME = "archivedObjects";
|
||||
|
||||
@ -162,15 +161,6 @@ public class ArchiveHeapTestClass {
|
||||
output = dumpBootAndHello(CDSTestClassF_name);
|
||||
mustFail(output, "Class java.util.logging.Level not allowed in archive heap");
|
||||
}
|
||||
|
||||
testCase("Complex enums");
|
||||
output = dumpBootAndHello(CDSTestClassG_name, "-XX:+AOTClassLinking", "-Xlog:cds+class=debug");
|
||||
mustSucceed(output);
|
||||
|
||||
TestCommon.run("-Xbootclasspath/a:" + bootJar, "-cp", appJar, "-Xlog:aot+heap,cds+init",
|
||||
CDSTestClassG_name)
|
||||
.assertNormalExit("init subgraph " + CDSTestClassG_name,
|
||||
"Initialized from CDS");
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,147 +277,3 @@ class CDSTestClassF {
|
||||
archivedObjects[0] = java.util.logging.Level.OFF;
|
||||
}
|
||||
}
|
||||
|
||||
class CDSTestClassG {
|
||||
static Object[] archivedObjects;
|
||||
static {
|
||||
if (archivedObjects == null) {
|
||||
archivedObjects = new Object[13];
|
||||
archivedObjects[0] = Wrapper.BOOLEAN;
|
||||
archivedObjects[1] = Wrapper.INT.zero();
|
||||
archivedObjects[2] = Wrapper.DOUBLE.zero();
|
||||
archivedObjects[3] = MyEnum.DUMMY1;
|
||||
|
||||
archivedObjects[4] = Boolean.class;
|
||||
archivedObjects[5] = Byte.class;
|
||||
archivedObjects[6] = Character.class;
|
||||
archivedObjects[7] = Short.class;
|
||||
archivedObjects[8] = Integer.class;
|
||||
archivedObjects[9] = Long.class;
|
||||
archivedObjects[10] = Float.class;
|
||||
archivedObjects[11] = Double.class;
|
||||
archivedObjects[12] = Void.class;
|
||||
} else {
|
||||
System.out.println("Initialized from CDS");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
if (archivedObjects[0] != Wrapper.BOOLEAN) {
|
||||
throw new RuntimeException("Huh 0");
|
||||
}
|
||||
|
||||
if (archivedObjects[1] != Wrapper.INT.zero()) {
|
||||
throw new RuntimeException("Huh 1");
|
||||
}
|
||||
|
||||
if (archivedObjects[2] != Wrapper.DOUBLE.zero()) {
|
||||
throw new RuntimeException("Huh 2");
|
||||
}
|
||||
|
||||
if (archivedObjects[3] != MyEnum.DUMMY1) {
|
||||
throw new RuntimeException("Huh 3");
|
||||
}
|
||||
|
||||
if (MyEnum.BOOLEAN != true) {
|
||||
throw new RuntimeException("Huh 10.1");
|
||||
}
|
||||
if (MyEnum.BYTE != -128) {
|
||||
throw new RuntimeException("Huh 10.2");
|
||||
}
|
||||
if (MyEnum.CHAR != 'c') {
|
||||
throw new RuntimeException("Huh 10.3");
|
||||
}
|
||||
if (MyEnum.SHORT != -12345) {
|
||||
throw new RuntimeException("Huh 10.4");
|
||||
}
|
||||
if (MyEnum.INT != -123456) {
|
||||
throw new RuntimeException("Huh 10.5");
|
||||
}
|
||||
if (MyEnum.LONG != 0x1234567890L) {
|
||||
throw new RuntimeException("Huh 10.6");
|
||||
}
|
||||
if (MyEnum.LONG2 != -0x1234567890L) {
|
||||
throw new RuntimeException("Huh 10.7");
|
||||
}
|
||||
if (MyEnum.FLOAT != 567891.0f) {
|
||||
throw new RuntimeException("Huh 10.8");
|
||||
}
|
||||
if (MyEnum.DOUBLE != 12345678905678.890) {
|
||||
throw new RuntimeException("Huh 10.9");
|
||||
}
|
||||
|
||||
checkClass(4, Boolean.class);
|
||||
checkClass(5, Byte.class);
|
||||
checkClass(6, Character.class);
|
||||
checkClass(7, Short.class);
|
||||
checkClass(8, Integer.class);
|
||||
checkClass(9, Long.class);
|
||||
checkClass(10, Float.class);
|
||||
checkClass(11, Double.class);
|
||||
checkClass(12, Void.class);
|
||||
|
||||
System.out.println("Success!");
|
||||
}
|
||||
|
||||
static void checkClass(int index, Class c) {
|
||||
if (archivedObjects[index] != c) {
|
||||
throw new RuntimeException("archivedObjects[" + index + "] should be " + c);
|
||||
}
|
||||
}
|
||||
|
||||
// Simplified version of sun.invoke.util.Wrapper
|
||||
public enum Wrapper {
|
||||
// wrapperType simple primitiveType simple char emptyArray
|
||||
BOOLEAN( Boolean.class, "Boolean", boolean.class, "boolean", 'Z', new boolean[0]),
|
||||
INT ( Integer.class, "Integer", int.class, "int", 'I', new int[0]),
|
||||
DOUBLE ( Double.class, "Double", double.class, "double", 'D', new double[0])
|
||||
;
|
||||
|
||||
public static final int COUNT = 10;
|
||||
private static final Object DOUBLE_ZERO = (Double)(double)0;
|
||||
|
||||
private final Class<?> wrapperType;
|
||||
private final Class<?> primitiveType;
|
||||
private final char basicTypeChar;
|
||||
private final String basicTypeString;
|
||||
private final Object emptyArray;
|
||||
|
||||
Wrapper(Class<?> wtype,
|
||||
String wtypeName,
|
||||
Class<?> ptype,
|
||||
String ptypeName,
|
||||
char tchar,
|
||||
Object emptyArray) {
|
||||
this.wrapperType = wtype;
|
||||
this.primitiveType = ptype;
|
||||
this.basicTypeChar = tchar;
|
||||
this.basicTypeString = String.valueOf(this.basicTypeChar);
|
||||
this.emptyArray = emptyArray;
|
||||
}
|
||||
|
||||
public Object zero() {
|
||||
return switch (this) {
|
||||
case BOOLEAN -> Boolean.FALSE;
|
||||
case INT -> (Integer)0;
|
||||
case DOUBLE -> DOUBLE_ZERO;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum MyEnum {
|
||||
DUMMY1,
|
||||
DUMMY2;
|
||||
|
||||
static final boolean BOOLEAN = true;
|
||||
static final byte BYTE = -128;
|
||||
static final short SHORT = -12345;
|
||||
static final char CHAR = 'c';
|
||||
static final int INT = -123456;
|
||||
static final long LONG = 0x1234567890L;
|
||||
static final long LONG2 = -0x1234567890L;
|
||||
static final float FLOAT = 567891.0f;
|
||||
static final double DOUBLE = 12345678905678.890;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user