< prev index next >

src/hotspot/share/memory/dynamicArchive.cpp

Print this page

*** 24,73 **** #include "precompiled.hpp" #include "jvm.h" #include "classfile/classLoaderData.inline.hpp" #include "classfile/symbolTable.hpp" - #include "classfile/systemDictionary.hpp" #include "classfile/systemDictionaryShared.hpp" #include "logging/log.hpp" #include "memory/archiveUtils.inline.hpp" #include "memory/dynamicArchive.hpp" - #include "memory/metadataFactory.hpp" - #include "memory/metaspace.hpp" #include "memory/metaspaceClosure.hpp" #include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" - #include "oops/compressedOops.hpp" - #include "oops/objArrayKlass.hpp" - #include "prims/jvmtiRedefineClasses.hpp" - #include "runtime/handles.inline.hpp" #include "runtime/os.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" #include "utilities/bitMap.inline.hpp" - #ifndef O_BINARY // if defined (Win32) use binary files. - #define O_BINARY 0 // otherwise do nothing. - #endif - - class DynamicArchiveBuilder : ResourceObj { - static unsigned my_hash(const address& a) { - return primitive_hash<address>(a); - } - static bool my_equals(const address& a0, const address& a1) { - return primitive_equals<address>(a0, a1); - } - typedef ResourceHashtable< - address, address, - DynamicArchiveBuilder::my_hash, // solaris compiler doesn't like: primitive_hash<address> - DynamicArchiveBuilder::my_equals, // solaris compiler doesn't like: primitive_equals<address> - 16384, ResourceObj::C_HEAP> RelocationTable; - RelocationTable _new_loc_table; static intx _buffer_to_target_delta; - DumpRegion* _current_dump_space; static size_t reserve_alignment() { return os::vm_allocation_granularity(); } --- 24,52 ---- #include "precompiled.hpp" #include "jvm.h" #include "classfile/classLoaderData.inline.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionaryShared.hpp" #include "logging/log.hpp" + #include "memory/archiveBuilder.hpp" #include "memory/archiveUtils.inline.hpp" #include "memory/dynamicArchive.hpp" #include "memory/metaspaceClosure.hpp" #include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" #include "runtime/os.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" + #include "utilities/align.hpp" #include "utilities/bitMap.inline.hpp" + class DynamicArchiveBuilder : public ArchiveBuilder { + public: static intx _buffer_to_target_delta; DumpRegion* _current_dump_space; static size_t reserve_alignment() { return os::vm_allocation_granularity(); }
*** 104,130 **** template <typename T> T to_target(T obj) const { assert(is_in_buffer_space(obj), "must be"); return (T)(address(obj) + _buffer_to_target_delta); } ! template <typename T> T get_new_loc(T obj) { ! address* pp = _new_loc_table.get((address)obj); ! if (pp == NULL) { ! // Excluded klasses are not copied ! return NULL; ! } else { ! return (T)*pp; ! } ! } ! ! address get_new_loc(MetaspaceClosure::Ref* ref) { ! return get_new_loc(ref->obj()); ! } ! ! template <typename T> bool has_new_loc(T obj) { ! address* pp = _new_loc_table.get((address)obj); ! return pp != NULL; } static int dynamic_dump_method_comparator(Method* a, Method* b) { Symbol* a_name = a->name(); Symbol* b_name = b->name(); --- 83,94 ---- template <typename T> T to_target(T obj) const { assert(is_in_buffer_space(obj), "must be"); return (T)(address(obj) + _buffer_to_target_delta); } ! template <typename T> T get_dumped_addr(T obj) { ! return (T)ArchiveBuilder::get_dumped_addr((address)obj); } static int dynamic_dump_method_comparator(Method* a, Method* b) { Symbol* a_name = a->name(); Symbol* b_name = b->name();
*** 145,493 **** } return a_name->fast_compare(b_name); } - protected: - enum FollowMode { - make_a_copy, point_to_it, set_to_null - }; - public: - void copy(MetaspaceClosure::Ref* ref, bool read_only) { - int bytes = ref->size() * BytesPerWord; - address old_obj = ref->obj(); - address new_obj = copy_impl(ref, read_only, bytes); - - assert(new_obj != NULL, "must be"); - assert(new_obj != old_obj, "must be"); - bool isnew = _new_loc_table.put(old_obj, new_obj); - assert(isnew, "must be"); - } - - // Make a shallow copy of each eligible MetaspaceObj into the buffer. - class ShallowCopier: public UniqueMetaspaceClosure { - DynamicArchiveBuilder* _builder; - bool _read_only; - public: - ShallowCopier(DynamicArchiveBuilder* shuffler, bool read_only) - : _builder(shuffler), _read_only(read_only) {} - - virtual bool do_unique_ref(Ref* orig_obj, bool read_only) { - // This method gets called on each *original* object - // reachable from _builder->iterate_roots(). Each orig_obj is - // called exactly once. - FollowMode mode = _builder->follow_ref(orig_obj); - - if (mode == point_to_it) { - if (read_only == _read_only) { - log_debug(cds, dynamic)("ptr : " PTR_FORMAT " %s", p2i(orig_obj->obj()), - MetaspaceObj::type_name(orig_obj->msotype())); - address p = orig_obj->obj(); - bool isnew = _builder->_new_loc_table.put(p, p); - assert(isnew, "must be"); - } - return false; - } - - if (mode == set_to_null) { - log_debug(cds, dynamic)("nul : " PTR_FORMAT " %s", p2i(orig_obj->obj()), - MetaspaceObj::type_name(orig_obj->msotype())); - return false; - } - - if (read_only == _read_only) { - // Make a shallow copy of orig_obj in a buffer (maintained - // by copy_impl in a subclass of DynamicArchiveBuilder). - _builder->copy(orig_obj, read_only); - } - return true; - } - }; - - // Relocate all embedded pointer fields within a MetaspaceObj's shallow copy - class ShallowCopyEmbeddedRefRelocator: public UniqueMetaspaceClosure { - DynamicArchiveBuilder* _builder; - public: - ShallowCopyEmbeddedRefRelocator(DynamicArchiveBuilder* shuffler) - : _builder(shuffler) {} - - // This method gets called on each *original* object reachable - // from _builder->iterate_roots(). Each orig_obj is - // called exactly once. - virtual bool do_unique_ref(Ref* orig_ref, bool read_only) { - FollowMode mode = _builder->follow_ref(orig_ref); - - if (mode == point_to_it) { - // We did not make a copy of this object - // and we have nothing to update - assert(_builder->get_new_loc(orig_ref) == NULL || - _builder->get_new_loc(orig_ref) == orig_ref->obj(), "must be"); - return false; - } - - if (mode == set_to_null) { - // We did not make a copy of this object - // and we have nothing to update - assert(!_builder->has_new_loc(orig_ref->obj()), "must not be copied or pointed to"); - return false; - } - - // - orig_obj points to the original object. - // - new_obj points to the shallow copy (created by ShallowCopier) - // of orig_obj. new_obj is NULL if the orig_obj is excluded - address orig_obj = orig_ref->obj(); - address new_obj = _builder->get_new_loc(orig_ref); - - assert(new_obj != orig_obj, "must be"); - #ifdef ASSERT - if (new_obj == NULL) { - if (orig_ref->msotype() == MetaspaceObj::ClassType) { - Klass* k = (Klass*)orig_obj; - assert(k->is_instance_klass() && - SystemDictionaryShared::is_excluded_class(InstanceKlass::cast(k)), - "orig_obj must be excluded Class"); - } - } - #endif - - log_debug(cds, dynamic)("Relocating " PTR_FORMAT " %s", p2i(new_obj), - MetaspaceObj::type_name(orig_ref->msotype())); - if (new_obj != NULL) { - EmbeddedRefUpdater updater(_builder, orig_obj, new_obj); - orig_ref->metaspace_pointers_do(&updater); - } - - return true; // keep recursing until every object is visited exactly once. - } - - virtual void push_special(SpecialRef type, Ref* ref, intptr_t* p) { - assert(type == _method_entry_ref, "only special type allowed for now"); - address obj = ref->obj(); - address new_obj = _builder->get_new_loc(ref); - size_t offset = pointer_delta(p, obj, sizeof(u1)); - intptr_t* new_p = (intptr_t*)(new_obj + offset); - assert(*p == *new_p, "must be a copy"); - ArchivePtrMarker::mark_pointer((address*)new_p); - } - }; - - class EmbeddedRefUpdater: public MetaspaceClosure { - DynamicArchiveBuilder* _builder; - address _orig_obj; - address _new_obj; - public: - EmbeddedRefUpdater(DynamicArchiveBuilder* shuffler, address orig_obj, address new_obj) : - _builder(shuffler), _orig_obj(orig_obj), _new_obj(new_obj) {} - - // This method gets called once for each pointer field F of orig_obj. - // We update new_obj->F to point to the new location of orig_obj->F. - // - // Example: Klass* 0x100 is copied to 0x400 - // Symbol* 0x200 is copied to 0x500 - // - // Let orig_obj == 0x100; and - // new_obj == 0x400; and - // ((Klass*)orig_obj)->_name == 0x200; - // Then this function effectively assigns - // ((Klass*)new_obj)->_name = 0x500; - virtual bool do_ref(Ref* ref, bool read_only) { - address new_pointee = NULL; - - if (ref->not_null()) { - address old_pointee = ref->obj(); - - FollowMode mode = _builder->follow_ref(ref); - if (mode == point_to_it) { - new_pointee = old_pointee; - } else if (mode == set_to_null) { - new_pointee = NULL; - } else { - new_pointee = _builder->get_new_loc(old_pointee); - } - } - - const char* kind = MetaspaceObj::type_name(ref->msotype()); - // offset of this field inside the original object - intx offset = (address)ref->addr() - _orig_obj; - _builder->update_pointer((address*)(_new_obj + offset), new_pointee, kind, offset); - - // We can't mark the pointer here, because DynamicArchiveBuilder::sort_methods - // may re-layout the [iv]tables, which would change the offset(s) in an InstanceKlass - // that would contain pointers. Therefore, we must mark the pointers after - // sort_methods(), using PointerMarker. - return false; // Do not recurse. - } - }; - - class ExternalRefUpdater: public MetaspaceClosure { - DynamicArchiveBuilder* _builder; - - public: - ExternalRefUpdater(DynamicArchiveBuilder* shuffler) : _builder(shuffler) {} - - virtual bool do_ref(Ref* ref, bool read_only) { - // ref is a pointer that lives OUTSIDE of the buffer, but points to an object inside the buffer - if (ref->not_null()) { - address new_loc = _builder->get_new_loc(ref); - const char* kind = MetaspaceObj::type_name(ref->msotype()); - _builder->update_pointer(ref->addr(), new_loc, kind, 0); - _builder->mark_pointer(ref->addr()); - } - return false; // Do not recurse. - } - }; - - class PointerMarker: public UniqueMetaspaceClosure { - DynamicArchiveBuilder* _builder; - - public: - PointerMarker(DynamicArchiveBuilder* shuffler) : _builder(shuffler) {} - - virtual bool do_unique_ref(Ref* ref, bool read_only) { - if (_builder->is_in_buffer_space(ref->obj())) { - EmbeddedRefMarker ref_marker(_builder); - ref->metaspace_pointers_do(&ref_marker); - return true; // keep recursing until every buffered object is visited exactly once. - } else { - return false; - } - } - }; - - class EmbeddedRefMarker: public MetaspaceClosure { - DynamicArchiveBuilder* _builder; - - public: - EmbeddedRefMarker(DynamicArchiveBuilder* shuffler) : _builder(shuffler) {} - virtual bool do_ref(Ref* ref, bool read_only) { - if (ref->not_null()) { - _builder->mark_pointer(ref->addr()); - } - return false; // Do not recurse. - } - }; - - void update_pointer(address* addr, address value, const char* kind, uintx offset, bool is_mso_pointer=true) { - // Propagate the the mask bits to the new value -- see comments above MetaspaceClosure::obj() - if (is_mso_pointer) { - const uintx FLAG_MASK = 0x03; - uintx mask_bits = uintx(*addr) & FLAG_MASK; - value = (address)(uintx(value) | mask_bits); - } - - if (*addr != value) { - log_debug(cds, dynamic)("Update (%18s*) %3d [" PTR_FORMAT "] " PTR_FORMAT " -> " PTR_FORMAT, - kind, int(offset), p2i(addr), p2i(*addr), p2i(value)); - *addr = value; - } - } - - private: - GrowableArray<Symbol*>* _symbols; // symbols to dump - GrowableArray<InstanceKlass*>* _klasses; // klasses to dump - - void append(InstanceKlass* k) { _klasses->append(k); } - void append(Symbol* s) { _symbols->append(s); } - - class GatherKlassesAndSymbols : public UniqueMetaspaceClosure { - DynamicArchiveBuilder* _builder; - bool _read_only; - - public: - GatherKlassesAndSymbols(DynamicArchiveBuilder* builder) - : _builder(builder) {} - - virtual bool do_unique_ref(Ref* ref, bool read_only) { - if (_builder->follow_ref(ref) != make_a_copy) { - return false; - } - if (ref->msotype() == MetaspaceObj::ClassType) { - Klass* klass = (Klass*)ref->obj(); - assert(klass->is_klass(), "must be"); - if (klass->is_instance_klass()) { - InstanceKlass* ik = InstanceKlass::cast(klass); - assert(!SystemDictionaryShared::is_excluded_class(ik), "must be"); - _builder->append(ik); - _builder->_estimated_metsapceobj_bytes += BytesPerWord; // See RunTimeSharedClassInfo::get_for() - } - } else if (ref->msotype() == MetaspaceObj::SymbolType) { - _builder->append((Symbol*)ref->obj()); - } - - int bytes = ref->size() * BytesPerWord; - _builder->_estimated_metsapceobj_bytes += bytes; - - return true; - } - }; - - FollowMode follow_ref(MetaspaceClosure::Ref *ref) { - address obj = ref->obj(); - if (MetaspaceShared::is_in_shared_metaspace(obj)) { - // Don't dump existing shared metadata again. - return point_to_it; - } else if (ref->msotype() == MetaspaceObj::MethodDataType) { - return set_to_null; - } else { - if (ref->msotype() == MetaspaceObj::ClassType) { - Klass* klass = (Klass*)ref->obj(); - assert(klass->is_klass(), "must be"); - if (klass->is_instance_klass()) { - InstanceKlass* ik = InstanceKlass::cast(klass); - if (SystemDictionaryShared::is_excluded_class(ik)) { - ResourceMark rm; - log_debug(cds, dynamic)("Skipping class (excluded): %s", klass->external_name()); - return set_to_null; - } - } else if (klass->is_array_klass()) { - // Don't support archiving of array klasses for now. - ResourceMark rm; - log_debug(cds, dynamic)("Skipping class (array): %s", klass->external_name()); - return set_to_null; - } - } - - return make_a_copy; - } - } - - address copy_impl(MetaspaceClosure::Ref* ref, bool read_only, int bytes) { - if (ref->msotype() == MetaspaceObj::ClassType) { - // Save a pointer immediate in front of an InstanceKlass, so - // we can do a quick lookup from InstanceKlass* -> RunTimeSharedClassInfo* - // without building another hashtable. See RunTimeSharedClassInfo::get_for() - // in systemDictionaryShared.cpp. - address obj = ref->obj(); - Klass* klass = (Klass*)obj; - if (klass->is_instance_klass()) { - SystemDictionaryShared::validate_before_archiving(InstanceKlass::cast(klass)); - current_dump_space()->allocate(sizeof(address), BytesPerWord); - } - } - address p = (address)current_dump_space()->allocate(bytes); - address obj = ref->obj(); - log_debug(cds, dynamic)("COPY: " PTR_FORMAT " ==> " PTR_FORMAT " %5d %s", - p2i(obj), p2i(p), bytes, - MetaspaceObj::type_name(ref->msotype())); - memcpy(p, obj, bytes); - intptr_t* archived_vtable = MetaspaceShared::get_archived_cpp_vtable(ref->msotype(), p); - if (archived_vtable != NULL) { - update_pointer((address*)p, (address)archived_vtable, "vtb", 0, /*is_mso_pointer*/false); - mark_pointer((address*)p); - } - - return (address)p; - } - DynamicArchiveHeader *_header; address _alloc_bottom; address _last_verified_top; size_t _other_region_used_bytes; // Conservative estimate for number of bytes needed for: - size_t _estimated_metsapceobj_bytes; // all archived MetsapceObj's. size_t _estimated_hashtable_bytes; // symbol table and dictionaries size_t _estimated_trampoline_bytes; // method entry trampolines size_t estimate_archive_size(); size_t estimate_trampoline_size(); --- 109,125 ----
*** 496,506 **** void init_header(address addr); void release_header(); void make_trampolines(); void make_klasses_shareable(); void sort_methods(InstanceKlass* ik) const; ! void set_symbols_permanent(); void relocate_buffer_to_target(); void write_archive(char* serialized_data); void init_first_dump_space(address reserved_bottom) { DumpRegion* mc_space = MetaspaceShared::misc_code_dump_space(); --- 128,138 ---- void init_header(address addr); void release_header(); void make_trampolines(); void make_klasses_shareable(); void sort_methods(InstanceKlass* ik) const; ! void remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const; void relocate_buffer_to_target(); void write_archive(char* serialized_data); void init_first_dump_space(address reserved_bottom) { DumpRegion* mc_space = MetaspaceShared::misc_code_dump_space();
*** 518,532 **** assert(n >= SharedRuntime::trampoline_size(), "dont want to be empty"); MetaspaceShared::misc_code_space_alloc(n); } public: ! DynamicArchiveBuilder() { ! _klasses = new (ResourceObj::C_HEAP, mtClass) GrowableArray<InstanceKlass*>(100, mtClass); ! _symbols = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Symbol*>(1000, mtClass); ! ! _estimated_metsapceobj_bytes = 0; _estimated_hashtable_bytes = 0; _estimated_trampoline_bytes = 0; _num_dump_regions_used = 0; } --- 150,160 ---- assert(n >= SharedRuntime::trampoline_size(), "dont want to be empty"); MetaspaceShared::misc_code_space_alloc(n); } public: ! DynamicArchiveBuilder() : ArchiveBuilder(NULL, NULL) { _estimated_hashtable_bytes = 0; _estimated_trampoline_bytes = 0; _num_dump_regions_used = 0; }
*** 570,648 **** void doit() { verify_universe("Before CDS dynamic dump"); DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); SystemDictionaryShared::check_excluded_classes(); ! { ! ResourceMark rm; ! GatherKlassesAndSymbols gatherer(this); ! ! SystemDictionaryShared::dumptime_classes_do(&gatherer); ! SymbolTable::metaspace_pointers_do(&gatherer); ! FileMapInfo::metaspace_pointers_do(&gatherer); ! ! gatherer.finish(); ! } // rw space starts ... address reserved_bottom = reserve_space_and_init_buffer_to_target_delta(); init_header(reserved_bottom); CHeapBitMap ptrmap; ArchivePtrMarker::initialize(&ptrmap, (address*)reserved_bottom, (address*)current_dump_space()->top()); reserve_buffers_for_trampolines(); verify_estimate_size(_estimated_trampoline_bytes, "Trampolines"); start_dump_space(MetaspaceShared::read_write_dump_space()); log_info(cds, dynamic)("Copying %d klasses and %d symbols", ! _klasses->length(), _symbols->length()); ! { ! assert(current_dump_space() == MetaspaceShared::read_write_dump_space(), ! "Current dump space is not rw space"); ! // shallow-copy RW objects, if necessary ! ResourceMark rm; ! ShallowCopier rw_copier(this, false); ! iterate_roots(&rw_copier); ! } // ro space starts ... DumpRegion* ro_space = MetaspaceShared::read_only_dump_space(); - { start_dump_space(ro_space); ! ! // shallow-copy RO objects, if necessary ! ResourceMark rm; ! ShallowCopier ro_copier(this, true); ! iterate_roots(&ro_copier); ! } ! ! { ! log_info(cds)("Relocating embedded pointers ... "); ! ResourceMark rm; ! ShallowCopyEmbeddedRefRelocator emb_reloc(this); ! iterate_roots(&emb_reloc); ! } ! ! { ! log_info(cds)("Relocating external roots ... "); ! ResourceMark rm; ! ExternalRefUpdater ext_reloc(this); ! iterate_roots(&ext_reloc); ! } verify_estimate_size(_estimated_metsapceobj_bytes, "MetaspaceObjs"); char* serialized_data; { - set_symbols_permanent(); - // Write the symbol table and system dictionaries to the RO space. ! // Note that these tables still point to the *original* objects ! // (because they were not processed by ExternalRefUpdater), so // they would need to call DynamicArchive::original_to_target() to // get the correct addresses. assert(current_dump_space() == ro_space, "Must be RO space"); SymbolTable::write_to_archive(false); SystemDictionaryShared::write_to_archive(false); --- 198,240 ---- void doit() { verify_universe("Before CDS dynamic dump"); DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); SystemDictionaryShared::check_excluded_classes(); ! gather_klasses_and_symbols(); // rw space starts ... address reserved_bottom = reserve_space_and_init_buffer_to_target_delta(); + set_dump_regions(MetaspaceShared::read_write_dump_space(), MetaspaceShared::read_only_dump_space()); init_header(reserved_bottom); CHeapBitMap ptrmap; ArchivePtrMarker::initialize(&ptrmap, (address*)reserved_bottom, (address*)current_dump_space()->top()); reserve_buffers_for_trampolines(); verify_estimate_size(_estimated_trampoline_bytes, "Trampolines"); + gather_source_objs(); start_dump_space(MetaspaceShared::read_write_dump_space()); log_info(cds, dynamic)("Copying %d klasses and %d symbols", ! klasses()->length(), symbols()->length()); ! dump_rw_region(); // ro space starts ... DumpRegion* ro_space = MetaspaceShared::read_only_dump_space(); start_dump_space(ro_space); ! dump_ro_region(); ! relocate_pointers(); verify_estimate_size(_estimated_metsapceobj_bytes, "MetaspaceObjs"); char* serialized_data; { // Write the symbol table and system dictionaries to the RO space. ! // Note that these tables still point to the *original* objects, so // they would need to call DynamicArchive::original_to_target() to // get the correct addresses. assert(current_dump_space() == ro_space, "Must be RO space"); SymbolTable::write_to_archive(false); SystemDictionaryShared::write_to_archive(false);
*** 654,713 **** } verify_estimate_size(_estimated_hashtable_bytes, "Hashtables"); make_trampolines(); make_klasses_shareable(); - { log_info(cds)("Adjust lambda proxy class dictionary"); SystemDictionaryShared::adjust_lambda_proxy_class_dictionary(); - } - { log_info(cds)("Final relocation of pointers ... "); - ResourceMark rm; - PointerMarker marker(this); - iterate_roots(&marker); relocate_buffer_to_target(); - } write_archive(serialized_data); release_header(); assert(_num_dump_regions_used == _total_dump_regions, "must be"); verify_universe("After CDS dynamic dump"); } ! void iterate_roots(MetaspaceClosure* it) { ! int i; ! int num_klasses = _klasses->length(); ! for (i = 0; i < num_klasses; i++) { ! it->push(&_klasses->at(i)); } - - int num_symbols = _symbols->length(); - for (i = 0; i < num_symbols; i++) { - it->push(&_symbols->at(i)); - } - FileMapInfo::metaspace_pointers_do(it); - - // Do not call these again, as we have already collected all the classes and symbols - // that we want to archive. Also, these calls would corrupt the tables when - // ExternalRefUpdater is used. - // - // SystemDictionaryShared::dumptime_classes_do(it); - // SymbolTable::metaspace_pointers_do(it); - - it->finish(); } }; intx DynamicArchiveBuilder::_buffer_to_target_delta; - size_t DynamicArchiveBuilder::estimate_archive_size() { // size of the symbol table and two dictionaries, plus the RunTimeSharedClassInfo's _estimated_hashtable_bytes = 0; _estimated_hashtable_bytes += SymbolTable::estimate_size_for_archive(); _estimated_hashtable_bytes += SystemDictionaryShared::estimate_size_for_archive(); --- 246,283 ---- } verify_estimate_size(_estimated_hashtable_bytes, "Hashtables"); make_trampolines(); + + log_info(cds)("Make classes shareable"); make_klasses_shareable(); log_info(cds)("Adjust lambda proxy class dictionary"); SystemDictionaryShared::adjust_lambda_proxy_class_dictionary(); log_info(cds)("Final relocation of pointers ... "); relocate_buffer_to_target(); write_archive(serialized_data); release_header(); assert(_num_dump_regions_used == _total_dump_regions, "must be"); verify_universe("After CDS dynamic dump"); } ! virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) { ! if (!is_relocating_pointers) { ! SystemDictionaryShared::dumptime_classes_do(it); ! SymbolTable::metaspace_pointers_do(it); } FileMapInfo::metaspace_pointers_do(it); } }; intx DynamicArchiveBuilder::_buffer_to_target_delta; size_t DynamicArchiveBuilder::estimate_archive_size() { // size of the symbol table and two dictionaries, plus the RunTimeSharedClassInfo's _estimated_hashtable_bytes = 0; _estimated_hashtable_bytes += SymbolTable::estimate_size_for_archive(); _estimated_hashtable_bytes += SystemDictionaryShared::estimate_size_for_archive();
*** 793,819 **** size_t total = 0; size_t each_method_bytes = align_up(SharedRuntime::trampoline_size(), BytesPerWord) + align_up(sizeof(AdapterHandlerEntry*), BytesPerWord); ! for (int i = 0; i < _klasses->length(); i++) { ! InstanceKlass* ik = _klasses->at(i); ! Array<Method*>* methods = ik->methods(); total += each_method_bytes * methods->length(); } if (total == 0) { // We have nothing to archive, but let's avoid having an empty region. total = SharedRuntime::trampoline_size(); } return total; } void DynamicArchiveBuilder::make_trampolines() { DumpRegion* mc_space = MetaspaceShared::misc_code_dump_space(); char* p = mc_space->base(); ! for (int i = 0; i < _klasses->length(); i++) { ! InstanceKlass* ik = _klasses->at(i); Array<Method*>* methods = ik->methods(); for (int j = 0; j < methods->length(); j++) { Method* m = methods->at(j); address c2i_entry_trampoline = (address)p; p += SharedRuntime::trampoline_size(); --- 363,395 ---- size_t total = 0; size_t each_method_bytes = align_up(SharedRuntime::trampoline_size(), BytesPerWord) + align_up(sizeof(AdapterHandlerEntry*), BytesPerWord); ! for (int i = 0; i < klasses()->length(); i++) { ! Klass* k = klasses()->at(i); ! if (k->is_instance_klass()) { ! Array<Method*>* methods = InstanceKlass::cast(k)->methods(); total += each_method_bytes * methods->length(); } + } if (total == 0) { // We have nothing to archive, but let's avoid having an empty region. total = SharedRuntime::trampoline_size(); } return total; } void DynamicArchiveBuilder::make_trampolines() { DumpRegion* mc_space = MetaspaceShared::misc_code_dump_space(); char* p = mc_space->base(); ! for (int i = 0; i < klasses()->length(); i++) { ! Klass* k = klasses()->at(i); ! if (!k->is_instance_klass()) { ! continue; ! } ! InstanceKlass* ik = InstanceKlass::cast(k); Array<Method*>* methods = ik->methods(); for (int j = 0; j < methods->length(); j++) { Method* m = methods->at(j); address c2i_entry_trampoline = (address)p; p += SharedRuntime::trampoline_size();
*** 830,849 **** guarantee(p <= mc_space->top(), "Estimate of trampoline size is insufficient"); } void DynamicArchiveBuilder::make_klasses_shareable() { ! int i, count = _klasses->length(); InstanceKlass::disable_method_binary_search(); for (i = 0; i < count; i++) { ! InstanceKlass* ik = _klasses->at(i); ! sort_methods(ik); } for (i = 0; i < count; i++) { ! InstanceKlass* ik = _klasses->at(i); ik->assign_class_loader_type(); MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik); ik->remove_unshareable_info(); --- 406,431 ---- guarantee(p <= mc_space->top(), "Estimate of trampoline size is insufficient"); } void DynamicArchiveBuilder::make_klasses_shareable() { ! int i, count = klasses()->length(); InstanceKlass::disable_method_binary_search(); for (i = 0; i < count; i++) { ! Klass* k = klasses()->at(i); ! if (k->is_instance_klass()) { ! sort_methods(InstanceKlass::cast(k)); ! } } for (i = 0; i < count; i++) { ! Klass* k = klasses()->at(i); ! if (!k->is_instance_klass()) { ! continue; ! } ! InstanceKlass* ik = InstanceKlass::cast(k); ik->assign_class_loader_type(); MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik); ik->remove_unshareable_info();
*** 874,883 **** --- 456,470 ---- if (log_is_enabled(Debug, cds, dynamic)) { ResourceMark rm; log_debug(cds, dynamic)("sorting methods for " PTR_FORMAT " %s", p2i(to_target(ik)), ik->external_name()); } + // Method sorting may re-layout the [iv]tables, which would change the offset(s) + // of the locations in an InstanceKlass that would contain pointers. Let's clear + // all the existing pointer marking bits, and re-mark the pointers after sorting. + remark_pointers_for_instance_klass(ik, false); + // Make sure all supertypes have been sorted sort_methods(ik->java_super()); Array<InstanceKlass*>* interfaces = ik->local_interfaces(); int len = interfaces->length(); for (int i = 0; i < len; i++) {
*** 904,925 **** if (ik->default_methods() != NULL) { Method::sort_methods(ik->default_methods(), /*set_idnums=*/false, dynamic_dump_method_comparator); } ik->vtable().initialize_vtable(true, THREAD); assert(!HAS_PENDING_EXCEPTION, "cannot fail"); ik->itable().initialize_itable(true, THREAD); assert(!HAS_PENDING_EXCEPTION, "cannot fail"); - } ! void DynamicArchiveBuilder::set_symbols_permanent() { ! int count = _symbols->length(); ! for (int i=0; i<count; i++) { ! Symbol* s = _symbols->at(i); ! s->set_permanent(); ! if (log_is_enabled(Trace, cds, dynamic)) { ! ResourceMark rm; ! log_trace(cds, dynamic)("symbols[%4i] = " PTR_FORMAT " %s", i, p2i(to_target(s)), s->as_quoted_ascii()); } } } class RelocateBufferToTarget: public BitMapClosure { DynamicArchiveBuilder *_builder; --- 491,527 ---- if (ik->default_methods() != NULL) { Method::sort_methods(ik->default_methods(), /*set_idnums=*/false, dynamic_dump_method_comparator); } ik->vtable().initialize_vtable(true, THREAD); assert(!HAS_PENDING_EXCEPTION, "cannot fail"); ik->itable().initialize_itable(true, THREAD); assert(!HAS_PENDING_EXCEPTION, "cannot fail"); ! // Set all the pointer marking bits after sorting. ! remark_pointers_for_instance_klass(ik, true); ! } ! template<bool should_mark> ! class PointerRemarker: public MetaspaceClosure { ! public: ! virtual bool do_ref(Ref* ref, bool read_only) { ! if (should_mark) { ! ArchivePtrMarker::mark_pointer(ref->addr()); ! } else { ! ArchivePtrMarker::clear_pointer(ref->addr()); } + return false; // don't recurse + } + }; + + void DynamicArchiveBuilder::remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const { + if (should_mark) { + PointerRemarker<true> marker; + k->metaspace_pointers_do(&marker); + marker.finish(); + } else { + PointerRemarker<false> marker; + k->metaspace_pointers_do(&marker); + marker.finish(); } } class RelocateBufferToTarget: public BitMapClosure { DynamicArchiveBuilder *_builder;
*** 1001,1012 **** ArchivePtrMarker::compact(patcher.max_non_null_offset()); } } void DynamicArchiveBuilder::write_archive(char* serialized_data) { ! int num_klasses = _klasses->length(); ! int num_symbols = _symbols->length(); _header->set_serialized_data(to_target(serialized_data)); FileMapInfo* dynamic_info = FileMapInfo::dynamic_info(); assert(dynamic_info != NULL, "Sanity"); --- 603,614 ---- ArchivePtrMarker::compact(patcher.max_non_null_offset()); } } void DynamicArchiveBuilder::write_archive(char* serialized_data) { ! int num_klasses = klasses()->length(); ! int num_symbols = symbols()->length(); _header->set_serialized_data(to_target(serialized_data)); FileMapInfo* dynamic_info = FileMapInfo::dynamic_info(); assert(dynamic_info != NULL, "Sanity");
*** 1030,1040 **** " [" SIZE_FORMAT " bytes header, " SIZE_FORMAT " bytes total]", p2i(base), p2i(top), _header->header_size(), file_size); log_info(cds, dynamic)("%d klasses; %d symbols", num_klasses, num_symbols); } - class VM_PopulateDynamicDumpSharedSpace: public VM_Operation { DynamicArchiveBuilder* _builder; public: VM_PopulateDynamicDumpSharedSpace(DynamicArchiveBuilder* builder) : _builder(builder) {} VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; } --- 632,641 ----
*** 1068,1078 **** _builder = NULL; } address DynamicArchive::original_to_buffer_impl(address orig_obj) { assert(DynamicDumpSharedSpaces, "must be"); ! address buff_obj = _builder->get_new_loc(orig_obj); assert(buff_obj != NULL, "orig_obj must be used by the dynamic archive"); assert(buff_obj != orig_obj, "call this only when you know orig_obj must be copied and not just referenced"); assert(_builder->is_in_buffer_space(buff_obj), "must be"); return buff_obj; } --- 669,679 ---- _builder = NULL; } address DynamicArchive::original_to_buffer_impl(address orig_obj) { assert(DynamicDumpSharedSpaces, "must be"); ! address buff_obj = _builder->get_dumped_addr(orig_obj); assert(buff_obj != NULL, "orig_obj must be used by the dynamic archive"); assert(buff_obj != orig_obj, "call this only when you know orig_obj must be copied and not just referenced"); assert(_builder->is_in_buffer_space(buff_obj), "must be"); return buff_obj; }
*** 1087,1097 **** assert(DynamicDumpSharedSpaces, "must be"); if (MetaspaceShared::is_in_shared_metaspace(orig_obj)) { // This happens when the top archive points to a Symbol* in the base archive. return orig_obj; } ! address buff_obj = _builder->get_new_loc(orig_obj); assert(buff_obj != NULL, "orig_obj must be used by the dynamic archive"); if (buff_obj == orig_obj) { // We are storing a pointer to an original object into the dynamic buffer. E.g., // a Symbol* that used by both the base and top archives. assert(MetaspaceShared::is_in_shared_metaspace(orig_obj), "must be"); --- 688,698 ---- assert(DynamicDumpSharedSpaces, "must be"); if (MetaspaceShared::is_in_shared_metaspace(orig_obj)) { // This happens when the top archive points to a Symbol* in the base archive. return orig_obj; } ! address buff_obj = _builder->get_dumped_addr(orig_obj); assert(buff_obj != NULL, "orig_obj must be used by the dynamic archive"); if (buff_obj == orig_obj) { // We are storing a pointer to an original object into the dynamic buffer. E.g., // a Symbol* that used by both the base and top archives. assert(MetaspaceShared::is_in_shared_metaspace(orig_obj), "must be");
< prev index next >