author | jiangli |
Fri, 02 Mar 2018 17:25:55 -0500 | |
changeset 49329 | 04ed29f9ef33 |
parent 49328 | 6a86f0deb479 |
child 49330 | e5ba028ee3f1 |
--- a/src/hotspot/share/classfile/dictionary.cpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/classfile/dictionary.cpp Fri Mar 02 17:25:55 2018 -0500 @@ -481,6 +481,7 @@ 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 @@ 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).
--- a/src/hotspot/share/classfile/javaClasses.cpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/classfile/javaClasses.cpp Fri Mar 02 17:25:55 2018 -0500 @@ -36,6 +36,7 @@ #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/oopFactory.hpp" +#include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/fieldStreams.hpp" @@ -67,6 +68,11 @@ #define INJECTED_FIELD_COMPUTE_OFFSET(klass, name, signature, may_be_java) \ klass::_##name##_offset = JavaClasses::compute_injected_offset(JavaClasses::klass##_##name##_enum); +#if INCLUDE_CDS +#define INJECTED_FIELD_SERIALIZE_OFFSET(klass, name, signature, may_be_java) \ + f->do_u4((u4*)&_##name##_offset); +#endif + #define DECLARE_INJECTED_FIELD(klass, name, signature, may_be_java) \ { SystemDictionary::WK_KLASS_ENUM_NAME(klass), vmSymbols::VM_SYMBOL_ENUM_NAME(name##_name), vmSymbols::VM_SYMBOL_ENUM_NAME(signature), may_be_java }, @@ -170,17 +176,43 @@ return is_instance_inlined(obj); } +#if INCLUDE_CDS +#define FIELD_SERIALIZE_OFFSET(offset, klass, name, signature, is_static) \ + f->do_u4((u4*)&offset) + +#define FIELD_SERIALIZE_OFFSET_OPTIONAL(offset, klass, name, signature) \ + f->do_u4((u4*)&offset) +#endif + +#define FIELD_COMPUTE_OFFSET(offset, klass, name, signature, is_static) \ + compute_offset(offset, klass, name, vmSymbols::signature(), is_static) + +#define FIELD_COMPUTE_OFFSET_OPTIONAL(offset, klass, name, signature) \ + compute_optional_offset(offset, klass, name, vmSymbols::signature()) + +#define STRING_FIELDS_DO(macro) \ + macro(value_offset, k, vmSymbols::value_name(), byte_array_signature, false); \ + macro(hash_offset, k, "hash", int_signature, false); \ + macro(coder_offset, k, "coder", byte_signature, false) + void java_lang_String::compute_offsets() { - assert(!initialized, "offsets should be initialized only once"); + if (initialized) { + return; + } InstanceKlass* k = SystemDictionary::String_klass(); - compute_offset(value_offset, k, vmSymbols::value_name(), vmSymbols::byte_array_signature()); - compute_offset(hash_offset, k, "hash", vmSymbols::int_signature()); - compute_offset(coder_offset, k, "coder", vmSymbols::byte_signature()); + STRING_FIELDS_DO(FIELD_COMPUTE_OFFSET); initialized = true; } +#if INCLUDE_CDS +void java_lang_String::serialize(SerializeClosure* f) { + STRING_FIELDS_DO(FIELD_SERIALIZE_OFFSET); + f->do_u4((u4*)&initialized); +} +#endif + class CompactStringsFixup : public FieldClosure { private: bool _value; @@ -731,12 +763,17 @@ break; case T_OBJECT: { - #ifdef ASSERT - TempNewSymbol sym = SymbolTable::new_symbol("Ljava/lang/String;", CHECK); - assert(fd->signature() == sym, "just checking"); - #endif - oop string = fd->string_initial_value(CHECK); - mirror()->obj_field_put(fd->offset(), string); + assert(fd->signature() == vmSymbols::string_signature(), + "just checking"); + if (DumpSharedSpaces && oopDesc::is_archive_object(mirror())) { + // Archive the String field and update the pointer. + oop s = mirror()->obj_field(fd->offset()); + oop archived_s = StringTable::create_archived_string(s, CHECK); + mirror()->obj_field_put(fd->offset(), archived_s); + } else { + oop string = fd->string_initial_value(CHECK); + mirror()->obj_field_put(fd->offset(), string); + } } break; default: @@ -764,6 +801,21 @@ } } } + + if (k->is_shared() && k->has_raw_archived_mirror()) { + if (MetaspaceShared::open_archive_heap_region_mapped()) { + oop m = k->archived_java_mirror(); + assert(m != NULL, "archived mirror is NULL"); + assert(oopDesc::is_archive_object(m), "must be archived mirror object"); + Handle m_h(THREAD, m); + // restore_archived_mirror() clears the klass' _has_raw_archived_mirror flag + restore_archived_mirror(k, m_h, Handle(), Handle(), Handle(), CHECK); + return; + } else { + k->set_java_mirror_handle(NULL); + k->clear_has_raw_archived_mirror(); + } + } create_mirror(k, Handle(), Handle(), Handle(), CHECK); } @@ -916,6 +968,277 @@ } } +#if INCLUDE_CDS_JAVA_HEAP +// Clears mirror fields. Static final fields with initial values are reloaded +// from constant pool. The object identity hash is in the object header and is +// not affected. +class ResetMirrorField: public FieldClosure { + private: + Handle _m; + + public: + ResetMirrorField(Handle mirror) : _m(mirror) {} + + void do_field(fieldDescriptor* fd) { + assert(DumpSharedSpaces, "dump time only"); + assert(_m.not_null(), "Mirror cannot be NULL"); + + if (fd->is_static() && fd->has_initial_value()) { + initialize_static_field(fd, _m, Thread::current()); + return; + } + + BasicType ft = fd->field_type(); + switch (ft) { + case T_BYTE: + _m()->byte_field_put(fd->offset(), 0); + break; + case T_CHAR: + _m()->char_field_put(fd->offset(), 0); + break; + case T_DOUBLE: + _m()->double_field_put(fd->offset(), 0); + break; + case T_FLOAT: + _m()->float_field_put(fd->offset(), 0); + break; + case T_INT: + _m()->int_field_put(fd->offset(), 0); + break; + case T_LONG: + _m()->long_field_put(fd->offset(), 0); + break; + case T_SHORT: + _m()->short_field_put(fd->offset(), 0); + break; + case T_BOOLEAN: + _m()->bool_field_put(fd->offset(), false); + break; + case T_ARRAY: + case T_OBJECT: { + // It might be useful to cache the String field, but + // for now just clear out any reference field + oop o = _m()->obj_field(fd->offset()); + _m()->obj_field_put(fd->offset(), NULL); + break; + } + default: + ShouldNotReachHere(); + break; + } + } +}; + +void java_lang_Class::archive_basic_type_mirrors(TRAPS) { + assert(MetaspaceShared::is_heap_object_archiving_allowed(), + "MetaspaceShared::is_heap_object_archiving_allowed() must be true"); + + for (int t = 0; t <= T_VOID; t++) { + oop m = Universe::_mirrors[t]; + if (m != NULL) { + // Update the field at _array_klass_offset to point to the relocated array klass. + oop archived_m = MetaspaceShared::archive_heap_object(m, THREAD); + Klass *ak = (Klass*)(archived_m->metadata_field(_array_klass_offset)); + assert(ak != NULL || t == T_VOID, "should not be NULL"); + if (ak != NULL) { + Klass *reloc_ak = MetaspaceShared::get_relocated_klass(ak); + archived_m->metadata_field_put(_array_klass_offset, reloc_ak); + } + + // Clear the fields. Just to be safe + Klass *k = m->klass(); + Handle archived_mirror_h(THREAD, archived_m); + ResetMirrorField reset(archived_mirror_h); + InstanceKlass::cast(k)->do_nonstatic_fields(&reset); + + log_trace(cds, mirror)("Archived %s mirror object from " PTR_FORMAT " ==> " PTR_FORMAT, + type2name((BasicType)t), p2i(Universe::_mirrors[t]), p2i(archived_m)); + + Universe::_mirrors[t] = archived_m; + } + } + + assert(Universe::_mirrors[T_INT] != NULL && + Universe::_mirrors[T_FLOAT] != NULL && + Universe::_mirrors[T_DOUBLE] != NULL && + Universe::_mirrors[T_BYTE] != NULL && + Universe::_mirrors[T_BOOLEAN] != NULL && + Universe::_mirrors[T_CHAR] != NULL && + Universe::_mirrors[T_LONG] != NULL && + Universe::_mirrors[T_SHORT] != NULL && + Universe::_mirrors[T_VOID] != NULL, "sanity"); + + Universe::set_int_mirror(Universe::_mirrors[T_INT]); + Universe::set_float_mirror(Universe::_mirrors[T_FLOAT]); + Universe::set_double_mirror(Universe::_mirrors[T_DOUBLE]); + Universe::set_byte_mirror(Universe::_mirrors[T_BYTE]); + Universe::set_bool_mirror(Universe::_mirrors[T_BOOLEAN]); + Universe::set_char_mirror(Universe::_mirrors[T_CHAR]); + Universe::set_long_mirror(Universe::_mirrors[T_LONG]); + Universe::set_short_mirror(Universe::_mirrors[T_SHORT]); + Universe::set_void_mirror(Universe::_mirrors[T_VOID]); +} + +// +// After the mirror object is successfully archived, the archived +// klass is set with _has_archived_raw_mirror flag. +// +// The _has_archived_raw_mirror flag is cleared at runtime when the +// archived mirror is restored. If archived java heap data cannot +// be used at runtime, new mirror object is created for the shared +// class. The _has_archived_raw_mirror is cleared also during the process. +oop java_lang_Class::archive_mirror(Klass* k, TRAPS) { + assert(MetaspaceShared::is_heap_object_archiving_allowed(), + "MetaspaceShared::is_heap_object_archiving_allowed() must be true"); + + // Mirror is already archived + if (k->has_raw_archived_mirror()) { + assert(k->archived_java_mirror_raw() != NULL, "no archived mirror"); + return k->archived_java_mirror_raw(); + } + + // No mirror + oop mirror = k->java_mirror(); + if (mirror == NULL) { + return NULL; + } + + if (k->is_instance_klass()) { + InstanceKlass *ik = InstanceKlass::cast(k); + assert(ik->signers() == NULL && !k->has_signer_and_not_archived(), + "class with signer cannot be supported"); + + if (!(ik->is_shared_boot_class() || ik->is_shared_platform_class() || + ik->is_shared_app_class())) { + // Archiving mirror for classes from non-builtin loaders is not + // supported. Clear the _java_mirror within the archived class. + k->set_java_mirror_handle(NULL); + return NULL; + } + } + + // Now start archiving the mirror object + oop archived_mirror = MetaspaceShared::archive_heap_object(mirror, THREAD); + if (archived_mirror == NULL) { + return NULL; + } + + archived_mirror = process_archived_mirror(k, mirror, archived_mirror, THREAD); + if (archived_mirror == NULL) { + return NULL; + } + + k->set_archived_java_mirror_raw(archived_mirror); + + k->set_has_raw_archived_mirror(); + + ResourceMark rm; + log_trace(cds, mirror)("Archived %s mirror object from " PTR_FORMAT " ==> " PTR_FORMAT, + k->external_name(), p2i(mirror), p2i(archived_mirror)); + + return archived_mirror; +} + +// The process is based on create_mirror(). +oop java_lang_Class::process_archived_mirror(Klass* k, oop mirror, + oop archived_mirror, + Thread *THREAD) { + // Clear nonstatic fields in archived mirror. Some of the fields will be set + // to archived metadata and objects below. + Klass *c = archived_mirror->klass(); + Handle archived_mirror_h(THREAD, archived_mirror); + ResetMirrorField reset(archived_mirror_h); + InstanceKlass::cast(c)->do_nonstatic_fields(&reset); + + if (k->is_array_klass()) { + oop archived_comp_mirror; + if (k->is_typeArray_klass()) { + // The primitive type mirrors are already archived. Get the archived mirror. + oop comp_mirror = java_lang_Class::component_mirror(mirror); + archived_comp_mirror = MetaspaceShared::find_archived_heap_object(comp_mirror); + assert(archived_comp_mirror != NULL, "Must be"); + } else { + assert(k->is_objArray_klass(), "Must be"); + Klass* element_klass = ObjArrayKlass::cast(k)->element_klass(); + assert(element_klass != NULL, "Must have an element klass"); + archived_comp_mirror = archive_mirror(element_klass, THREAD); + if (archived_comp_mirror == NULL) { + return NULL; + } + } + java_lang_Class::set_component_mirror(archived_mirror, archived_comp_mirror); + } else { + assert(k->is_instance_klass(), "Must be"); + + // Reset local static fields in the mirror + InstanceKlass::cast(k)->do_local_static_fields(&reset); + + java_lang_Class:set_init_lock(archived_mirror, NULL); + + set_protection_domain(archived_mirror, NULL); + } + + // clear class loader and mirror_module_field + set_class_loader(archived_mirror, NULL); + set_module(archived_mirror, NULL); + + // The archived mirror's field at _klass_offset is still pointing to the original + // klass. Updated the field in the archived mirror to point to the relocated + // klass in the archive. + Klass *reloc_k = MetaspaceShared::get_relocated_klass(as_Klass(mirror)); + log_debug(cds, mirror)("Relocate mirror metadata field at _klass_offset from " PTR_FORMAT " ==> " PTR_FORMAT, + p2i(as_Klass(mirror)), p2i(reloc_k)); + archived_mirror->metadata_field_put(_klass_offset, reloc_k); + + // The field at _array_klass_offset is pointing to the original one dimension + // higher array klass if exists. Relocate the pointer. + Klass *arr = array_klass_acquire(mirror); + if (arr != NULL) { + Klass *reloc_arr = MetaspaceShared::get_relocated_klass(arr); + log_debug(cds, mirror)("Relocate mirror metadata field at _array_klass_offset from " PTR_FORMAT " ==> " PTR_FORMAT, + p2i(arr), p2i(reloc_arr)); + archived_mirror->metadata_field_put(_array_klass_offset, reloc_arr); + } + return archived_mirror; +} + +// After the archived mirror object is restored, the shared klass' +// _has_raw_archived_mirror flag is cleared +void java_lang_Class::restore_archived_mirror(Klass *k, Handle mirror, + Handle class_loader, Handle module, + Handle protection_domain, TRAPS) { + + // The java.lang.Class field offsets were archived and reloaded from archive. + // No need to put classes on the fixup_mirror_list before java.lang.Class + // is loaded. + + if (!k->is_array_klass()) { + // - local static final fields with initial values were initialized at dump time + + // create the init_lock + typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK); + set_init_lock(mirror(), r); + + if (protection_domain.not_null()) { + set_protection_domain(mirror(), protection_domain()); + } + } + + assert(class_loader() == k->class_loader(), "should be same"); + if (class_loader.not_null()) { + set_class_loader(mirror(), class_loader()); + } + + k->set_java_mirror(mirror); + k->clear_has_raw_archived_mirror(); + + set_mirror_module_field(k, mirror, module, THREAD); + + ResourceMark rm; + log_trace(cds, mirror)("Restored %s archived mirror " PTR_FORMAT, k->external_name(), p2i(mirror())); +} +#endif // INCLUDE_CDS_JAVA_HEAP + void java_lang_Class::fixup_module_field(Klass* k, Handle module) { assert(_module_offset != 0, "must have been computed already"); java_lang_Class::set_module(k->java_mirror(), module()); @@ -1167,15 +1490,21 @@ bool java_lang_Class::offsets_computed = false; int java_lang_Class::classRedefinedCount_offset = -1; +#define CLASS_FIELDS_DO(macro) \ + macro(classRedefinedCount_offset, k, "classRedefinedCount", int_signature, false) ; \ + macro(_class_loader_offset, k, "classLoader", classloader_signature, false); \ + macro(_component_mirror_offset, k, "componentType", class_signature, false); \ + macro(_module_offset, k, "module", module_signature, false) + void java_lang_Class::compute_offsets() { - assert(!offsets_computed, "offsets should be initialized only once"); + if (offsets_computed) { + return; + } + offsets_computed = true; InstanceKlass* k = SystemDictionary::Class_klass(); - compute_offset(classRedefinedCount_offset, k, "classRedefinedCount", vmSymbols::int_signature()); - compute_offset(_class_loader_offset, k, "classLoader", vmSymbols::classloader_signature()); - compute_offset(_component_mirror_offset, k, "componentType", vmSymbols::class_signature()); - compute_offset(_module_offset, k, "module", vmSymbols::module_signature()); + CLASS_FIELDS_DO(FIELD_COMPUTE_OFFSET); // Init lock is a C union with component_mirror. Only instanceKlass mirrors have // init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops @@ -1185,6 +1514,17 @@ CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } +#if INCLUDE_CDS +void java_lang_Class::serialize(SerializeClosure* f) { + f->do_u4((u4*)&offsets_computed); + f->do_u4((u4*)&_init_lock_offset); + + CLASS_FIELDS_DO(FIELD_SERIALIZE_OFFSET); + + CLASS_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET); +} +#endif + int java_lang_Class::classRedefinedCount(oop the_class_mirror) { if (classRedefinedCount_offset == -1) { // If we don't have an offset for it then just return -1 as a marker. @@ -1226,28 +1566,33 @@ int java_lang_Thread::_park_blocker_offset = 0; int java_lang_Thread::_park_event_offset = 0 ; +#define THREAD_FIELDS_DO(macro) \ + macro(_name_offset, k, vmSymbols::name_name(), string_signature, false); \ + macro(_group_offset, k, vmSymbols::group_name(), threadgroup_signature, false); \ + macro(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), classloader_signature, false); \ + macro(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(), accesscontrolcontext_signature, false); \ + macro(_priority_offset, k, vmSymbols::priority_name(), int_signature, false); \ + macro(_daemon_offset, k, vmSymbols::daemon_name(), bool_signature, false); \ + macro(_eetop_offset, k, "eetop", long_signature, false); \ + macro(_stillborn_offset, k, "stillborn", bool_signature, false); \ + macro(_stackSize_offset, k, "stackSize", long_signature, false); \ + macro(_tid_offset, k, "tid", long_signature, false); \ + macro(_thread_status_offset, k, "threadStatus", int_signature, false); \ + macro(_park_blocker_offset, k, "parkBlocker", object_signature, false); \ + macro(_park_event_offset, k, "nativeParkEventPointer", long_signature, false) void java_lang_Thread::compute_offsets() { assert(_group_offset == 0, "offsets should be initialized only once"); InstanceKlass* k = SystemDictionary::Thread_klass(); - compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); - compute_offset(_group_offset, k, vmSymbols::group_name(), vmSymbols::threadgroup_signature()); - compute_offset(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), - vmSymbols::classloader_signature()); - compute_offset(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(), - vmSymbols::accesscontrolcontext_signature()); - compute_offset(_priority_offset, k, vmSymbols::priority_name(), vmSymbols::int_signature()); - compute_offset(_daemon_offset, k, vmSymbols::daemon_name(), vmSymbols::bool_signature()); - compute_offset(_eetop_offset, k, "eetop", vmSymbols::long_signature()); - compute_offset(_stillborn_offset, k, "stillborn", vmSymbols::bool_signature()); - compute_offset(_stackSize_offset, k, "stackSize", vmSymbols::long_signature()); - compute_offset(_tid_offset, k, "tid", vmSymbols::long_signature()); - compute_offset(_thread_status_offset, k, "threadStatus", vmSymbols::int_signature()); - compute_offset(_park_blocker_offset, k, "parkBlocker", vmSymbols::object_signature()); - compute_offset(_park_event_offset, k, "nativeParkEventPointer", vmSymbols::long_signature()); -} - + THREAD_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_Thread::serialize(SerializeClosure* f) { + THREAD_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif JavaThread* java_lang_Thread::thread(oop java_thread) { return (JavaThread*)java_thread->address_field(_eetop_offset); @@ -1477,32 +1822,47 @@ return java_thread_group->bool_field(_daemon_offset) != 0; } +#define THREADGROUP_FIELDS_DO(macro) \ + macro(_parent_offset, k, vmSymbols::parent_name(), threadgroup_signature, false); \ + macro(_name_offset, k, vmSymbols::name_name(), string_signature, false); \ + macro(_threads_offset, k, vmSymbols::threads_name(), thread_array_signature, false); \ + macro(_groups_offset, k, vmSymbols::groups_name(), threadgroup_array_signature, false); \ + macro(_maxPriority_offset, k, vmSymbols::maxPriority_name(), int_signature, false); \ + macro(_destroyed_offset, k, vmSymbols::destroyed_name(), bool_signature, false); \ + macro(_daemon_offset, k, vmSymbols::daemon_name(), bool_signature, false); \ + macro(_nthreads_offset, k, vmSymbols::nthreads_name(), int_signature, false); \ + macro(_ngroups_offset, k, vmSymbols::ngroups_name(), int_signature, false) + void java_lang_ThreadGroup::compute_offsets() { assert(_parent_offset == 0, "offsets should be initialized only once"); InstanceKlass* k = SystemDictionary::ThreadGroup_klass(); - - compute_offset(_parent_offset, k, vmSymbols::parent_name(), vmSymbols::threadgroup_signature()); - compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); - compute_offset(_threads_offset, k, vmSymbols::threads_name(), vmSymbols::thread_array_signature()); - compute_offset(_groups_offset, k, vmSymbols::groups_name(), vmSymbols::threadgroup_array_signature()); - compute_offset(_maxPriority_offset, k, vmSymbols::maxPriority_name(), vmSymbols::int_signature()); - compute_offset(_destroyed_offset, k, vmSymbols::destroyed_name(), vmSymbols::bool_signature()); - compute_offset(_daemon_offset, k, vmSymbols::daemon_name(), vmSymbols::bool_signature()); - compute_offset(_nthreads_offset, k, vmSymbols::nthreads_name(), vmSymbols::int_signature()); - compute_offset(_ngroups_offset, k, vmSymbols::ngroups_name(), vmSymbols::int_signature()); -} - + THREADGROUP_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_ThreadGroup::serialize(SerializeClosure* f) { + THREADGROUP_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif + +#define THROWABLE_FIELDS_DO(macro) \ + macro(backtrace_offset, k, "backtrace", object_signature, false); \ + macro(detailMessage_offset, k, "detailMessage", string_signature, false); \ + macro(stackTrace_offset, k, "stackTrace", java_lang_StackTraceElement_array, false); \ + macro(depth_offset, k, "depth", int_signature, false); \ + macro(static_unassigned_stacktrace_offset, k, "UNASSIGNED_STACK", java_lang_StackTraceElement_array, true) void java_lang_Throwable::compute_offsets() { InstanceKlass* k = SystemDictionary::Throwable_klass(); - compute_offset(backtrace_offset, k, "backtrace", vmSymbols::object_signature()); - compute_offset(detailMessage_offset, k, "detailMessage", vmSymbols::string_signature()); - compute_offset(stackTrace_offset, k, "stackTrace", vmSymbols::java_lang_StackTraceElement_array()); - compute_offset(depth_offset, k, "depth", vmSymbols::int_signature()); - compute_offset(static_unassigned_stacktrace_offset, k, "UNASSIGNED_STACK", vmSymbols::java_lang_StackTraceElement_array(), - /*is_static*/true); -} + THROWABLE_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_Throwable::serialize(SerializeClosure* f) { + THROWABLE_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif oop java_lang_Throwable::unassigned_stacktrace() { InstanceKlass* ik = SystemDictionary::Throwable_klass(); @@ -2268,25 +2628,53 @@ java_lang_StackTraceElement::fill_in(stack_trace_element, holder, method, version, bci, name, CHECK); } +#define STACKFRAMEINFO_FIELDS_DO(macro) \ + macro(_memberName_offset, k, "memberName", object_signature, false); \ + macro(_bci_offset, k, "bci", short_signature, false) + void java_lang_StackFrameInfo::compute_offsets() { InstanceKlass* k = SystemDictionary::StackFrameInfo_klass(); - compute_offset(_memberName_offset, k, "memberName", vmSymbols::object_signature()); - compute_offset(_bci_offset, k, "bci", vmSymbols::short_signature()); + STACKFRAMEINFO_FIELDS_DO(FIELD_COMPUTE_OFFSET); STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } +#if INCLUDE_CDS +void java_lang_StackFrameInfo::serialize(SerializeClosure* f) { + STACKFRAMEINFO_FIELDS_DO(FIELD_SERIALIZE_OFFSET); + STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET); +} +#endif + +#define LIVESTACKFRAMEINFO_FIELDS_DO(macro) \ + macro(_monitors_offset, k, "monitors", object_array_signature, false); \ + macro(_locals_offset, k, "locals", object_array_signature, false); \ + macro(_operands_offset, k, "operands", object_array_signature, false); \ + macro(_mode_offset, k, "mode", int_signature, false) + void java_lang_LiveStackFrameInfo::compute_offsets() { InstanceKlass* k = SystemDictionary::LiveStackFrameInfo_klass(); - compute_offset(_monitors_offset, k, "monitors", vmSymbols::object_array_signature()); - compute_offset(_locals_offset, k, "locals", vmSymbols::object_array_signature()); - compute_offset(_operands_offset, k, "operands", vmSymbols::object_array_signature()); - compute_offset(_mode_offset, k, "mode", vmSymbols::int_signature()); -} + LIVESTACKFRAMEINFO_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_LiveStackFrameInfo::serialize(SerializeClosure* f) { + LIVESTACKFRAMEINFO_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif + +#define ACCESSIBLEOBJECT_FIELDS_DO(macro) \ + macro(override_offset, k, "override", bool_signature, false) void java_lang_reflect_AccessibleObject::compute_offsets() { InstanceKlass* k = SystemDictionary::reflect_AccessibleObject_klass(); - compute_offset(override_offset, k, "override", vmSymbols::bool_signature()); -} + ACCESSIBLEOBJECT_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_reflect_AccessibleObject::serialize(SerializeClosure* f) { + ACCESSIBLEOBJECT_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif jboolean java_lang_reflect_AccessibleObject::override(oop reflect) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); @@ -2298,27 +2686,36 @@ reflect->bool_field_put(override_offset, (int) value); } +#define METHOD_FIELDS_DO(macro) \ + macro(clazz_offset, k, vmSymbols::clazz_name(), class_signature, false); \ + macro(name_offset, k, vmSymbols::name_name(), string_signature, false); \ + macro(returnType_offset, k, vmSymbols::returnType_name(), class_signature, false); \ + macro(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), class_array_signature, false); \ + macro(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), class_array_signature, false); \ + macro(slot_offset, k, vmSymbols::slot_name(), int_signature, false); \ + macro(modifiers_offset, k, vmSymbols::modifiers_name(), int_signature, false); \ + macro##_OPTIONAL(signature_offset, k, vmSymbols::signature_name(), string_signature); \ + macro##_OPTIONAL(annotations_offset, k, vmSymbols::annotations_name(), byte_array_signature); \ + macro##_OPTIONAL(parameter_annotations_offset, k, vmSymbols::parameter_annotations_name(), byte_array_signature); \ + macro##_OPTIONAL(annotation_default_offset, k, vmSymbols::annotation_default_name(), byte_array_signature); \ + macro##_OPTIONAL(type_annotations_offset, k, vmSymbols::type_annotations_name(), byte_array_signature) + void java_lang_reflect_Method::compute_offsets() { InstanceKlass* k = SystemDictionary::reflect_Method_klass(); - compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature()); - compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); - compute_offset(returnType_offset, k, vmSymbols::returnType_name(), vmSymbols::class_signature()); - compute_offset(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), vmSymbols::class_array_signature()); - compute_offset(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), vmSymbols::class_array_signature()); - compute_offset(slot_offset, k, vmSymbols::slot_name(), vmSymbols::int_signature()); - compute_offset(modifiers_offset, k, vmSymbols::modifiers_name(), vmSymbols::int_signature()); // The generic signature and annotations fields are only present in 1.5 signature_offset = -1; annotations_offset = -1; parameter_annotations_offset = -1; annotation_default_offset = -1; type_annotations_offset = -1; - compute_optional_offset(signature_offset, k, vmSymbols::signature_name(), vmSymbols::string_signature()); - compute_optional_offset(annotations_offset, k, vmSymbols::annotations_name(), vmSymbols::byte_array_signature()); - compute_optional_offset(parameter_annotations_offset, k, vmSymbols::parameter_annotations_name(), vmSymbols::byte_array_signature()); - compute_optional_offset(annotation_default_offset, k, vmSymbols::annotation_default_name(), vmSymbols::byte_array_signature()); - compute_optional_offset(type_annotations_offset, k, vmSymbols::type_annotations_name(), vmSymbols::byte_array_signature()); -} + METHOD_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_reflect_Method::serialize(SerializeClosure* f) { + METHOD_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif Handle java_lang_reflect_Method::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); @@ -2479,23 +2876,33 @@ method->obj_field_put(type_annotations_offset, value); } +#define CONSTRUCTOR_FIELDS_DO(macro) \ + macro(clazz_offset, k, vmSymbols::clazz_name(), class_signature, false); \ + macro(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), class_array_signature, false); \ + macro(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), class_array_signature, false); \ + macro(slot_offset, k, vmSymbols::slot_name(), int_signature, false); \ + macro(modifiers_offset, k, vmSymbols::modifiers_name(), int_signature, false); \ + macro##_OPTIONAL(signature_offset, k, vmSymbols::signature_name(), string_signature); \ + macro##_OPTIONAL(annotations_offset, k, vmSymbols::annotations_name(), byte_array_signature); \ + macro##_OPTIONAL(parameter_annotations_offset, k, vmSymbols::parameter_annotations_name(), byte_array_signature); \ + macro##_OPTIONAL(type_annotations_offset, k, vmSymbols::type_annotations_name(), byte_array_signature) + + void java_lang_reflect_Constructor::compute_offsets() { InstanceKlass* k = SystemDictionary::reflect_Constructor_klass(); - compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature()); - compute_offset(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), vmSymbols::class_array_signature()); - compute_offset(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), vmSymbols::class_array_signature()); - compute_offset(slot_offset, k, vmSymbols::slot_name(), vmSymbols::int_signature()); - compute_offset(modifiers_offset, k, vmSymbols::modifiers_name(), vmSymbols::int_signature()); // The generic signature and annotations fields are only present in 1.5 signature_offset = -1; annotations_offset = -1; parameter_annotations_offset = -1; type_annotations_offset = -1; - compute_optional_offset(signature_offset, k, vmSymbols::signature_name(), vmSymbols::string_signature()); - compute_optional_offset(annotations_offset, k, vmSymbols::annotations_name(), vmSymbols::byte_array_signature()); - compute_optional_offset(parameter_annotations_offset, k, vmSymbols::parameter_annotations_name(), vmSymbols::byte_array_signature()); - compute_optional_offset(type_annotations_offset, k, vmSymbols::type_annotations_name(), vmSymbols::byte_array_signature()); -} + CONSTRUCTOR_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_reflect_Constructor::serialize(SerializeClosure* f) { + CONSTRUCTOR_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif Handle java_lang_reflect_Constructor::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); @@ -2621,21 +3028,30 @@ constructor->obj_field_put(type_annotations_offset, value); } +#define FIELD_FIELDS_DO(macro) \ + macro(clazz_offset, k, vmSymbols::clazz_name(), class_signature, false); \ + macro(name_offset, k, vmSymbols::name_name(), string_signature, false); \ + macro(type_offset, k, vmSymbols::type_name(), class_signature, false); \ + macro(slot_offset, k, vmSymbols::slot_name(), int_signature, false); \ + macro(modifiers_offset, k, vmSymbols::modifiers_name(), int_signature, false); \ + macro##_OPTIONAL(signature_offset, k, vmSymbols::signature_name(), string_signature); \ + macro##_OPTIONAL(annotations_offset, k, vmSymbols::annotations_name(), byte_array_signature); \ + macro##_OPTIONAL(type_annotations_offset, k, vmSymbols::type_annotations_name(), byte_array_signature) + void java_lang_reflect_Field::compute_offsets() { InstanceKlass* k = SystemDictionary::reflect_Field_klass(); - compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature()); - compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); - compute_offset(type_offset, k, vmSymbols::type_name(), vmSymbols::class_signature()); - compute_offset(slot_offset, k, vmSymbols::slot_name(), vmSymbols::int_signature()); - compute_offset(modifiers_offset, k, vmSymbols::modifiers_name(), vmSymbols::int_signature()); // The generic signature and annotations fields are only present in 1.5 signature_offset = -1; annotations_offset = -1; type_annotations_offset = -1; - compute_optional_offset(signature_offset, k, vmSymbols::signature_name(), vmSymbols::string_signature()); - compute_optional_offset(annotations_offset, k, vmSymbols::annotations_name(), vmSymbols::byte_array_signature()); - compute_optional_offset(type_annotations_offset, k, vmSymbols::type_annotations_name(), vmSymbols::byte_array_signature()); -} + FIELD_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_reflect_Field::serialize(SerializeClosure* f) { + FIELD_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif Handle java_lang_reflect_Field::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); @@ -2745,19 +3161,37 @@ field->obj_field_put(type_annotations_offset, value); } +#define CONSTANTPOOL_FIELDS_DO(macro) \ + macro(_oop_offset, k, "constantPoolOop", object_signature, false) + void reflect_ConstantPool::compute_offsets() { InstanceKlass* k = SystemDictionary::reflect_ConstantPool_klass(); // The field is called ConstantPool* in the sun.reflect.ConstantPool class. - compute_offset(_oop_offset, k, "constantPoolOop", vmSymbols::object_signature()); -} + CONSTANTPOOL_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void reflect_ConstantPool::serialize(SerializeClosure* f) { + CONSTANTPOOL_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif + +#define PARAMETER_FIELDS_DO(macro) \ + macro(name_offset, k, vmSymbols::name_name(), string_signature, false); \ + macro(modifiers_offset, k, vmSymbols::modifiers_name(), int_signature, false); \ + macro(index_offset, k, vmSymbols::index_name(), int_signature, false); \ + macro(executable_offset, k, vmSymbols::executable_name(), executable_signature, false) void java_lang_reflect_Parameter::compute_offsets() { InstanceKlass* k = SystemDictionary::reflect_Parameter_klass(); - compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); - compute_offset(modifiers_offset, k, vmSymbols::modifiers_name(), vmSymbols::int_signature()); - compute_offset(index_offset, k, vmSymbols::index_name(), vmSymbols::int_signature()); - compute_offset(executable_offset, k, vmSymbols::executable_name(), vmSymbols::executable_signature()); -} + PARAMETER_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_reflect_Parameter::serialize(SerializeClosure* f) { + PARAMETER_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif Handle java_lang_reflect_Parameter::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); @@ -2829,13 +3263,22 @@ return jlmh; } +#define MODULE_FIELDS_DO(macro) \ + macro(loader_offset, k, vmSymbols::loader_name(), classloader_signature, false); \ + macro(name_offset, k, vmSymbols::name_name(), string_signature, false) + void java_lang_Module::compute_offsets() { InstanceKlass* k = SystemDictionary::Module_klass(); - compute_offset(loader_offset, k, vmSymbols::loader_name(), vmSymbols::classloader_signature()); - compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); + MODULE_FIELDS_DO(FIELD_COMPUTE_OFFSET); MODULE_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } +#if INCLUDE_CDS +void java_lang_Module::serialize(SerializeClosure* f) { + MODULE_FIELDS_DO(FIELD_SERIALIZE_OFFSET); + MODULE_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET); +} +#endif oop java_lang_Module::loader(oop module) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); @@ -2912,10 +3355,19 @@ return InstanceKlass::cast(k)->constants(); } +#define UNSAFESTATICFIELDACCESSORIMPL_FIELDS_DO(macro) \ + macro(_base_offset, k, "base", object_signature, false) + void reflect_UnsafeStaticFieldAccessorImpl::compute_offsets() { InstanceKlass* k = SystemDictionary::reflect_UnsafeStaticFieldAccessorImpl_klass(); - compute_offset(_base_offset, k, "base", vmSymbols::object_signature()); -} + UNSAFESTATICFIELDACCESSORIMPL_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void reflect_UnsafeStaticFieldAccessorImpl::serialize(SerializeClosure* f) { + UNSAFESTATICFIELDACCESSORIMPL_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif oop java_lang_boxing_object::initialize_and_allocate(BasicType type, TRAPS) { Klass* k = SystemDictionary::box_klass(type); @@ -3074,11 +3526,20 @@ // Support for java_lang_ref_SoftReference // +#define SOFTREFERENCE_FIELDS_DO(macro) \ + macro(timestamp_offset, k, "timestamp", long_signature, false); \ + macro(static_clock_offset, k, "clock", long_signature, true) + void java_lang_ref_SoftReference::compute_offsets() { InstanceKlass* k = SystemDictionary::SoftReference_klass(); - compute_offset(timestamp_offset, k, "timestamp", vmSymbols::long_signature()); - compute_offset(static_clock_offset, k, "clock", vmSymbols::long_signature(), true); -} + SOFTREFERENCE_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_ref_SoftReference::serialize(SerializeClosure* f) { + SOFTREFERENCE_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif jlong java_lang_ref_SoftReference::timestamp(oop ref) { return ref->long_field(timestamp_offset); @@ -3107,10 +3568,19 @@ return dmh->obj_field(member_offset_in_bytes()); } +#define DIRECTMETHODHANDLE_FIELDS_DO(macro) \ + macro(_member_offset, k, "member", java_lang_invoke_MemberName_signature, false) + void java_lang_invoke_DirectMethodHandle::compute_offsets() { InstanceKlass* k = SystemDictionary::DirectMethodHandle_klass(); - compute_offset(_member_offset, k, "member", vmSymbols::java_lang_invoke_MemberName_signature()); -} + DIRECTMETHODHANDLE_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_invoke_DirectMethodHandle::serialize(SerializeClosure* f) { + DIRECTMETHODHANDLE_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif // Support for java_lang_invoke_MethodHandle @@ -3129,33 +3599,67 @@ int java_lang_invoke_LambdaForm::_vmentry_offset; +#define METHODHANDLE_FIELDS_DO(macro) \ + macro(_type_offset, k, vmSymbols::type_name(), java_lang_invoke_MethodType_signature, false); \ + macro(_form_offset, k, "form", java_lang_invoke_LambdaForm_signature, false) + void java_lang_invoke_MethodHandle::compute_offsets() { InstanceKlass* k = SystemDictionary::MethodHandle_klass(); - compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_lang_invoke_MethodType_signature()); - compute_offset(_form_offset, k, "form", vmSymbols::java_lang_invoke_LambdaForm_signature()); -} + METHODHANDLE_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_invoke_MethodHandle::serialize(SerializeClosure* f) { + METHODHANDLE_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif + +#define MEMBERNAME_FIELDS_DO(macro) \ + macro(_clazz_offset, k, vmSymbols::clazz_name(), class_signature, false); \ + macro(_name_offset, k, vmSymbols::name_name(), string_signature, false); \ + macro(_type_offset, k, vmSymbols::type_name(), object_signature, false); \ + macro(_flags_offset, k, vmSymbols::flags_name(), int_signature, false); \ + macro(_method_offset, k, vmSymbols::method_name(), java_lang_invoke_ResolvedMethodName_signature, false) void java_lang_invoke_MemberName::compute_offsets() { InstanceKlass* k = SystemDictionary::MemberName_klass(); - compute_offset(_clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature()); - compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); - compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::object_signature()); - compute_offset(_flags_offset, k, vmSymbols::flags_name(), vmSymbols::int_signature()); - compute_offset(_method_offset, k, vmSymbols::method_name(), vmSymbols::java_lang_invoke_ResolvedMethodName_signature()); + MEMBERNAME_FIELDS_DO(FIELD_COMPUTE_OFFSET); MEMBERNAME_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } +#if INCLUDE_CDS +void java_lang_invoke_MemberName::serialize(SerializeClosure* f) { + MEMBERNAME_FIELDS_DO(FIELD_SERIALIZE_OFFSET); + MEMBERNAME_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET); +} +#endif + void java_lang_invoke_ResolvedMethodName::compute_offsets() { InstanceKlass* k = SystemDictionary::ResolvedMethodName_klass(); assert(k != NULL, "jdk mismatch"); RESOLVEDMETHOD_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } +#if INCLUDE_CDS +void java_lang_invoke_ResolvedMethodName::serialize(SerializeClosure* f) { + RESOLVEDMETHOD_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET); +} +#endif + +#define LAMBDAFORM_FIELDS_DO(macro) \ + macro(_vmentry_offset, k, "vmentry", java_lang_invoke_MemberName_signature, false) + void java_lang_invoke_LambdaForm::compute_offsets() { InstanceKlass* k = SystemDictionary::LambdaForm_klass(); assert (k != NULL, "jdk mismatch"); - compute_offset(_vmentry_offset, k, "vmentry", vmSymbols::java_lang_invoke_MemberName_signature()); -} + LAMBDAFORM_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_invoke_LambdaForm::serialize(SerializeClosure* f) { + LAMBDAFORM_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif bool java_lang_invoke_LambdaForm::is_instance(oop obj) { return obj != NULL && is_subclass(obj->klass()); @@ -3294,11 +3798,20 @@ int java_lang_invoke_MethodType::_rtype_offset; int java_lang_invoke_MethodType::_ptypes_offset; +#define METHODTYPE_FIELDS_DO(macro) \ + macro(_rtype_offset, k, "rtype", class_signature, false); \ + macro(_ptypes_offset, k, "ptypes", class_array_signature, false) + void java_lang_invoke_MethodType::compute_offsets() { InstanceKlass* k = SystemDictionary::MethodType_klass(); - compute_offset(_rtype_offset, k, "rtype", vmSymbols::class_signature()); - compute_offset(_ptypes_offset, k, "ptypes", vmSymbols::class_array_signature()); -} + METHODTYPE_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_invoke_MethodType::serialize(SerializeClosure* f) { + METHODTYPE_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif void java_lang_invoke_MethodType::print_signature(oop mt, outputStream* st) { st->print("("); @@ -3379,12 +3892,20 @@ int java_lang_invoke_CallSite::_target_offset; int java_lang_invoke_CallSite::_context_offset; +#define CALLSITE_FIELDS_DO(macro) \ + macro(_target_offset, k, "target", java_lang_invoke_MethodHandle_signature, false); \ + macro(_context_offset, k, "context", java_lang_invoke_MethodHandleNatives_CallSiteContext_signature, false) + void java_lang_invoke_CallSite::compute_offsets() { InstanceKlass* k = SystemDictionary::CallSite_klass(); - compute_offset(_target_offset, k, "target", vmSymbols::java_lang_invoke_MethodHandle_signature()); - compute_offset(_context_offset, k, "context", - vmSymbols::java_lang_invoke_MethodHandleNatives_CallSiteContext_signature()); -} + CALLSITE_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_invoke_CallSite::serialize(SerializeClosure* f) { + CALLSITE_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif oop java_lang_invoke_CallSite::context(oop call_site) { assert(java_lang_invoke_CallSite::is_instance(call_site), ""); @@ -3402,6 +3923,12 @@ CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } +#if INCLUDE_CDS +void java_lang_invoke_MethodHandleNatives_CallSiteContext::serialize(SerializeClosure* f) { + CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET); +} +#endif + DependencyContext java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) { assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), ""); intptr_t* vmdeps_addr = (intptr_t*)call_site->field_addr(_vmdependencies_offset); @@ -3416,16 +3943,23 @@ int java_security_AccessControlContext::_isPrivileged_offset = 0; int java_security_AccessControlContext::_isAuthorized_offset = -1; +#define ACCESSCONTROLCONTEXT_FIELDS_DO(macro) \ + macro(_context_offset, k, "context", protectiondomain_signature, false); \ + macro(_privilegedContext_offset, k, "privilegedContext", accesscontrolcontext_signature, false); \ + macro(_isPrivileged_offset, k, "isPrivileged", bool_signature, false); \ + macro(_isAuthorized_offset, k, "isAuthorized", bool_signature, false) + void java_security_AccessControlContext::compute_offsets() { assert(_isPrivileged_offset == 0, "offsets should be initialized only once"); InstanceKlass* k = SystemDictionary::AccessControlContext_klass(); - - compute_offset(_context_offset, k, "context", vmSymbols::protectiondomain_signature()); - compute_offset(_privilegedContext_offset, k, "privilegedContext", vmSymbols::accesscontrolcontext_signature()); - compute_offset(_isPrivileged_offset, k, "isPrivileged", vmSymbols::bool_signature()); - compute_offset(_isAuthorized_offset, k, "isAuthorized", vmSymbols::bool_signature()); -} - + ACCESSCONTROLCONTEXT_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_security_AccessControlContext::serialize(SerializeClosure* f) { + ACCESSCONTROLCONTEXT_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif bool java_security_AccessControlContext::is_authorized(Handle context) { assert(context.not_null() && context->klass() == SystemDictionary::AccessControlContext_klass(), "Invalid type"); @@ -3469,25 +4003,29 @@ return HeapAccess<>::atomic_cmpxchg_at(new_data, loader, _loader_data_offset, expected_data); } +#define CLASSLOADER_FIELDS_DO(macro) \ + macro(parallelCapable_offset, k1, "parallelLockMap", concurrenthashmap_signature, false); \ + macro(name_offset, k1, vmSymbols::name_name(), string_signature, false); \ + macro(unnamedModule_offset, k1, "unnamedModule", module_signature, false); \ + macro(parent_offset, k1, "parent", classloader_signature, false) + void java_lang_ClassLoader::compute_offsets() { assert(!offsets_computed, "offsets should be initialized only once"); offsets_computed = true; InstanceKlass* k1 = SystemDictionary::ClassLoader_klass(); - compute_offset(parallelCapable_offset, - k1, "parallelLockMap", vmSymbols::concurrenthashmap_signature()); - - compute_offset(name_offset, - k1, vmSymbols::name_name(), vmSymbols::string_signature()); - - compute_offset(unnamedModule_offset, - k1, "unnamedModule", vmSymbols::module_signature()); - - compute_offset(parent_offset, k1, "parent", vmSymbols::classloader_signature()); + CLASSLOADER_FIELDS_DO(FIELD_COMPUTE_OFFSET); CLASSLOADER_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } +#if INCLUDE_CDS +void java_lang_ClassLoader::serialize(SerializeClosure* f) { + CLASSLOADER_FIELDS_DO(FIELD_SERIALIZE_OFFSET); + CLASSLOADER_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET); +} +#endif + oop java_lang_ClassLoader::parent(oop loader) { assert(is_instance(loader), "loader must be oop"); return loader->obj_field(parent_offset); @@ -3571,13 +4109,22 @@ // Support for java_lang_System // +#define SYSTEM_FIELDS_DO(macro) \ + macro(static_in_offset, k, "in", input_stream_signature, true); \ + macro(static_out_offset, k, "out", print_stream_signature, true); \ + macro(static_err_offset, k, "err", print_stream_signature, true); \ + macro(static_security_offset, k, "security", security_manager_signature, true) + void java_lang_System::compute_offsets() { InstanceKlass* k = SystemDictionary::System_klass(); - compute_offset(static_in_offset, k, "in", vmSymbols::input_stream_signature(), true); - compute_offset(static_out_offset, k, "out", vmSymbols::print_stream_signature(), true); - compute_offset(static_err_offset, k, "err", vmSymbols::print_stream_signature(), true); - compute_offset(static_security_offset, k, "security", vmSymbols::security_manager_signature(), true); -} + SYSTEM_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_System::serialize(SerializeClosure* f) { + SYSTEM_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif int java_lang_System::in_offset_in_bytes() { return static_in_offset; } int java_lang_System::out_offset_in_bytes() { return static_out_offset; } @@ -3683,19 +4230,27 @@ int reflect_ConstantPool::_oop_offset; int reflect_UnsafeStaticFieldAccessorImpl::_base_offset; +#define STACKTRACEELEMENT_FIELDS_DO(macro) \ + macro(declaringClassObject_offset, k, "declaringClassObject", class_signature, false); \ + macro(classLoaderName_offset, k, "classLoaderName", string_signature, false); \ + macro(moduleName_offset, k, "moduleName", string_signature, false); \ + macro(moduleVersion_offset, k, "moduleVersion", string_signature, false); \ + macro(declaringClass_offset, k, "declaringClass", string_signature, false); \ + macro(methodName_offset, k, "methodName", string_signature, false); \ + macro(fileName_offset, k, "fileName", string_signature, false); \ + macro(lineNumber_offset, k, "lineNumber", int_signature, false) // Support for java_lang_StackTraceElement void java_lang_StackTraceElement::compute_offsets() { InstanceKlass* k = SystemDictionary::StackTraceElement_klass(); - compute_offset(declaringClassObject_offset, k, "declaringClassObject", vmSymbols::class_signature()); - compute_offset(classLoaderName_offset, k, "classLoaderName", vmSymbols::string_signature()); - compute_offset(moduleName_offset, k, "moduleName", vmSymbols::string_signature()); - compute_offset(moduleVersion_offset, k, "moduleVersion", vmSymbols::string_signature()); - compute_offset(declaringClass_offset, k, "declaringClass", vmSymbols::string_signature()); - compute_offset(methodName_offset, k, "methodName", vmSymbols::string_signature()); - compute_offset(fileName_offset, k, "fileName", vmSymbols::string_signature()); - compute_offset(lineNumber_offset, k, "lineNumber", vmSymbols::int_signature()); -} + STACKTRACEELEMENT_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_StackTraceElement::serialize(SerializeClosure* f) { + STACKTRACEELEMENT_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif void java_lang_StackTraceElement::set_fileName(oop element, oop value) { element->obj_field_put(fileName_offset, value); @@ -3754,16 +4309,23 @@ } // Support for java Assertions - java_lang_AssertionStatusDirectives. +#define ASSERTIONSTATUSDIRECTIVES_FIELDS_DO(macro) \ + macro(classes_offset, k, "classes", string_array_signature, false); \ + macro(classEnabled_offset, k, "classEnabled", bool_array_signature, false); \ + macro(packages_offset, k, "packages", string_array_signature, false); \ + macro(packageEnabled_offset, k, "packageEnabled", bool_array_signature, false); \ + macro(deflt_offset, k, "deflt", bool_signature, false) void java_lang_AssertionStatusDirectives::compute_offsets() { InstanceKlass* k = SystemDictionary::AssertionStatusDirectives_klass(); - compute_offset(classes_offset, k, "classes", vmSymbols::string_array_signature()); - compute_offset(classEnabled_offset, k, "classEnabled", vmSymbols::bool_array_signature()); - compute_offset(packages_offset, k, "packages", vmSymbols::string_array_signature()); - compute_offset(packageEnabled_offset, k, "packageEnabled", vmSymbols::bool_array_signature()); - compute_offset(deflt_offset, k, "deflt", vmSymbols::bool_signature()); -} - + ASSERTIONSTATUSDIRECTIVES_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_AssertionStatusDirectives::serialize(SerializeClosure* f) { + ASSERTIONSTATUSDIRECTIVES_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif void java_lang_AssertionStatusDirectives::set_classes(oop o, oop val) { o->obj_field_put(classes_offset, val); @@ -3791,12 +4353,20 @@ return _limit_offset; } +#define BUFFER_FIELDS_DO(macro) \ + macro(_limit_offset, k, "limit", int_signature, false) void java_nio_Buffer::compute_offsets() { InstanceKlass* k = SystemDictionary::nio_Buffer_klass(); assert(k != NULL, "must be loaded in 1.4+"); - compute_offset(_limit_offset, k, "limit", vmSymbols::int_signature()); -} + BUFFER_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_nio_Buffer::serialize(SerializeClosure* f) { + BUFFER_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif void java_util_concurrent_locks_AbstractOwnableSynchronizer::initialize(TRAPS) { if (_owner_offset != 0) return; @@ -3835,6 +4405,10 @@ // Compute non-hard-coded field offsets of all the classes in this file void JavaClasses::compute_offsets() { + if (UseSharedSpaces) { + return; // field offsets are loaded from archive + } + // java_lang_Class::compute_offsets was called earlier in bootstrap java_lang_System::compute_offsets(); java_lang_ClassLoader::compute_offsets();
--- a/src/hotspot/share/classfile/javaClasses.hpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/classfile/javaClasses.hpp Fri Mar 02 17:25:55 2018 -0500 @@ -71,6 +71,7 @@ }; 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ static void compute_offsets(); public: + static void serialize(SerializeClosure* f) NOT_CDS_RETURN; + // Allocation static Handle create(TRAPS); @@ -615,6 +634,8 @@ static void compute_offsets(); public: + static void serialize(SerializeClosure* f) NOT_CDS_RETURN; + // Allocation static Handle create(TRAPS); @@ -673,6 +694,8 @@ static void compute_offsets(); public: + static void serialize(SerializeClosure* f) NOT_CDS_RETURN; + // Allocation static Handle create(TRAPS); @@ -728,6 +751,8 @@ static void compute_offsets(); public: + static void serialize(SerializeClosure* f) NOT_CDS_RETURN; + // Allocation static Handle create(TRAPS); @@ -758,6 +783,8 @@ 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 @@ static void compute_offsets(); public: + static void serialize(SerializeClosure* f) NOT_CDS_RETURN; + // Allocation static Handle create(TRAPS); @@ -809,6 +838,8 @@ static void compute_offsets(); public: + static void serialize(SerializeClosure* f) NOT_CDS_RETURN; + static int base_offset() { return _base_offset; } @@ -910,6 +941,7 @@ 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 @@ 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 @@ static void compute_offsets(); public: + static void serialize(SerializeClosure* f) NOT_CDS_RETURN; + // Accessors static oop member(oop mh); @@ -980,6 +1016,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ static void compute_offsets(); public: + static void serialize(SerializeClosure* f) NOT_CDS_RETURN; // Accessors static DependencyContext vmdependencies(oop context); @@ -1203,6 +1247,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ public: static int limit_offset(); static void compute_offsets(); + static void serialize(SerializeClosure* f) NOT_CDS_RETURN; }; class java_util_concurrent_locks_AbstractOwnableSynchronizer : AllStatic {
--- a/src/hotspot/share/classfile/stringTable.cpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/classfile/stringTable.cpp Fri Mar 02 17:25:55 2018 -0500 @@ -703,7 +703,6 @@ 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 @@ } } - G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity()); return true; }
--- a/src/hotspot/share/logging/logTag.hpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/logging/logTag.hpp Fri Mar 02 17:25:55 2018 -0500 @@ -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) \
--- a/src/hotspot/share/memory/filemap.hpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/memory/filemap.hpp Fri Mar 02 17:25:55 2018 -0500 @@ -125,14 +125,13 @@ 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?
--- a/src/hotspot/share/memory/iterator.hpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/memory/iterator.hpp Fri Mar 02 17:25:55 2018 -0500 @@ -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 @@ // correct length. virtual void do_tag(int tag) = 0; + // Read/write the oop + virtual void do_oop(oop* o) = 0; + bool writing() { return !reading(); }
--- a/src/hotspot/share/memory/metaspaceShared.cpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/memory/metaspaceShared.cpp Fri Mar 02 17:25:55 2018 -0500 @@ -375,9 +375,45 @@ 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 @@ 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 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 @@ _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 @@ 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 @@ } 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 @@ // 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 @@ 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 @@ 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 @@ _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 @@ 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 @@ // 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 @@ 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 @@ 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::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) { + return *p; + } else { + return NULL; + } +} + oop MetaspaceShared::archive_heap_object(oop obj, Thread* THREAD) { assert(DumpSharedSpaces, "dump-time only"); - ArchivedObjectCache* cache = MetaspaceShared::archive_object_cache(); - oop* p = cache->get(obj); - if (p != NULL) { + oop ao = find_archived_heap_object(obj); + if (ao != NULL) { // already archived - return *p; + return ao; } int len = obj->size(); @@ -1745,15 +1846,23 @@ 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 @@ 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");
--- a/src/hotspot/share/memory/metaspaceShared.hpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/memory/metaspaceShared.hpp Fri Mar 02 17:25:55 2018 -0500 @@ -113,8 +113,9 @@ 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 @@ } 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 @@ 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 @@ 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
--- a/src/hotspot/share/memory/universe.cpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/memory/universe.cpp Fri Mar 02 17:25:55 2018 -0500 @@ -247,7 +247,7 @@ _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 @@ } } +#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::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;
--- a/src/hotspot/share/memory/universe.hpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/memory/universe.hpp Fri Mar 02 17:25:55 2018 -0500 @@ -294,6 +294,16 @@ 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];
--- a/src/hotspot/share/oops/klass.cpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/oops/klass.cpp Fri Mar 02 17:25:55 2018 -0500 @@ -183,7 +183,8 @@ 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 @@ 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.
--- a/src/hotspot/share/oops/klass.hpp Fri Mar 02 10:42:32 2018 -0800 +++ b/src/hotspot/share/oops/klass.hpp Fri Mar 02 17:25:55 2018 -0500 @@ -156,6 +156,18 @@ // -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 @@ 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 @@ _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;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckCachedMirrorApp.java Fri Mar 02 17:25:55 2018 -0500 @@ -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"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckCachedMirrorTest.java Fri Mar 02 17:25:55 2018 -0500 @@ -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); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/MirrorWithReferenceFieldsApp.java Fri Mar 02 17:25:55 2018 -0500 @@ -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."); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/MirrorWithReferenceFieldsTest.java Fri Mar 02 17:25:55 2018 -0500 @@ -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"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/PrimitiveTypesApp.java Fri Mar 02 17:25:55 2018 -0500 @@ -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."); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/PrimitiveTypesTest.java Fri Mar 02 17:25:55 2018 -0500 @@ -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); + } +}
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/RedefineClassApp.java Fri Mar 02 10:42:32 2018 -0800 +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/RedefineClassApp.java Fri Mar 02 17:25:55 2018 -0500 @@ -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 @@ 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 @@ 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 @@ System.gc(); System.gc(); + // Check archived mirror object after redefine and GC + checkArchivedMirrorObject(klass); + System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++ (done)\n\n"); } }