8194759: Support caching class mirror objects

Support archiving mirror objects for shared classes in 'open' archive java heap region.

Reviewed-by: coleenp, iklam, mseledtsov, tschatzl
This commit is contained in:
Jiangli Zhou 2018-03-02 17:25:55 -05:00
parent 979d5b7986
commit f987dec395
20 changed files with 1681 additions and 200 deletions

@ -481,6 +481,7 @@ static bool is_jfr_event_class(Klass *k) {
void Dictionary::reorder_dictionary_for_sharing() {
// Copy all the dictionary entries into a single master list.
assert(DumpSharedSpaces, "Should only be used at dump time");
DictionaryEntry* master_list = NULL;
for (int i = 0; i < table_size(); ++i) {
@ -488,7 +489,7 @@ void Dictionary::reorder_dictionary_for_sharing() {
while (p != NULL) {
DictionaryEntry* next = p->next();
InstanceKlass*ik = p->instance_klass();
if (ik->signers() != NULL) {
if (ik->has_signer_and_not_archived()) {
// We cannot include signed classes in the archive because the certificates
// used during dump time may be different than those used during
// runtime (due to expiration, etc).

File diff suppressed because it is too large Load Diff

@ -71,6 +71,7 @@ class java_lang_String : AllStatic {
};
static void compute_offsets();
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Instance creation
static Handle create_from_unicode(jchar* unicode, int len, TRAPS);
@ -222,6 +223,15 @@ class java_lang_Class : AllStatic {
static void fixup_mirror(Klass* k, TRAPS);
static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
// Archiving
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
static void archive_basic_type_mirrors(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
static oop archive_mirror(Klass* k, TRAPS) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
static oop process_archived_mirror(Klass* k, oop mirror, oop archived_mirror, Thread *THREAD)
NOT_CDS_JAVA_HEAP_RETURN_(NULL);
static void restore_archived_mirror(Klass *k, Handle mirror, Handle class_loader, Handle module,
Handle protection_domain, TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
static void fixup_module_field(Klass* k, Handle module);
// Conversion
@ -306,6 +316,8 @@ class java_lang_Thread : AllStatic {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Instance creation
static oop create();
// Returns the JavaThread associated with the thread obj
@ -406,6 +418,8 @@ class java_lang_ThreadGroup : AllStatic {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// parent ThreadGroup
static oop parent(oop java_thread_group);
// name
@ -485,6 +499,7 @@ class java_lang_Throwable: AllStatic {
static void print_stack_usage(Handle stream);
static void compute_offsets();
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Allocate space for backtrace (created but stack trace not filled in)
static void allocate_backtrace(Handle throwable, TRAPS);
@ -515,6 +530,8 @@ class java_lang_reflect_AccessibleObject: AllStatic {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Accessors
static jboolean override(oop reflect);
static void set_override(oop reflect, jboolean value);
@ -546,6 +563,8 @@ class java_lang_reflect_Method : public java_lang_reflect_AccessibleObject {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Allocation
static Handle create(TRAPS);
@ -615,6 +634,8 @@ class java_lang_reflect_Constructor : public java_lang_reflect_AccessibleObject
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Allocation
static Handle create(TRAPS);
@ -673,6 +694,8 @@ class java_lang_reflect_Field : public java_lang_reflect_AccessibleObject {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Allocation
static Handle create(TRAPS);
@ -728,6 +751,8 @@ class java_lang_reflect_Parameter {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Allocation
static Handle create(TRAPS);
@ -758,6 +783,8 @@ class java_lang_Module {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Allocation
static Handle create(Handle loader, Handle module_name, TRAPS);
@ -787,6 +814,8 @@ class reflect_ConstantPool {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Allocation
static Handle create(TRAPS);
@ -809,6 +838,8 @@ class reflect_UnsafeStaticFieldAccessorImpl {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
static int base_offset() {
return _base_offset;
}
@ -910,6 +941,7 @@ class java_lang_ref_SoftReference: public java_lang_ref_Reference {
static void set_clock(jlong value);
static void compute_offsets();
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
};
// Interface to java.lang.invoke.MethodHandle objects
@ -926,6 +958,8 @@ class java_lang_invoke_MethodHandle: AllStatic {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Accessors
static oop type(oop mh);
static void set_type(oop mh, oop mtype);
@ -955,6 +989,8 @@ class java_lang_invoke_DirectMethodHandle: AllStatic {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Accessors
static oop member(oop mh);
@ -980,6 +1016,8 @@ class java_lang_invoke_LambdaForm: AllStatic {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Accessors
static oop vmentry(oop lform);
static void set_vmentry(oop lform, oop invoker);
@ -1011,6 +1049,8 @@ class java_lang_invoke_ResolvedMethodName : AllStatic {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
static int vmtarget_offset_in_bytes() { return _vmtarget_offset; }
static Method* vmtarget(oop resolved_method);
@ -1048,6 +1088,7 @@ class java_lang_invoke_MemberName: AllStatic {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Accessors
static oop clazz(oop mname);
static void set_clazz(oop mname, oop clazz);
@ -1112,6 +1153,7 @@ class java_lang_invoke_MethodType: AllStatic {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Accessors
static oop rtype(oop mt);
static objArrayOop ptypes(oop mt);
@ -1147,6 +1189,7 @@ private:
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Accessors
static oop target( oop site);
static void set_target( oop site, oop target);
@ -1180,6 +1223,7 @@ private:
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Accessors
static DependencyContext vmdependencies(oop context);
@ -1203,6 +1247,7 @@ class java_security_AccessControlContext: AllStatic {
static void compute_offsets();
public:
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
static oop create(objArrayHandle context, bool isPrivileged, Handle privileged_context, TRAPS);
static bool is_authorized(Handle context);
@ -1228,6 +1273,7 @@ class java_lang_ClassLoader : AllStatic {
public:
static void compute_offsets();
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
static ClassLoaderData* loader_data(oop loader);
static ClassLoaderData* cmpxchg_loader_data(ClassLoaderData* new_data, oop loader, ClassLoaderData* expected_data);
@ -1279,6 +1325,7 @@ class java_lang_System : AllStatic {
static bool has_security_manager();
static void compute_offsets();
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Debugging
friend class JavaClasses;
@ -1316,6 +1363,7 @@ class java_lang_StackTraceElement: AllStatic {
int version, int bci, Symbol* name, TRAPS);
static void compute_offsets();
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Debugging
friend class JavaClasses;
@ -1359,6 +1407,7 @@ public:
static void set_version(oop info, short value);
static void compute_offsets();
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
static void to_stack_trace_element(Handle stackFrame, Handle stack_trace_element, TRAPS);
@ -1380,6 +1429,7 @@ class java_lang_LiveStackFrameInfo: AllStatic {
static void set_mode(oop info, int value);
static void compute_offsets();
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Debugging
friend class JavaClasses;
@ -1404,6 +1454,7 @@ class java_lang_AssertionStatusDirectives: AllStatic {
static void set_deflt(oop obj, bool val);
static void compute_offsets();
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
// Debugging
friend class JavaClasses;
@ -1417,6 +1468,7 @@ class java_nio_Buffer: AllStatic {
public:
static int limit_offset();
static void compute_offsets();
static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
};
class java_util_concurrent_locks_AbstractOwnableSynchronizer : AllStatic {

@ -703,7 +703,6 @@ bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
Thread* THREAD = Thread::current();
G1CollectedHeap::heap()->begin_archive_alloc_range();
for (int i = 0; i < the_table()->table_size(); ++i) {
HashtableEntry<oop, mtSymbol>* bucket = the_table()->bucket(i);
for ( ; bucket != NULL; bucket = bucket->next()) {
@ -727,7 +726,6 @@ bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
}
}
G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity());
return true;
}

@ -148,6 +148,7 @@
LOG_TAG(update) \
LOG_TAG(unload) /* Trace unloading of classes */ \
LOG_TAG(unshareable) \
LOG_TAG(mirror) \
LOG_TAG(verification) \
LOG_TAG(verify) \
LOG_TAG(vmoperation) \

@ -125,14 +125,13 @@ public:
size_t _cds_i2i_entry_code_buffers_size;
size_t _core_spaces_size; // number of bytes allocated by the core spaces
// (mc, md, ro, rw and od).
struct space_info {
int _crc; // crc checksum of the current space
size_t _file_offset; // sizeof(this) rounded to vm page size
union {
char* _base; // copy-on-write base address
intx _offset; // offset from the compressed oop encoding base, only used
// by string space
// by archive heap space
} _addr;
size_t _used; // for setting space top on read
bool _read_only; // read only space?

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -344,6 +344,9 @@ public:
// correct length.
virtual void do_tag(int tag) = 0;
// Read/write the oop
virtual void do_oop(oop* o) = 0;
bool writing() {
return !reading();
}

@ -375,9 +375,45 @@ void MetaspaceShared::serialize(SerializeClosure* soc) {
StringTable::serialize(soc);
soc->do_tag(--tag);
serialize_well_known_classes(soc);
soc->do_tag(--tag);
soc->do_tag(666);
}
void MetaspaceShared::serialize_well_known_classes(SerializeClosure* soc) {
java_lang_Class::serialize(soc);
java_lang_String::serialize(soc);
java_lang_System::serialize(soc);
java_lang_ClassLoader::serialize(soc);
java_lang_Throwable::serialize(soc);
java_lang_Thread::serialize(soc);
java_lang_ThreadGroup::serialize(soc);
java_lang_AssertionStatusDirectives::serialize(soc);
java_lang_ref_SoftReference::serialize(soc);
java_lang_invoke_MethodHandle::serialize(soc);
java_lang_invoke_DirectMethodHandle::serialize(soc);
java_lang_invoke_MemberName::serialize(soc);
java_lang_invoke_ResolvedMethodName::serialize(soc);
java_lang_invoke_LambdaForm::serialize(soc);
java_lang_invoke_MethodType::serialize(soc);
java_lang_invoke_CallSite::serialize(soc);
java_lang_invoke_MethodHandleNatives_CallSiteContext::serialize(soc);
java_security_AccessControlContext::serialize(soc);
java_lang_reflect_AccessibleObject::serialize(soc);
java_lang_reflect_Method::serialize(soc);
java_lang_reflect_Constructor::serialize(soc);
java_lang_reflect_Field::serialize(soc);
java_nio_Buffer::serialize(soc);
reflect_ConstantPool::serialize(soc);
reflect_UnsafeStaticFieldAccessorImpl::serialize(soc);
java_lang_reflect_Parameter::serialize(soc);
java_lang_Module::serialize(soc);
java_lang_StackTraceElement::serialize(soc);
java_lang_StackFrameInfo::serialize(soc);
java_lang_LiveStackFrameInfo::serialize(soc);
}
address MetaspaceShared::cds_i2i_entry_code_buffers(size_t total_size) {
if (DumpSharedSpaces) {
if (_cds_i2i_entry_code_buffers == NULL) {
@ -415,7 +451,12 @@ static void collect_array_classes(Klass* k) {
class CollectClassesClosure : public KlassClosure {
void do_klass(Klass* k) {
if (!(k->is_instance_klass() && InstanceKlass::cast(k)->is_in_error_state())) {
_global_klass_objects->append_if_missing(k);
if (k->is_instance_klass() && InstanceKlass::cast(k)->signers() != NULL) {
// Mark any class with signers and don't add to the _global_klass_objects
k->set_has_signer_and_not_archived();
} else {
_global_klass_objects->append_if_missing(k);
}
}
if (k->is_array_klass()) {
// Add in the array classes too
@ -452,6 +493,19 @@ static void remove_java_mirror_in_classes() {
}
}
static void clear_basic_type_mirrors() {
assert(!MetaspaceShared::is_heap_object_archiving_allowed(), "Sanity");
Universe::set_int_mirror(NULL);
Universe::set_float_mirror(NULL);
Universe::set_double_mirror(NULL);
Universe::set_byte_mirror(NULL);
Universe::set_bool_mirror(NULL);
Universe::set_char_mirror(NULL);
Universe::set_long_mirror(NULL);
Universe::set_short_mirror(NULL);
Universe::set_void_mirror(NULL);
}
static void rewrite_nofast_bytecode(Method* method) {
BytecodeStream bcs(method);
while (!bcs.is_last_bytecode()) {
@ -775,6 +829,17 @@ public:
_dump_region->append_intptr_t((intptr_t)tag);
}
void do_oop(oop* o) {
if (*o == NULL) {
_dump_region->append_intptr_t(0);
} else {
assert(MetaspaceShared::is_heap_object_archiving_allowed(),
"Archiving heap object is not allowed");
_dump_region->append_intptr_t(
(intptr_t)oopDesc::encode_heap_oop_not_null(*o));
}
}
void do_region(u_char* start, size_t size) {
assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
assert(size % sizeof(intptr_t) == 0, "bad size");
@ -935,7 +1000,7 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all, int mc_all, int md_all)
class VM_PopulateDumpSharedSpace: public VM_Operation {
private:
GrowableArray<MemRegion> *_string_regions;
GrowableArray<MemRegion> *_closed_archive_heap_regions;
GrowableArray<MemRegion> *_open_archive_heap_regions;
void dump_java_heap_objects() NOT_CDS_JAVA_HEAP_RETURN;
@ -1193,6 +1258,7 @@ public:
}
static Klass* get_relocated_klass(Klass* orig_klass) {
assert(DumpSharedSpaces, "dump time only");
address* pp = _new_loc_table->get((address)orig_klass);
assert(pp != NULL, "must be");
Klass* klass = (Klass*)(*pp);
@ -1222,7 +1288,11 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
// Reorder the system dictionary. Moving the symbols affects
// how the hash table indices are calculated.
SystemDictionary::reorder_dictionary_for_sharing();
tty->print("Removing java_mirror ... ");
if (!MetaspaceShared::is_heap_object_archiving_allowed()) {
clear_basic_type_mirrors();
}
remove_java_mirror_in_classes();
tty->print_cr("done. ");
NOT_PRODUCT(SystemDictionary::verify();)
@ -1312,7 +1382,7 @@ void VM_PopulateDumpSharedSpace::doit() {
dump_symbols();
// Dump supported java heap objects
_string_regions = NULL;
_closed_archive_heap_regions = NULL;
_open_archive_heap_regions = NULL;
dump_java_heap_objects();
@ -1375,7 +1445,7 @@ void VM_PopulateDumpSharedSpace::doit() {
write_region(mapinfo, MetaspaceShared::od, &_od_region, /*read_only=*/true, /*allow_exec=*/false);
_total_string_region_size = mapinfo->write_archive_heap_regions(
_string_regions,
_closed_archive_heap_regions,
MetaspaceShared::first_string,
MetaspaceShared::max_strings);
_total_open_archive_region_size = mapinfo->write_archive_heap_regions(
@ -1424,7 +1494,7 @@ void VM_PopulateDumpSharedSpace::print_region_stats() {
_ro_region.print(total_reserved);
_md_region.print(total_reserved);
_od_region.print(total_reserved);
print_heap_region_stats(_string_regions, "st", total_reserved);
print_heap_region_stats(_closed_archive_heap_regions, "st", total_reserved);
print_heap_region_stats(_open_archive_heap_regions, "oa", total_reserved);
tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
@ -1452,6 +1522,11 @@ void MetaspaceShared::relocate_klass_ptr(oop o) {
o->set_klass(k);
}
Klass* MetaspaceShared::get_relocated_klass(Klass *k) {
assert(DumpSharedSpaces, "sanity");
return ArchiveCompactor::get_relocated_klass(k);
}
class LinkSharedClassesClosure : public KlassClosure {
Thread* THREAD;
bool _made_progress;
@ -1693,11 +1768,11 @@ void VM_PopulateDumpSharedSpace::dump_java_heap_objects() {
// Cache for recording where the archived objects are copied to
MetaspaceShared::create_archive_object_cache();
tty->print_cr("Dumping String objects to closed archive heap region ...");
tty->print_cr("Dumping objects to closed archive heap region ...");
NOT_PRODUCT(StringTable::verify());
// The string space has maximum two regions. See FileMapInfo::write_archive_heap_regions() for details.
_string_regions = new GrowableArray<MemRegion>(2);
StringTable::write_to_archive(_string_regions);
// The closed space has maximum two regions. See FileMapInfo::write_archive_heap_regions() for details.
_closed_archive_heap_regions = new GrowableArray<MemRegion>(2);
MetaspaceShared::dump_closed_archive_heap_objects(_closed_archive_heap_regions);
tty->print_cr("Dumping objects to open archive heap region ...");
_open_archive_heap_regions = new GrowableArray<MemRegion>(2);
@ -1709,6 +1784,20 @@ void VM_PopulateDumpSharedSpace::dump_java_heap_objects() {
G1HeapVerifier::verify_archive_regions();
}
void MetaspaceShared::dump_closed_archive_heap_objects(
GrowableArray<MemRegion> * closed_archive) {
assert(is_heap_object_archiving_allowed(), "Cannot dump java heap objects");
Thread* THREAD = Thread::current();
G1CollectedHeap::heap()->begin_archive_alloc_range();
// Archive interned string objects
StringTable::write_to_archive(closed_archive);
G1CollectedHeap::heap()->end_archive_alloc_range(closed_archive,
os::vm_allocation_granularity());
}
void MetaspaceShared::dump_open_archive_heap_objects(
GrowableArray<MemRegion> * open_archive) {
assert(UseG1GC, "Only support G1 GC");
@ -1718,21 +1807,33 @@ void MetaspaceShared::dump_open_archive_heap_objects(
Thread* THREAD = Thread::current();
G1CollectedHeap::heap()->begin_archive_alloc_range(true /* open */);
MetaspaceShared::archive_resolved_constants(THREAD);
java_lang_Class::archive_basic_type_mirrors(THREAD);
MetaspaceShared::archive_klass_objects(THREAD);
G1CollectedHeap::heap()->end_archive_alloc_range(open_archive,
os::vm_allocation_granularity());
}
MetaspaceShared::ArchivedObjectCache* MetaspaceShared::_archive_object_cache = NULL;
oop MetaspaceShared::archive_heap_object(oop obj, Thread* THREAD) {
oop MetaspaceShared::find_archived_heap_object(oop obj) {
assert(DumpSharedSpaces, "dump-time only");
ArchivedObjectCache* cache = MetaspaceShared::archive_object_cache();
oop* p = cache->get(obj);
if (p != NULL) {
// already archived
return *p;
} else {
return NULL;
}
}
oop MetaspaceShared::archive_heap_object(oop obj, Thread* THREAD) {
assert(DumpSharedSpaces, "dump-time only");
oop ao = find_archived_heap_object(obj);
if (ao != NULL) {
// already archived
return ao;
}
int len = obj->size();
@ -1745,15 +1846,23 @@ oop MetaspaceShared::archive_heap_object(oop obj, Thread* THREAD) {
if (archived_oop != NULL) {
Copy::aligned_disjoint_words((HeapWord*)obj, (HeapWord*)archived_oop, len);
relocate_klass_ptr(archived_oop);
ArchivedObjectCache* cache = MetaspaceShared::archive_object_cache();
cache->put(obj, archived_oop);
}
log_debug(cds)("Archived heap object " PTR_FORMAT " ==> " PTR_FORMAT,
p2i(obj), p2i(archived_oop));
return archived_oop;
}
void MetaspaceShared::archive_resolved_constants(Thread* THREAD) {
void MetaspaceShared::archive_klass_objects(Thread* THREAD) {
int i;
for (i = 0; i < _global_klass_objects->length(); i++) {
Klass* k = _global_klass_objects->at(i);
// archive mirror object
java_lang_Class::archive_mirror(k, CHECK);
// archive the resolved_referenes array
if (k->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(k);
ik->constants()->archive_resolved_references(THREAD);
@ -1802,6 +1911,19 @@ public:
FileMapInfo::assert_mark(tag == old_tag);
}
void do_oop(oop *p) {
narrowOop o = (narrowOop)nextPtr();
if (o == 0 || !MetaspaceShared::open_archive_heap_region_mapped()) {
p = NULL;
} else {
assert(MetaspaceShared::is_heap_object_archiving_allowed(),
"Archived heap object is not allowed");
assert(MetaspaceShared::open_archive_heap_region_mapped(),
"Open archive heap region is not mapped");
RootAccess<IN_ARCHIVE_ROOT>::oop_store(p, oopDesc::decode_heap_oop_not_null(o));
}
}
void do_region(u_char* start, size_t size) {
assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
assert(size % sizeof(intptr_t) == 0, "bad size");

@ -113,8 +113,9 @@ class MetaspaceShared : AllStatic {
static ArchivedObjectCache* archive_object_cache() {
return _archive_object_cache;
}
static oop find_archived_heap_object(oop obj);
static oop archive_heap_object(oop obj, Thread* THREAD);
static void archive_resolved_constants(Thread* THREAD);
static void archive_klass_objects(Thread* THREAD);
#endif
static bool is_heap_object_archiving_allowed() {
CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedOops && UseCompressedClassPointers);)
@ -128,6 +129,8 @@ class MetaspaceShared : AllStatic {
}
static void fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
static void dump_closed_archive_heap_objects(GrowableArray<MemRegion> * closed_archive) NOT_CDS_JAVA_HEAP_RETURN;
static void dump_open_archive_heap_objects(GrowableArray<MemRegion> * open_archive) NOT_CDS_JAVA_HEAP_RETURN;
static void set_open_archive_heap_region_mapped() {
CDS_JAVA_HEAP_ONLY(_open_archive_heap_region_mapped = true);
@ -199,7 +202,8 @@ class MetaspaceShared : AllStatic {
static void zero_cpp_vtable_clones_for_writing();
static void patch_cpp_vtable_pointers();
static bool is_valid_shared_method(const Method* m) NOT_CDS_RETURN_(false);
static void serialize(SerializeClosure* sc);
static void serialize(SerializeClosure* sc) NOT_CDS_RETURN;
static void serialize_well_known_classes(SerializeClosure* soc) NOT_CDS_RETURN;
static MetaspaceSharedStats* stats() {
return &_stats;
@ -248,5 +252,7 @@ class MetaspaceShared : AllStatic {
return _cds_i2i_entry_code_buffers_size;
}
static void relocate_klass_ptr(oop o);
static Klass* get_relocated_klass(Klass *k);
};
#endif // SHARE_VM_MEMORY_METASPACESHARED_HPP

@ -247,7 +247,7 @@ void Universe::metaspace_pointers_do(MetaspaceClosure* it) {
_do_stack_walk_cache->metaspace_pointers_do(it);
}
// Serialize metadata in and out of CDS archive, not oops.
// Serialize metadata and pointers to primitive type mirrors in and out of CDS archive
void Universe::serialize(SerializeClosure* f, bool do_all) {
f->do_ptr((void**)&_boolArrayKlassObj);
@ -271,6 +271,20 @@ void Universe::serialize(SerializeClosure* f, bool do_all) {
}
}
#if INCLUDE_CDS_JAVA_HEAP
// The mirrors are NULL if MetaspaceShared::is_heap_object_archiving_allowed
// is false.
f->do_oop(&_int_mirror);
f->do_oop(&_float_mirror);
f->do_oop(&_double_mirror);
f->do_oop(&_byte_mirror);
f->do_oop(&_bool_mirror);
f->do_oop(&_char_mirror);
f->do_oop(&_long_mirror);
f->do_oop(&_short_mirror);
f->do_oop(&_void_mirror);
#endif
f->do_ptr((void**)&_the_array_interfaces_array);
f->do_ptr((void**)&_the_empty_int_array);
f->do_ptr((void**)&_the_empty_short_array);
@ -453,25 +467,38 @@ void Universe::genesis(TRAPS) {
}
void Universe::initialize_basic_type_mirrors(TRAPS) {
assert(_int_mirror==NULL, "basic type mirrors already initialized");
_int_mirror =
java_lang_Class::create_basic_type_mirror("int", T_INT, CHECK);
_float_mirror =
java_lang_Class::create_basic_type_mirror("float", T_FLOAT, CHECK);
_double_mirror =
java_lang_Class::create_basic_type_mirror("double", T_DOUBLE, CHECK);
_byte_mirror =
java_lang_Class::create_basic_type_mirror("byte", T_BYTE, CHECK);
_bool_mirror =
java_lang_Class::create_basic_type_mirror("boolean",T_BOOLEAN, CHECK);
_char_mirror =
java_lang_Class::create_basic_type_mirror("char", T_CHAR, CHECK);
_long_mirror =
java_lang_Class::create_basic_type_mirror("long", T_LONG, CHECK);
_short_mirror =
java_lang_Class::create_basic_type_mirror("short", T_SHORT, CHECK);
_void_mirror =
java_lang_Class::create_basic_type_mirror("void", T_VOID, CHECK);
#if INCLUDE_CDS_JAVA_HEAP
if (UseSharedSpaces &&
MetaspaceShared::open_archive_heap_region_mapped() &&
_int_mirror != NULL) {
assert(MetaspaceShared::is_heap_object_archiving_allowed(), "Sanity");
assert(_float_mirror != NULL && _double_mirror != NULL &&
_byte_mirror != NULL && _byte_mirror != NULL &&
_bool_mirror != NULL && _char_mirror != NULL &&
_long_mirror != NULL && _short_mirror != NULL &&
_void_mirror != NULL, "Sanity");
} else
#endif
{
_int_mirror =
java_lang_Class::create_basic_type_mirror("int", T_INT, CHECK);
_float_mirror =
java_lang_Class::create_basic_type_mirror("float", T_FLOAT, CHECK);
_double_mirror =
java_lang_Class::create_basic_type_mirror("double", T_DOUBLE, CHECK);
_byte_mirror =
java_lang_Class::create_basic_type_mirror("byte", T_BYTE, CHECK);
_bool_mirror =
java_lang_Class::create_basic_type_mirror("boolean",T_BOOLEAN, CHECK);
_char_mirror =
java_lang_Class::create_basic_type_mirror("char", T_CHAR, CHECK);
_long_mirror =
java_lang_Class::create_basic_type_mirror("long", T_LONG, CHECK);
_short_mirror =
java_lang_Class::create_basic_type_mirror("short", T_SHORT, CHECK);
_void_mirror =
java_lang_Class::create_basic_type_mirror("void", T_VOID, CHECK);
}
_mirrors[T_INT] = _int_mirror;
_mirrors[T_FLOAT] = _float_mirror;

@ -294,6 +294,16 @@ class Universe: AllStatic {
static oop short_mirror() { return check_mirror(_short_mirror); }
static oop void_mirror() { return check_mirror(_void_mirror); }
static void set_int_mirror(oop m) { _int_mirror = m; }
static void set_float_mirror(oop m) { _float_mirror = m; }
static void set_double_mirror(oop m) { _double_mirror = m; }
static void set_byte_mirror(oop m) { _byte_mirror = m; }
static void set_bool_mirror(oop m) { _bool_mirror = m; }
static void set_char_mirror(oop m) { _char_mirror = m; }
static void set_long_mirror(oop m) { _long_mirror = m; }
static void set_short_mirror(oop m) { _short_mirror = m; }
static void set_void_mirror(oop m) { _void_mirror = m; }
// table of same
static oop _mirrors[T_VOID+1];

@ -183,7 +183,8 @@ void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word
Klass::Klass() : _prototype_header(markOopDesc::prototype()),
_shared_class_path_index(-1),
_java_mirror(NULL) {
CDS_ONLY(_shared_class_flags = 0;)
CDS_JAVA_HEAP_ONLY(_archived_mirror = 0;)
_primary_supers[0] = this;
set_super_check_offset(in_bytes(primary_supers_offset()));
}
@ -519,29 +520,71 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec
loader_data->add_class(this);
}
// Recreate the class mirror.
Handle loader(THREAD, loader_data->class_loader());
ModuleEntry* module_entry = NULL;
Klass* k = this;
if (k->is_objArray_klass()) {
k = ObjArrayKlass::cast(k)->bottom_klass();
}
// Obtain klass' module.
if (k->is_instance_klass()) {
InstanceKlass* ik = (InstanceKlass*) k;
module_entry = ik->module();
} else {
module_entry = ModuleEntryTable::javabase_moduleEntry();
}
// Obtain java.lang.Module, if available
Handle module_handle(THREAD, ((module_entry != NULL) ? module_entry->module() : (oop)NULL));
if (this->has_raw_archived_mirror()) {
log_debug(cds, mirror)("%s has raw archived mirror", external_name());
if (MetaspaceShared::open_archive_heap_region_mapped()) {
oop m = archived_java_mirror();
log_debug(cds, mirror)("Archived mirror is: " PTR_FORMAT, p2i(m));
if (m != NULL) {
// mirror is archived, restore
assert(oopDesc::is_archive_object(m), "must be archived mirror object");
Handle m_h(THREAD, m);
java_lang_Class::restore_archived_mirror(this, m_h, loader, module_handle, protection_domain, CHECK);
return;
}
}
// No archived mirror data
_java_mirror = NULL;
this->clear_has_raw_archived_mirror();
}
// Only recreate it if not present. A previous attempt to restore may have
// gotten an OOM later but keep the mirror if it was created.
if (java_mirror() == NULL) {
Handle loader(THREAD, loader_data->class_loader());
ModuleEntry* module_entry = NULL;
Klass* k = this;
if (k->is_objArray_klass()) {
k = ObjArrayKlass::cast(k)->bottom_klass();
}
// Obtain klass' module.
if (k->is_instance_klass()) {
InstanceKlass* ik = (InstanceKlass*) k;
module_entry = ik->module();
} else {
module_entry = ModuleEntryTable::javabase_moduleEntry();
}
// Obtain java.lang.Module, if available
Handle module_handle(THREAD, ((module_entry != NULL) ? module_entry->module() : (oop)NULL));
log_trace(cds, mirror)("Recreate mirror for %s", external_name());
java_lang_Class::create_mirror(this, loader, module_handle, protection_domain, CHECK);
}
}
#if INCLUDE_CDS_JAVA_HEAP
// Used at CDS dump time to access the archived mirror. No GC barrier.
oop Klass::archived_java_mirror_raw() {
assert(DumpSharedSpaces, "called only during runtime");
assert(has_raw_archived_mirror(), "must have raw archived mirror");
return oopDesc::decode_heap_oop(_archived_mirror);
}
// Used at CDS runtime to get the archived mirror from shared class. Uses GC barrier.
oop Klass::archived_java_mirror() {
assert(UseSharedSpaces, "UseSharedSpaces expected.");
assert(has_raw_archived_mirror(), "must have raw archived mirror");
return RootAccess<IN_ARCHIVE_ROOT>::oop_load(&_archived_mirror);
}
// No GC barrier
void Klass::set_archived_java_mirror_raw(oop m) {
assert(DumpSharedSpaces, "called only during runtime");
_archived_mirror = oopDesc::encode_heap_oop(m);
}
#endif // INCLUDE_CDS_JAVA_HEAP
Klass* Klass::array_klass_or_null(int rank) {
EXCEPTION_MARK;
// No exception can be thrown by array_klass_impl when called with or_null == true.

@ -156,6 +156,18 @@ private:
// -1.
jshort _shared_class_path_index;
#if INCLUDE_CDS
// Flags of the current shared class.
u2 _shared_class_flags;
enum {
_has_raw_archived_mirror = 1,
_has_signer_and_not_archived = 1 << 2
};
#endif
// The _archived_mirror is set at CDS dump time pointing to the cached mirror
// in the open archive heap region when archiving java object is supported.
CDS_JAVA_HEAP_ONLY(narrowOop _archived_mirror);
friend class SharedClassUtil;
protected:
@ -229,11 +241,17 @@ protected:
oop java_mirror() const;
void set_java_mirror(Handle m);
oop archived_java_mirror_raw() NOT_CDS_JAVA_HEAP_RETURN_(NULL); // no GC barrier
oop archived_java_mirror() NOT_CDS_JAVA_HEAP_RETURN_(NULL); // accessor with GC barrier
void set_archived_java_mirror_raw(oop m) NOT_CDS_JAVA_HEAP_RETURN; // no GC barrier
// Temporary mirror switch used by RedefineClasses
// Both mirrors are on the ClassLoaderData::_handles list already so no
// barriers are needed.
void set_java_mirror_handle(OopHandle mirror) { _java_mirror = mirror; }
OopHandle java_mirror_handle() const { return _java_mirror; }
OopHandle java_mirror_handle() const {
return _java_mirror;
}
// modifier flags
jint modifier_flags() const { return _modifier_flags; }
@ -267,6 +285,26 @@ protected:
_shared_class_path_index = index;
};
void set_has_raw_archived_mirror() {
CDS_ONLY(_shared_class_flags |= _has_raw_archived_mirror;)
}
void clear_has_raw_archived_mirror() {
CDS_ONLY(_shared_class_flags &= ~_has_raw_archived_mirror;)
}
bool has_raw_archived_mirror() const {
CDS_ONLY(return (_shared_class_flags & _has_raw_archived_mirror) != 0;)
NOT_CDS(return false;)
}
#if INCLUDE_CDS
void set_has_signer_and_not_archived() {
_shared_class_flags |= _has_signer_and_not_archived;
}
bool has_signer_and_not_archived() const {
assert(DumpSharedSpaces, "dump time only");
return (_shared_class_flags & _has_signer_and_not_archived) != 0;
}
#endif // INCLUDE_CDS
// Obtain the module or package for this class
virtual ModuleEntry* module() const = 0;
virtual PackageEntry* package() const = 0;

@ -0,0 +1,92 @@
/*
* 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 java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import sun.hotspot.WhiteBox;
//
// Test class mirror objects are cached when open archive heap objects are mapped:
// - Well-known shared library classes:
// java.lang.Object
// java.lang.String
// - Shared application class loaded by the system class loader
// - Shared application class loaded user defined class loader
//
public class CheckCachedMirrorApp {
static WhiteBox wb;
public static void main(String args[]) throws Exception {
String path = args[0];
URL url = new File(path).toURI().toURL();
URL[] urls = new URL[] {url};
URLClassLoader loader = new URLClassLoader(urls);
Class hello = loader.loadClass("Hello");
System.out.println("Loaded " + hello + " from " + url + " using loader " + loader);
wb = WhiteBox.getWhiteBox();
if (!wb.areOpenArchiveHeapObjectsMapped()) {
System.out.println("Archived open_archive_heap objects are not mapped.");
System.out.println("This may happen during normal operation. Test Skipped.");
return;
}
// Well-known shared library classes
Class object_class = Object.class;
checkMirror(object_class, true);
Class string_class = String.class;
checkMirror(string_class, true);
// Shared app class
Class app_class = CheckCachedMirrorApp.class;
checkMirror(app_class, true);
// Hello is shared class and loaded by the 'loader' defined in current app.
// It should not have cached resolved_references.
Class class_with_user_defined_loader = hello;
checkMirror(class_with_user_defined_loader, false);
}
static void checkMirror(Class c, boolean mirrorShouldBeArchived) {
System.out.print("Check cached mirror for " + c);
if (wb.isSharedClass(c)) {
// Check if the Class object is cached
if (mirrorShouldBeArchived && wb.isShared(c)) {
System.out.println(c + " mirror is cached. Expected.");
} else if (!mirrorShouldBeArchived && !wb.isShared(c)) {
System.out.println(c + " mirror is not cached. Expected.");
} else if (mirrorShouldBeArchived && !wb.isShared(c)) {
throw new RuntimeException(
"FAILED. " + c + " mirror is not cached.");
} else {
throw new RuntimeException(
"FAILED. " + c + " mirror should not be cached.");
}
} else {
System.out.println("Class " + c + "is not shared, skipping the check for mirror");
}
}
}

@ -0,0 +1,68 @@
/*
* 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 archived mirror
* @requires vm.cds.archived.java.heap
* @requires vm.cds.custom.loaders
* @library /test/lib /test/hotspot/jtreg/runtime/appcds
* @modules java.base/jdk.internal.misc
* @modules java.management
* jdk.jartool/sun.tools.jar
* @build sun.hotspot.WhiteBox
* @compile CheckCachedMirrorApp.java
* @compile ../test-classes/Hello.java
* @run driver ClassFileInstaller -jar app.jar CheckCachedMirrorApp
* @run driver ClassFileInstaller -jar hello.jar Hello
* @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
* @run main CheckCachedMirrorTest
*/
import jdk.test.lib.process.OutputAnalyzer;
import sun.hotspot.WhiteBox;
public class CheckCachedMirrorTest {
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("app.jar");
String helloJarPath = ClassFileInstaller.getJarPath("hello.jar");
String classlist[] = new String[] {
"CheckCachedMirrorApp", // built-in app loader
"java/lang/Object id: 1", // boot loader
"Hello id: 2 super: 1 source: " + helloJarPath // custom loader
};
TestCommon.testDump(appJar, classlist, use_whitebox_jar);
OutputAnalyzer output = TestCommon.exec(appJar, use_whitebox_jar,
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-Xlog:cds=debug",
"CheckCachedMirrorApp",
helloJarPath);
TestCommon.checkExec(output);
}
}

@ -0,0 +1,99 @@
/*
* 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 java.io.File;
import java.net.URL;
import sun.hotspot.WhiteBox;
//
// - Test static final String field with initial value in cached mirror should be also archived.
// - GC should not crash when reference fields in cached mirror are updated at runtime
// - Reference fields are updated to point to runtime created objects
// - Reference fields are nullified
//
public class MirrorWithReferenceFieldsApp {
// Static String field with initial value
static final String archived_field = "abc";
// Static object field
static Object non_archived_field_1;
// Instance field
Integer non_archived_field_2;
public MirrorWithReferenceFieldsApp() {
non_archived_field_1 = new Object();
non_archived_field_2 = new Integer(1);
}
public static void main(String args[]) throws Exception {
WhiteBox wb = WhiteBox.getWhiteBox();
if (!wb.areOpenArchiveHeapObjectsMapped()) {
System.out.println("Archived open_archive_heap objects are not mapped.");
System.out.println("This may happen during normal operation. Test Skipped.");
return;
}
MirrorWithReferenceFieldsApp m = new MirrorWithReferenceFieldsApp();
m.test(wb);
}
public void test(WhiteBox wb) {
Class c = MirrorWithReferenceFieldsApp.class;
if (wb.isSharedClass(c)) {
// Check if the Class object is cached
if (wb.isShared(c)) {
System.out.println(c + " mirror is cached. Expected.");
} else {
throw new RuntimeException(
"FAILED. " + c + " mirror should be cached.");
}
// Check fields
if (wb.isShared(archived_field)) {
System.out.println("archived_field is archived as excepted");
} else {
throw new RuntimeException(
"FAILED. archived_field is not archived.");
}
// GC should not crash
System.gc();
System.gc();
System.gc();
non_archived_field_1 = null;
non_archived_field_2 = null;
System.gc();
System.gc();
System.gc();
System.out.println("Done.");
}
}
}

@ -0,0 +1,65 @@
/*
* 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 archived mirror with reference fields
* @requires vm.cds.archived.java.heap
* @library /test/lib /test/hotspot/jtreg/runtime/appcds
* @modules java.base/jdk.internal.misc
* @modules java.management
* jdk.jartool/sun.tools.jar
* @build sun.hotspot.WhiteBox
* @compile MirrorWithReferenceFieldsApp.java
* @run driver ClassFileInstaller -jar app.jar MirrorWithReferenceFieldsApp
* @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
* @run main MirrorWithReferenceFieldsTest
*/
import jdk.test.lib.process.OutputAnalyzer;
import sun.hotspot.WhiteBox;
public class MirrorWithReferenceFieldsTest {
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("app.jar");
String classlist[] = new String[] {
"MirrorWithReferenceFieldsApp",
};
TestCommon.testDump(appJar, classlist, use_whitebox_jar);
OutputAnalyzer output = TestCommon.exec(appJar, use_whitebox_jar,
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-XX:+VerifyAfterGC",
"MirrorWithReferenceFieldsApp");
try {
TestCommon.checkExec(output, "Done");
} catch (Exception e) {
output.shouldContain("Archived open_archive_heap objects are not mapped");
}
}
}

@ -0,0 +1,205 @@
/*
* 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 java.lang.reflect.Field;
import sun.hotspot.WhiteBox;
//
// Test primitive type class mirror objects are cached when open archive heap
// objects are mapped.
//
public class PrimitiveTypesApp {
public static void main(String[] args) {
WhiteBox wb = WhiteBox.getWhiteBox();
if (!wb.areOpenArchiveHeapObjectsMapped()) {
System.out.println("Archived open_archive_heap objects are not mapped.");
System.out.println("This may happen during normal operation. Test Skipped.");
return;
}
FieldsTest ft = new FieldsTest();
ft.testBoolean(wb);
ft.testByte(wb);
ft.testChar(wb);
ft.testInt(wb);
ft.testShort(wb);
ft.testLong(wb);
ft.testFloat(wb);
ft.testDouble(wb);
}
}
class FieldsTest {
public boolean f_boolean;
public byte f_byte;
public char f_char;
public int f_int;
public short f_short;
public long f_long;
public float f_float;
public double f_double;
FieldsTest() {
f_byte = 1;
f_boolean = false;
f_char = 'a';
f_int = 1;
f_short = 100;
f_long = 2018L;
f_float = 1.0f;
f_double = 2.5;
}
void testBoolean(WhiteBox wb) {
try {
Field f = this.getClass().getDeclaredField("f_boolean");
f.setBoolean(this, true);
if (!f_boolean) {
throw new RuntimeException("FAILED. Field f_boolean has unexpected value: " + f_boolean);
}
checkPrimitiveType(wb, f, Boolean.TYPE);
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
} catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
}
void testByte(WhiteBox wb) {
try {
Field f = this.getClass().getDeclaredField("f_byte");
f.setByte(this, (byte)9);
if (f_byte != (byte)9) {
throw new RuntimeException("FAILED. Field f_byte has unexpected value: " + f_byte);
}
checkPrimitiveType(wb, f, Byte.TYPE);
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
} catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
}
void testChar(WhiteBox wb) {
try {
Field f = this.getClass().getDeclaredField("f_char");
f.setChar(this, 'b');
if (f_char != 'b') {
throw new RuntimeException("FAILED. Field f_char has unexpected value: " + f_char);
}
checkPrimitiveType(wb, f, Character.TYPE);
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
} catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
}
void testInt(WhiteBox wb) {
try {
Field f = this.getClass().getDeclaredField("f_int");
f.setInt(this, 9999);
if (f_int != 9999) {
throw new RuntimeException("FAILED. Field f_int has unexpected value: " + f_int);
}
checkPrimitiveType(wb, f, Integer.TYPE);
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
} catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
}
void testShort(WhiteBox wb) {
try {
Field f = this.getClass().getDeclaredField("f_short");
f.setShort(this, (short)99);
if (f_short != 99) {
throw new RuntimeException("FAILED. Field f_short has unexpected value: " + f_short);
}
checkPrimitiveType(wb, f, Short.TYPE);
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
} catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
}
void testLong(WhiteBox wb) {
try {
Field f = this.getClass().getDeclaredField("f_long");
f.setLong(this, 99L);
if (f_long != 99L) {
throw new RuntimeException("FAILED. Field f_long has unexpected value: " + f_long);
}
checkPrimitiveType(wb, f, Long.TYPE);
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
} catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
}
void testFloat(WhiteBox wb) {
try {
Field f = this.getClass().getDeclaredField("f_float");
f.setFloat(this, 9.9f);
if (f_float != 9.9f) {
throw new RuntimeException("FAILED. Field f_float has unexpected value: " + f_float);
}
checkPrimitiveType(wb, f, Float.TYPE);
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
} catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
}
void testDouble(WhiteBox wb) {
try {
Field f = this.getClass().getDeclaredField("f_double");
f.setDouble(this, 9.9);
if (f_double != 9.9) {
throw new RuntimeException("FAILED. Field f_double has unexpected value: " + f_double);
}
checkPrimitiveType(wb, f, Double.TYPE);
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
} catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
}
void checkPrimitiveType(WhiteBox wb, Field f, Class t) {
Class c = f.getType();
if (!(c.isPrimitive() && c == t)) {
throw new RuntimeException("FAILED. " + c + " is not primitive type " + t);
}
if (wb.isShared(c)) {
System.out.println(c + " is cached, expected");
} else {
throw new RuntimeException("FAILED. " + c + " is not cached.");
}
}
}

@ -0,0 +1,62 @@
/*
* 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 archived primitive type mirrors
* @requires vm.cds.archived.java.heap
* @library /test/lib /test/hotspot/jtreg/runtime/appcds
* @modules java.base/jdk.internal.misc
* @modules java.management
* jdk.jartool/sun.tools.jar
* @build sun.hotspot.WhiteBox
* @compile PrimitiveTypesApp.java
* @run driver ClassFileInstaller -jar app.jar PrimitiveTypesApp FieldsTest
* @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
* @run main PrimitiveTypesTest
*/
import jdk.test.lib.process.OutputAnalyzer;
import sun.hotspot.WhiteBox;
public class PrimitiveTypesTest {
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("app.jar");
String classlist[] = new String[] {
"PrimitiveTypesApp",
"FieldsTest"
};
TestCommon.testDump(appJar, classlist, use_whitebox_jar);
OutputAnalyzer output = TestCommon.exec(appJar, use_whitebox_jar,
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-XX:+VerifyAfterGC",
"PrimitiveTypesApp");
TestCommon.checkExec(output);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -89,6 +89,16 @@ public class RedefineClassApp {
doTest(group, new Foo(), jar);
}
static void checkArchivedMirrorObject(Class klass) {
if (wb.areOpenArchiveHeapObjectsMapped()) {
if (!wb.isShared(klass)) {
failed ++;
System.out.println("FAILED. " + klass + " mirror object is not archived");
return;
}
}
}
static void doTest(String group, Intf object, File jar) throws Throwable {
numTests ++;
@ -101,6 +111,9 @@ public class RedefineClassApp {
System.out.println("Test is shared = " + wb.isSharedClass(klass));
System.out.println("++++++++++++++++++++++++++");
// Check archived mirror object before redefine
checkArchivedMirrorObject(klass);
// Call get() before redefine. All strings in archived classes are shared.
String res = object.get();
System.out.println("get() returns " + res);
@ -144,6 +157,9 @@ public class RedefineClassApp {
System.gc();
System.gc();
// Check archived mirror object after redefine and GC
checkArchivedMirrorObject(klass);
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++ (done)\n\n");
}
}