--- old/src/hotspot/share/classfile/compactHashtable.hpp 2018-09-20 11:16:34.500945765 -0700 +++ new/src/hotspot/share/classfile/compactHashtable.hpp 2018-09-20 11:16:34.232935526 -0700 @@ -123,6 +123,15 @@ public: void dump(SimpleCompactHashtable *cht, const char* table_name); + + static int default_num_buckets(size_t num_entries) { + return default_num_buckets((int)num_entries); + } + static int default_num_buckets(int num_entries) { + int num_buckets = num_entries / SharedSymbolTableBucketSize; + // calculation of num_buckets can result in zero buckets, we need at least one + return (num_buckets < 1) ? 1 : num_buckets; + } }; #endif // INCLUDE_CDS --- old/src/hotspot/share/classfile/stringTable.cpp 2018-09-20 11:16:35.212972965 -0700 +++ new/src/hotspot/share/classfile/stringTable.cpp 2018-09-20 11:16:34.896960893 -0700 @@ -819,18 +819,9 @@ return new_s; } -class CompactStringTableWriter: public CompactHashtableWriter { -public: - CompactStringTableWriter(int num_entries, CompactHashtableStats* stats) : - CompactHashtableWriter(num_entries, stats) {} - void add(unsigned int hash, oop string) { - CompactHashtableWriter::add(hash, CompressedOops::encode(string)); - } -}; - struct CopyToArchive : StackObj { - CompactStringTableWriter* _writer; - CopyToArchive(CompactStringTableWriter* writer) : _writer(writer) {} + CompactHashtableWriter* _writer; + CopyToArchive(CompactHashtableWriter* writer) : _writer(writer) {} bool operator()(WeakHandle* val) { oop s = val->peek(); if (s == NULL) { @@ -838,6 +829,7 @@ } unsigned int hash = java_lang_String::hash_code(s); if (hash == 0) { + // We do not archive Strings with a 0 hashcode because ...... return true; } @@ -849,12 +841,12 @@ val->replace(new_s); // add to the compact table - _writer->add(hash, new_s); + _writer->add(hash, CompressedOops::encode(new_s)); return true; } }; -void StringTable::copy_shared_string_table(CompactStringTableWriter* writer) { +void StringTable::copy_shared_string_table(CompactHashtableWriter* writer) { assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be"); CopyToArchive copy(writer); @@ -865,10 +857,10 @@ assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be"); _shared_table.reset(); - int num_buckets = the_table()->_items_count / SharedSymbolTableBucketSize; - // calculation of num_buckets can result in zero buckets, we need at least one - CompactStringTableWriter writer(num_buckets > 1 ? num_buckets : 1, - &MetaspaceShared::stats()->string); + int num_buckets = CompactHashtableWriter::default_num_buckets( + StringTable::the_table()->_items_count); + CompactHashtableWriter writer(num_buckets, + &MetaspaceShared::stats()->string); // Copy the interned strings into the "string space" within the java heap copy_shared_string_table(&writer); --- old/src/hotspot/share/classfile/stringTable.hpp 2018-09-20 11:16:35.872998179 -0700 +++ new/src/hotspot/share/classfile/stringTable.hpp 2018-09-20 11:16:35.608988094 -0700 @@ -33,7 +33,7 @@ #include "oops/weakHandle.hpp" #include "utilities/concurrentHashTable.hpp" -class CompactStringTableWriter; +class CompactHashtableWriter; class SerializeClosure; class StringTable; @@ -163,7 +163,7 @@ // Sharing private: oop lookup_shared(const jchar* name, int len, unsigned int hash) NOT_CDS_JAVA_HEAP_RETURN_(NULL); - static void copy_shared_string_table(CompactStringTableWriter* ch_table) NOT_CDS_JAVA_HEAP_RETURN; + static void copy_shared_string_table(CompactHashtableWriter* ch_table) NOT_CDS_JAVA_HEAP_RETURN; public: static oop create_archived_string(oop s, Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN_(NULL); static void set_shared_string_mapped() { _shared_string_mapped = true; } --- old/src/hotspot/share/classfile/symbolTable.cpp 2018-09-20 11:16:36.545023851 -0700 +++ new/src/hotspot/share/classfile/symbolTable.cpp 2018-09-20 11:16:36.285013918 -0700 @@ -627,43 +627,31 @@ } #if INCLUDE_CDS -class CompactSymbolTableWriter: public CompactHashtableWriter { -public: - CompactSymbolTableWriter(int num_buckets, CompactHashtableStats* stats) : - CompactHashtableWriter(num_buckets, stats) {} - void add(unsigned int hash, Symbol *symbol) { - uintx deltax = MetaspaceShared::object_delta(symbol); - // When the symbols are stored into the archive, we already check that - // they won't be more than MAX_SHARED_DELTA from the base address, or - // else the dumping would have been aborted. - assert(deltax <= MAX_SHARED_DELTA, "must not be"); - u4 delta = u4(deltax); - - CompactHashtableWriter::add(hash, delta); - } -}; - struct CopyToArchive : StackObj { - CompactSymbolTableWriter* _writer; - CopyToArchive(CompactSymbolTableWriter* writer) : _writer(writer) {} + CompactHashtableWriter* _writer; + CopyToArchive(CompactHashtableWriter* writer) : _writer(writer) {} bool operator()(Symbol** value) { assert(value != NULL, "expected valid value"); assert(*value != NULL, "value should point to a symbol"); Symbol* sym = *value; - unsigned int fixed_hash = hash_shared_symbol((const char*)sym->bytes(), sym->utf8_length()); - if (fixed_hash == 0) { - return true; - } + unsigned int fixed_hash = hash_shared_symbol((const char*)sym->bytes(), sym->utf8_length()); assert(fixed_hash == hash_symbol((const char*)sym->bytes(), sym->utf8_length(), false), "must not rehash during dumping"); + uintx deltax = MetaspaceShared::object_delta(sym); + // When the symbols are stored into the archive, we already check that + // they won't be more than MAX_SHARED_DELTA from the base address, or + // else the dumping would have been aborted. + assert(deltax <= MAX_SHARED_DELTA, "must not be"); + u4 delta = u4(deltax); + // add to the compact table - _writer->add(fixed_hash, sym); + _writer->add(fixed_hash, delta); return true; } }; -void SymbolTable::copy_shared_symbol_table(CompactSymbolTableWriter* writer) { +void SymbolTable::copy_shared_symbol_table(CompactHashtableWriter* writer) { CopyToArchive copy(writer); SymbolTable::the_table()->_local_table->do_scan(Thread::current(), copy); } @@ -671,10 +659,10 @@ void SymbolTable::write_to_archive() { _shared_table.reset(); - int num_buckets = (int)(SymbolTable::the_table()->_items_count / SharedSymbolTableBucketSize); - // calculation of num_buckets can result in zero buckets, we need at least one - CompactSymbolTableWriter writer(num_buckets > 1 ? num_buckets : 1, - &MetaspaceShared::stats()->symbol); + int num_buckets = CompactHashtableWriter::default_num_buckets( + SymbolTable::the_table()->_items_count); + CompactHashtableWriter writer(num_buckets, + &MetaspaceShared::stats()->symbol); copy_shared_symbol_table(&writer); writer.dump(&_shared_table, "symbol"); --- old/src/hotspot/share/classfile/symbolTable.hpp 2018-09-20 11:16:37.225049829 -0700 +++ new/src/hotspot/share/classfile/symbolTable.hpp 2018-09-20 11:16:36.957039591 -0700 @@ -84,7 +84,7 @@ operator Symbol*() { return _temp; } }; -class CompactSymbolTableWriter; +class CompactHashtableWriter; class SerializeClosure; class SymbolTableConfig; @@ -240,7 +240,7 @@ // Sharing private: - static void copy_shared_symbol_table(CompactSymbolTableWriter* ch_table); + static void copy_shared_symbol_table(CompactHashtableWriter* ch_table); public: static void write_to_archive() NOT_CDS_RETURN; static void serialize(SerializeClosure* soc) NOT_CDS_RETURN; --- old/src/hotspot/share/memory/heapShared.cpp 2018-09-20 11:16:37.881074890 -0700 +++ new/src/hotspot/share/memory/heapShared.cpp 2018-09-20 11:16:37.621064957 -0700 @@ -41,49 +41,25 @@ #include "utilities/bitMap.inline.hpp" #if INCLUDE_CDS_JAVA_HEAP -KlassSubGraphInfo* HeapShared::_subgraph_info_list = NULL; -int HeapShared::_num_archived_subgraph_info_records = 0; -Array* HeapShared::_archived_subgraph_info_records = NULL; - -KlassSubGraphInfo* HeapShared::find_subgraph_info(Klass* k) { - KlassSubGraphInfo* info = _subgraph_info_list; - while (info != NULL) { - if (info->klass() == k) { - return info; - } - info = info->next(); - } - return NULL; -} +address HeapShared::_narrow_oop_base; +int HeapShared::_narrow_oop_shift; +HeapShared::DumpTimeKlassSubGraphInfoTable* HeapShared::_dump_time_subgraph_info_table = NULL; +HeapShared::RunTimeKlassSubGraphInfoTable HeapShared::_run_time_subgraph_info_table; // Get the subgraph_info for Klass k. A new subgraph_info is created if // there is no existing one for k. The subgraph_info records the relocated // Klass* of the original k. KlassSubGraphInfo* HeapShared::get_subgraph_info(Klass* k) { Klass* relocated_k = MetaspaceShared::get_relocated_klass(k); - KlassSubGraphInfo* info = find_subgraph_info(relocated_k); - if (info != NULL) { - return info; + KlassSubGraphInfo* info = _dump_time_subgraph_info_table->get(relocated_k); + if (info == NULL) { + _dump_time_subgraph_info_table->put(relocated_k, KlassSubGraphInfo(relocated_k)); + info = _dump_time_subgraph_info_table->get(relocated_k); + ++ _dump_time_subgraph_info_table->_count; } - - info = new KlassSubGraphInfo(relocated_k, _subgraph_info_list); - _subgraph_info_list = info; return info; } -address HeapShared::_narrow_oop_base; -int HeapShared::_narrow_oop_shift; - -int HeapShared::num_of_subgraph_infos() { - int num = 0; - KlassSubGraphInfo* info = _subgraph_info_list; - while (info != NULL) { - num ++; - info = info->next(); - } - return num; -} - // Add an entry field to the current KlassSubGraphInfo. void KlassSubGraphInfo::add_subgraph_entry_field(int static_field_offset, oop v) { assert(DumpSharedSpaces, "dump time only"); @@ -156,7 +132,6 @@ // Initialize an archived subgraph_info_record from the given KlassSubGraphInfo. void ArchivedKlassSubGraphInfoRecord::init(KlassSubGraphInfo* info) { _k = info->klass(); - _next = NULL; _entry_field_records = NULL; _subgraph_object_klasses = NULL; @@ -191,6 +166,27 @@ } } +struct CopyKlassSubGraphInfoToArchive : StackObj { + CompactHashtableWriter* _writer; + CopyKlassSubGraphInfoToArchive(CompactHashtableWriter* writer) : _writer(writer) {} + + bool do_entry(Klass* klass, KlassSubGraphInfo& info) { + + if (info.subgraph_object_klasses() != NULL || info.subgraph_entry_fields() != NULL) { + ArchivedKlassSubGraphInfoRecord* record = + (ArchivedKlassSubGraphInfoRecord*)MetaspaceShared::read_only_space_alloc(sizeof(ArchivedKlassSubGraphInfoRecord)); + record->init(&info); + + unsigned int hash = primitive_hash(klass); + uintx deltax = MetaspaceShared::object_delta(record); + guarantee(deltax <= MAX_SHARED_DELTA, "must not be"); + u4 delta = u4(deltax); + _writer->add(hash, delta); + } + return true; // keep on iterating + } +}; + // Build the records of archived subgraph infos, which include: // - Entry points to all subgraphs from the containing class mirror. The entry // points are static fields in the mirror. For each entry point, the field @@ -198,74 +194,24 @@ // back to the corresponding field at runtime. // - A list of klasses that need to be loaded/initialized before archived // java object sub-graph can be accessed at runtime. -// -// The records are saved in the archive file and reloaded at runtime. -// -// Layout of the archived subgraph info records: -// -// records_size | num_records | records* -// ArchivedKlassSubGraphInfoRecord | entry_fields | subgraph_object_klasses -size_t HeapShared::build_archived_subgraph_info_records(int num_records) { - // remember the start address - char* start_p = MetaspaceShared::read_only_space_top(); - - // now populate the archived subgraph infos, which will be saved in the - // archive file - _archived_subgraph_info_records = - MetaspaceShared::new_ro_array(num_records); - KlassSubGraphInfo* info = _subgraph_info_list; - int i = 0; - while (info != NULL) { - assert(i < _archived_subgraph_info_records->length(), "sanity"); - ArchivedKlassSubGraphInfoRecord* record = - _archived_subgraph_info_records->adr_at(i); - record->init(info); - info = info->next(); - i ++; - } - - // _subgraph_info_list is no longer needed - delete _subgraph_info_list; - _subgraph_info_list = NULL; - - char* end_p = MetaspaceShared::read_only_space_top(); - size_t records_size = end_p - start_p; - return records_size; -} +void HeapShared::create_hashtables() { + // Allocate the contents of the hashtable(s) inside the RO region of the CDS archive. + DumpTimeKlassSubGraphInfoTable* d_table = _dump_time_subgraph_info_table; + CompactHashtableStats stats; -// Write the subgraph info records in the shared _ro region -void HeapShared::write_archived_subgraph_infos() { - assert(DumpSharedSpaces, "dump time only"); + _run_time_subgraph_info_table.reset(); - Array* records_header = MetaspaceShared::new_ro_array(3); + int num_buckets = CompactHashtableWriter::default_num_buckets(d_table->_count); + CompactHashtableWriter writer(num_buckets, &stats); + CopyKlassSubGraphInfoToArchive copy(&writer); + _dump_time_subgraph_info_table->iterate(©); - _num_archived_subgraph_info_records = num_of_subgraph_infos(); - size_t records_size = build_archived_subgraph_info_records( - _num_archived_subgraph_info_records); - - // Now write the header information: - // records_size, num_records, _archived_subgraph_info_records - assert(records_header != NULL, "sanity"); - intptr_t* p = (intptr_t*)(records_header->data()); - *p = (intptr_t)records_size; - p ++; - *p = (intptr_t)_num_archived_subgraph_info_records; - p ++; - *p = (intptr_t)_archived_subgraph_info_records; -} - -char* HeapShared::read_archived_subgraph_infos(char* buffer) { - Array* records_header = (Array*)buffer; - intptr_t* p = (intptr_t*)(records_header->data()); - size_t records_size = (size_t)(*p); - p ++; - _num_archived_subgraph_info_records = *p; - p ++; - _archived_subgraph_info_records = - (Array*)(*p); + writer.dump(&_run_time_subgraph_info_table, "subgraphs"); +} - buffer = (char*)_archived_subgraph_info_records + records_size; - return buffer; +// Read/write the headers of the hashtable(s) so they can be accessed quickly at runtime. +void HeapShared::serialize_hashtables(SerializeClosure* soc) { + _run_time_subgraph_info_table.serialize(soc); } void HeapShared::initialize_from_archived_subgraph(Klass* k) { @@ -273,69 +219,71 @@ return; // nothing to do } - if (_num_archived_subgraph_info_records == 0) { - return; // no subgraph info records - } + unsigned int hash = primitive_hash(k); + ArchivedKlassSubGraphInfoRecord* record = _run_time_subgraph_info_table.lookup(k, hash, 0); // Initialize from archived data. Currently this is done only // during VM initialization time. No lock is needed. - Thread* THREAD = Thread::current(); - for (int i = 0; i < _archived_subgraph_info_records->length(); i++) { - ArchivedKlassSubGraphInfoRecord* record = _archived_subgraph_info_records->adr_at(i); - if (record->klass() == k) { - int i; - // Found the archived subgraph info record for the requesting klass. - // Load/link/initialize the klasses of the objects in the subgraph. - // NULL class loader is used. - Array* klasses = record->subgraph_object_klasses(); - if (klasses != NULL) { - for (i = 0; i < klasses->length(); i++) { - Klass* obj_k = klasses->at(i); - Klass* resolved_k = SystemDictionary::resolve_or_null( - (obj_k)->name(), THREAD); - if (resolved_k != obj_k) { - return; - } - if ((obj_k)->is_instance_klass()) { - InstanceKlass* ik = InstanceKlass::cast(obj_k); - ik->initialize(THREAD); - } else if ((obj_k)->is_objArray_klass()) { - ObjArrayKlass* oak = ObjArrayKlass::cast(obj_k); - oak->initialize(THREAD); - } + if (record != NULL) { + Thread* THREAD = Thread::current(); + if (log_is_enabled(Info, cds, heap)) { + ResourceMark rm; + log_info(cds, heap)("initialize_from_archived_subgraph %p %s", k, + k->external_name()); + } + + int i; + // Load/link/initialize the klasses of the objects in the subgraph. + // NULL class loader is used. + Array* klasses = record->subgraph_object_klasses(); + if (klasses != NULL) { + for (i = 0; i < klasses->length(); i++) { + Klass* obj_k = klasses->at(i); + Klass* resolved_k = SystemDictionary::resolve_or_null( + (obj_k)->name(), THREAD); + if (resolved_k != obj_k) { + return; + } + if ((obj_k)->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(obj_k); + ik->initialize(THREAD); + } else if ((obj_k)->is_objArray_klass()) { + ObjArrayKlass* oak = ObjArrayKlass::cast(obj_k); + oak->initialize(THREAD); } } + } - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - // None of the field value will be set if there was an exception. - // The java code will not see any of the archived objects in the - // subgraphs referenced from k in this case. - return; - } + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + // None of the field value will be set if there was an exception. + // The java code will not see any of the archived objects in the + // subgraphs referenced from k in this case. + return; + } - // Load the subgraph entry fields from the record and store them back to - // the corresponding fields within the mirror. - oop m = k->java_mirror(); - Array* entry_field_records = record->entry_field_records(); - if (entry_field_records != NULL) { - int efr_len = entry_field_records->length(); - assert(efr_len % 2 == 0, "sanity"); - for (i = 0; i < efr_len;) { - int field_offset = entry_field_records->at(i); - // The object refereced by the field becomes 'known' by GC from this - // point. All objects in the subgraph reachable from the object are - // also 'known' by GC. - oop v = MetaspaceShared::materialize_archived_object( + // Load the subgraph entry fields from the record and store them back to + // the corresponding fields within the mirror. + oop m = k->java_mirror(); + Array* entry_field_records = record->entry_field_records(); + if (entry_field_records != NULL) { + int efr_len = entry_field_records->length(); + assert(efr_len % 2 == 0, "sanity"); + for (i = 0; i < efr_len;) { + int field_offset = entry_field_records->at(i); + // The object refereced by the field becomes 'known' by GC from this + // point. All objects in the subgraph reachable from the object are + // also 'known' by GC. + oop v = MetaspaceShared::materialize_archived_object( entry_field_records->at(i+1)); - m->obj_field_put(field_offset, v); - i += 2; - } + m->obj_field_put(field_offset, v); + i += 2; + + log_debug(cds, heap)(" %p init field @ %2d = %p", k, field_offset, (address)v); } - // Done. Java code can see the archived sub-graphs referenced from k's - // mirror after this point. - return; + // Done. Java code can see the archived sub-graphs referenced from k's + // mirror after this point. } } } @@ -702,6 +650,8 @@ }; void HeapShared::init_archivable_static_fields(Thread* THREAD) { + _dump_time_subgraph_info_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeKlassSubGraphInfoTable(); + for (int i = 0; i < num_archivable_static_fields; i++) { ArchivableStaticFieldInfo* info = &archivable_static_fields[i]; TempNewSymbol klass_name = SymbolTable::new_symbol(info->klass_name, THREAD); --- old/src/hotspot/share/memory/heapShared.hpp 2018-09-20 11:16:38.605102549 -0700 +++ new/src/hotspot/share/memory/heapShared.hpp 2018-09-20 11:16:38.301090935 -0700 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_MEMORY_HEAPSHARED_HPP #define SHARE_VM_MEMORY_HEAPSHARED_HPP +#include "classfile/compactHashtable.hpp" #include "classfile/systemDictionary.hpp" #include "memory/allocation.hpp" #include "memory/universe.hpp" @@ -42,7 +43,6 @@ // within the sub-graphs. class KlassSubGraphInfo: public CHeapObj { private: - KlassSubGraphInfo* _next; // The class that contains the static field(s) as the entry point(s) // of archived object sub-graph(s). Klass* _k; @@ -54,8 +54,8 @@ GrowableArray* _subgraph_entry_fields; public: - KlassSubGraphInfo(Klass* k, KlassSubGraphInfo* next) : - _next(next), _k(k), _subgraph_object_klasses(NULL), + KlassSubGraphInfo(Klass* k) : + _k(k), _subgraph_object_klasses(NULL), _subgraph_entry_fields(NULL) {} ~KlassSubGraphInfo() { if (_subgraph_object_klasses != NULL) { @@ -66,7 +66,6 @@ } }; - KlassSubGraphInfo* next() { return _next; } Klass* klass() { return _k; } GrowableArray* subgraph_object_klasses() { return _subgraph_object_klasses; @@ -87,7 +86,6 @@ // at runtime. class ArchivedKlassSubGraphInfoRecord { private: - ArchivedKlassSubGraphInfoRecord* _next; Klass* _k; // contains pairs of field offset and value for each subgraph entry field @@ -98,11 +96,9 @@ Array* _subgraph_object_klasses; public: ArchivedKlassSubGraphInfoRecord() : - _next(NULL), _k(NULL), _entry_field_records(NULL), _subgraph_object_klasses(NULL) {} + _k(NULL), _entry_field_records(NULL), _subgraph_object_klasses(NULL) {} void init(KlassSubGraphInfo* info); Klass* klass() { return _k; } - ArchivedKlassSubGraphInfoRecord* next() { return _next; } - void set_next(ArchivedKlassSubGraphInfoRecord* next) { _next = next; } Array* entry_field_records() { return _entry_field_records; } Array* subgraph_object_klasses() { return _subgraph_object_klasses; } }; @@ -112,14 +108,42 @@ friend class VerifySharedOopClosure; private: #if INCLUDE_CDS_JAVA_HEAP - // This is a list of subgraph infos built at dump time while - // archiving object subgraphs. - static KlassSubGraphInfo* _subgraph_info_list; - - // Contains a list of ArchivedKlassSubGraphInfoRecords that is stored - // in the archive file and reloaded at runtime. - static int _num_archived_subgraph_info_records; - static Array* _archived_subgraph_info_records; + + static bool klass_equals(Klass* const& p1, Klass* const& p2) { + return primitive_equals(p1, p2); + } + + static unsigned klass_hash(Klass* const& klass) { + return primitive_hash
((address)klass); + } + + class DumpTimeKlassSubGraphInfoTable + : public ResourceHashtable { + public: + int _count; + }; + + inline static ArchivedKlassSubGraphInfoRecord* read_record_from_compact_hashtable(address base_address, u4 offset) { + return (ArchivedKlassSubGraphInfoRecord*)(base_address + offset); + } + + inline static bool record_equals_compact_hashtable_entry(ArchivedKlassSubGraphInfoRecord* value, const Klass* key, int len_unused) { + return (value->klass() == key); + } + + typedef CompactHashtable< + const Klass*, + ArchivedKlassSubGraphInfoRecord*, + read_record_from_compact_hashtable, + record_equals_compact_hashtable_entry + > RunTimeKlassSubGraphInfoTable; + + static DumpTimeKlassSubGraphInfoTable* _dump_time_subgraph_info_table; + static RunTimeKlassSubGraphInfoTable _run_time_subgraph_info_table; // Archive object sub-graph starting from the given static field // in Klass k's mirror. @@ -131,11 +155,10 @@ static void verify_reachable_objects_from(oop obj, bool is_archived) PRODUCT_RETURN; - static KlassSubGraphInfo* find_subgraph_info(Klass *k); static KlassSubGraphInfo* get_subgraph_info(Klass *k); static int num_of_subgraph_infos(); - static size_t build_archived_subgraph_info_records(int num_records); + static void build_archived_subgraph_info_records(int num_records); // Used by decode_from_archive static address _narrow_oop_base; @@ -203,6 +226,8 @@ static void init_archivable_static_fields(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN; static void archive_static_fields(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN; + static void create_hashtables() NOT_CDS_JAVA_HEAP_RETURN; + static void serialize_hashtables(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; #if INCLUDE_CDS_JAVA_HEAP static ResourceBitMap calculate_oopmap(MemRegion region); --- old/src/hotspot/share/memory/metaspaceShared.cpp 2018-09-20 11:16:39.281128374 -0700 +++ new/src/hotspot/share/memory/metaspaceShared.cpp 2018-09-20 11:16:39.021118441 -0700 @@ -422,6 +422,9 @@ // Dump/restore the symbol and string tables SymbolTable::serialize(soc); StringTable::serialize(soc); + + // Dump/restore the tables related to shared heap objects + HeapShared::serialize_hashtables(soc); soc->do_tag(--tag); JavaClasses::serialize_offsets(soc); @@ -1097,6 +1100,21 @@ return _alloc_stats; } + // Use this when you allocate space with MetaspaceShare::read_only_space_alloc() + // outside of ArchiveCompactor::allocate(). These are usually for misc tables + // that are allocated in the RO space. + class OtherROAllocMark { + char* _oldtop; + public: + OtherROAllocMark() { + _oldtop = _ro_region.top(); + } + ~OtherROAllocMark() { + char* newtop = _ro_region.top(); + ArchiveCompactor::alloc_stats()->record_other_type(int(newtop - _oldtop), true); + } + }; + static void allocate(MetaspaceClosure::Ref* ref, bool read_only) { address obj = ref->obj(); int bytes = ref->size() * BytesPerWord; @@ -1307,7 +1325,7 @@ } char* VM_PopulateDumpSharedSpace::dump_read_only_tables() { - char* oldtop = _ro_region.top(); + ArchiveCompactor::OtherROAllocMark mark; // Reorder the system dictionary. Moving the symbols affects // how the hash table indices are calculated. SystemDictionary::reorder_dictionary_for_sharing(); @@ -1328,11 +1346,6 @@ char* table_top = _ro_region.allocate(table_bytes, sizeof(intptr_t)); SystemDictionary::copy_table(table_top, _ro_region.top()); - // Write the archived object sub-graph infos. For each klass with sub-graphs, - // the info includes the static fields (sub-graph entry points) and Klasses - // of objects included in the sub-graph. - HeapShared::write_archived_subgraph_infos(); - // Write the other data to the output array. WriteClosure wc(&_ro_region); MetaspaceShared::serialize(&wc); @@ -1340,8 +1353,6 @@ // Write the bitmaps for patching the archive heap regions dump_archive_heap_oopmaps(); - char* newtop = _ro_region.top(); - ArchiveCompactor::alloc_stats()->record_other_type(int(newtop - oldtop), true); return buckets_top; } @@ -1821,6 +1832,11 @@ } G1HeapVerifier::verify_archive_regions(); + + { + ArchiveCompactor::OtherROAllocMark mark; + HeapShared::create_hashtables(); + } } void VM_PopulateDumpSharedSpace::dump_archive_heap_oopmaps() { @@ -1888,7 +1904,7 @@ unsigned MetaspaceShared::obj_hash(oop const& p) { assert(!p->mark()->has_bias_pattern(), - "this object should never have been locked"); // so identity_hash won't safepoin + "this object should never have been locked"); // so identity_hash won't safepoint unsigned hash = (unsigned)p->identity_hash(); return hash; } @@ -2144,9 +2160,6 @@ buffer += sizeof(intptr_t); buffer += len; - // The table of archived java heap object sub-graph infos - buffer = HeapShared::read_archived_subgraph_infos(buffer); - // Verify various attributes of the archive, plus initialize the // shared string/symbol tables intptr_t* array = (intptr_t*)buffer;