mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-22 05:50:03 +00:00
8210388: Use hash table to store archived subgraph_info records
Reviewed-by: jiangli
This commit is contained in:
parent
859d376494
commit
2f82ed4f1d
@ -174,7 +174,7 @@ void CompactHashtableWriter::dump(SimpleCompactHashtable *cht, const char* table
|
||||
// The CompactHashtable implementation
|
||||
//
|
||||
|
||||
void SimpleCompactHashtable::serialize(SerializeClosure* soc) {
|
||||
void SimpleCompactHashtable::serialize_header(SerializeClosure* soc) {
|
||||
soc->do_ptr((void**)&_base_address);
|
||||
soc->do_u4(&_entry_count);
|
||||
soc->do_u4(&_bucket_count);
|
||||
|
||||
@ -123,6 +123,15 @@ private:
|
||||
|
||||
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
|
||||
|
||||
@ -213,8 +222,8 @@ public:
|
||||
_entries = entries;
|
||||
}
|
||||
|
||||
// For reading from/writing to the CDS archive
|
||||
void serialize(SerializeClosure* soc) NOT_CDS_RETURN;
|
||||
// Read/Write the table's header from/to the CDS archive
|
||||
void serialize_header(SerializeClosure* soc) NOT_CDS_RETURN;
|
||||
|
||||
inline bool empty() {
|
||||
return (_entry_count == 0);
|
||||
|
||||
@ -819,18 +819,9 @@ oop StringTable::create_archived_string(oop s, Thread* THREAD) {
|
||||
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<vm_string_table_data>* val) {
|
||||
oop s = val->peek();
|
||||
if (s == NULL) {
|
||||
@ -838,6 +829,7 @@ struct CopyToArchive : StackObj {
|
||||
}
|
||||
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 @@ struct CopyToArchive : StackObj {
|
||||
|
||||
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,18 +857,18 @@ void StringTable::write_to_archive() {
|
||||
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);
|
||||
writer.dump(&_shared_table, "string");
|
||||
}
|
||||
|
||||
void StringTable::serialize(SerializeClosure* soc) {
|
||||
_shared_table.serialize(soc);
|
||||
void StringTable::serialize_shared_table_header(SerializeClosure* soc) {
|
||||
_shared_table.serialize_header(soc);
|
||||
|
||||
if (soc->writing()) {
|
||||
// Sanity. Make sure we don't use the shared table at dump time
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#include "oops/weakHandle.hpp"
|
||||
#include "utilities/concurrentHashTable.hpp"
|
||||
|
||||
class CompactStringTableWriter;
|
||||
class CompactHashtableWriter;
|
||||
class SerializeClosure;
|
||||
|
||||
class StringTable;
|
||||
@ -163,14 +163,14 @@ private:
|
||||
// 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; }
|
||||
static bool shared_string_mapped() { return _shared_string_mapped; }
|
||||
static void shared_oops_do(OopClosure* f) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void write_to_archive() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void serialize(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
// Jcmd
|
||||
static void dump(outputStream* st, bool verbose=false);
|
||||
|
||||
@ -627,43 +627,31 @@ void SymbolTable::dump(outputStream* st, bool verbose) {
|
||||
}
|
||||
|
||||
#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);
|
||||
struct CopyToArchive : StackObj {
|
||||
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());
|
||||
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);
|
||||
|
||||
CompactHashtableWriter::add(hash, delta);
|
||||
}
|
||||
};
|
||||
|
||||
struct CopyToArchive : StackObj {
|
||||
CompactSymbolTableWriter* _writer;
|
||||
CopyToArchive(CompactSymbolTableWriter* 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;
|
||||
}
|
||||
assert(fixed_hash == hash_symbol((const char*)sym->bytes(), sym->utf8_length(), false),
|
||||
"must not rehash during dumping");
|
||||
|
||||
// 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::copy_shared_symbol_table(CompactSymbolTableWriter* writer) {
|
||||
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");
|
||||
|
||||
@ -686,8 +674,8 @@ void SymbolTable::write_to_archive() {
|
||||
assert(sym == _shared_table.lookup(name, hash, len), "sanity");
|
||||
}
|
||||
|
||||
void SymbolTable::serialize(SerializeClosure* soc) {
|
||||
_shared_table.serialize(soc);
|
||||
void SymbolTable::serialize_shared_table_header(SerializeClosure* soc) {
|
||||
_shared_table.serialize_header(soc);
|
||||
|
||||
if (soc->writing()) {
|
||||
// Sanity. Make sure we don't use the shared table at dump time
|
||||
|
||||
@ -84,7 +84,7 @@ public:
|
||||
operator Symbol*() { return _temp; }
|
||||
};
|
||||
|
||||
class CompactSymbolTableWriter;
|
||||
class CompactHashtableWriter;
|
||||
class SerializeClosure;
|
||||
|
||||
class SymbolTableConfig;
|
||||
@ -240,10 +240,10 @@ public:
|
||||
|
||||
// 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;
|
||||
static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_RETURN;
|
||||
static void metaspace_pointers_do(MetaspaceClosure* it);
|
||||
|
||||
// Jcmd
|
||||
|
||||
@ -41,49 +41,26 @@
|
||||
#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<ArchivedKlassSubGraphInfoRecord>* 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) {
|
||||
assert(DumpSharedSpaces, "dump time only");
|
||||
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 +133,6 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k, Klass *relocate
|
||||
// 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 +167,26 @@ void ArchivedKlassSubGraphInfoRecord::init(KlassSubGraphInfo* info) {
|
||||
}
|
||||
}
|
||||
|
||||
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*>(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,145 +194,97 @@ void ArchivedKlassSubGraphInfoRecord::init(KlassSubGraphInfo* info) {
|
||||
// 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();
|
||||
void HeapShared::write_subgraph_info_table() {
|
||||
// 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;
|
||||
|
||||
// now populate the archived subgraph infos, which will be saved in the
|
||||
// archive file
|
||||
_archived_subgraph_info_records =
|
||||
MetaspaceShared::new_ro_array<ArchivedKlassSubGraphInfoRecord>(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 ++;
|
||||
}
|
||||
_run_time_subgraph_info_table.reset();
|
||||
|
||||
// _subgraph_info_list is no longer needed
|
||||
delete _subgraph_info_list;
|
||||
_subgraph_info_list = NULL;
|
||||
int num_buckets = CompactHashtableWriter::default_num_buckets(d_table->_count);
|
||||
CompactHashtableWriter writer(num_buckets, &stats);
|
||||
CopyKlassSubGraphInfoToArchive copy(&writer);
|
||||
_dump_time_subgraph_info_table->iterate(©);
|
||||
|
||||
char* end_p = MetaspaceShared::read_only_space_top();
|
||||
size_t records_size = end_p - start_p;
|
||||
return records_size;
|
||||
writer.dump(&_run_time_subgraph_info_table, "subgraphs");
|
||||
}
|
||||
|
||||
// Write the subgraph info records in the shared _ro region
|
||||
void HeapShared::write_archived_subgraph_infos() {
|
||||
assert(DumpSharedSpaces, "dump time only");
|
||||
|
||||
Array<intptr_t>* records_header = MetaspaceShared::new_ro_array<intptr_t>(3);
|
||||
|
||||
_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<intptr_t>* records_header = (Array<intptr_t>*)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<ArchivedKlassSubGraphInfoRecord>*)(*p);
|
||||
|
||||
buffer = (char*)_archived_subgraph_info_records + records_size;
|
||||
return buffer;
|
||||
void HeapShared::serialize_subgraph_info_table_header(SerializeClosure* soc) {
|
||||
_run_time_subgraph_info_table.serialize_header(soc);
|
||||
}
|
||||
|
||||
void HeapShared::initialize_from_archived_subgraph(Klass* k) {
|
||||
if (!MetaspaceShared::open_archive_heap_region_mapped()) {
|
||||
return; // nothing to do
|
||||
}
|
||||
assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
|
||||
|
||||
if (_num_archived_subgraph_info_records == 0) {
|
||||
return; // no subgraph info records
|
||||
}
|
||||
unsigned int hash = primitive_hash<Klass*>(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<Klass*>* 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 " PTR_FORMAT " %s", p2i(k),
|
||||
k->external_name());
|
||||
}
|
||||
|
||||
int i;
|
||||
// Load/link/initialize the klasses of the objects in the subgraph.
|
||||
// NULL class loader is used.
|
||||
Array<Klass*>* 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;
|
||||
}
|
||||
|
||||
// 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<juint>* 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Done. Java code can see the archived sub-graphs referenced from k's
|
||||
// mirror after this point.
|
||||
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<juint>* 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;
|
||||
|
||||
log_debug(cds, heap)(" " PTR_FORMAT " init field @ %2d = " PTR_FORMAT, p2i(k), field_offset, p2i(v));
|
||||
}
|
||||
|
||||
// Done. Java code can see the archived sub-graphs referenced from k's
|
||||
// mirror after this point.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -702,6 +650,8 @@ public:
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
@ -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<mtClass> {
|
||||
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 @@ class KlassSubGraphInfo: public CHeapObj<mtClass> {
|
||||
GrowableArray<juint>* _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 @@ class KlassSubGraphInfo: public CHeapObj<mtClass> {
|
||||
}
|
||||
};
|
||||
|
||||
KlassSubGraphInfo* next() { return _next; }
|
||||
Klass* klass() { return _k; }
|
||||
GrowableArray<Klass*>* subgraph_object_klasses() {
|
||||
return _subgraph_object_klasses;
|
||||
@ -87,7 +86,6 @@ class KlassSubGraphInfo: public CHeapObj<mtClass> {
|
||||
// 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 @@ class ArchivedKlassSubGraphInfoRecord {
|
||||
Array<Klass*>* _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<juint>* entry_field_records() { return _entry_field_records; }
|
||||
Array<Klass*>* subgraph_object_klasses() { return _subgraph_object_klasses; }
|
||||
};
|
||||
@ -112,14 +108,42 @@ class HeapShared: AllStatic {
|
||||
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<ArchivedKlassSubGraphInfoRecord>* _archived_subgraph_info_records;
|
||||
static bool klass_equals(Klass* const& p1, Klass* const& p2) {
|
||||
return primitive_equals<Klass*>(p1, p2);
|
||||
}
|
||||
|
||||
static unsigned klass_hash(Klass* const& klass) {
|
||||
return primitive_hash<address>((address)klass);
|
||||
}
|
||||
|
||||
class DumpTimeKlassSubGraphInfoTable
|
||||
: public ResourceHashtable<Klass*, KlassSubGraphInfo,
|
||||
HeapShared::klass_hash,
|
||||
HeapShared::klass_equals,
|
||||
137, // prime number
|
||||
ResourceObj::C_HEAP> {
|
||||
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 @@ class HeapShared: AllStatic {
|
||||
|
||||
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 @@ class HeapShared: AllStatic {
|
||||
|
||||
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 write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void serialize_subgraph_info_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
static ResourceBitMap calculate_oopmap(MemRegion region);
|
||||
|
||||
@ -420,10 +420,10 @@ void MetaspaceShared::serialize(SerializeClosure* soc) {
|
||||
vmSymbols::serialize(soc);
|
||||
soc->do_tag(--tag);
|
||||
|
||||
// Dump/restore the symbol and string tables
|
||||
SymbolTable::serialize(soc);
|
||||
StringTable::serialize(soc);
|
||||
soc->do_tag(--tag);
|
||||
// Dump/restore the symbol/string/subgraph_info tables
|
||||
SymbolTable::serialize_shared_table_header(soc);
|
||||
StringTable::serialize_shared_table_header(soc);
|
||||
HeapShared::serialize_subgraph_info_table_header(soc);
|
||||
|
||||
JavaClasses::serialize_offsets(soc);
|
||||
InstanceMirrorKlass::serialize_offsets(soc);
|
||||
@ -1098,6 +1098,21 @@ public:
|
||||
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;
|
||||
@ -1308,7 +1323,7 @@ void VM_PopulateDumpSharedSpace::dump_symbols() {
|
||||
}
|
||||
|
||||
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();
|
||||
@ -1329,11 +1344,6 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
|
||||
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);
|
||||
@ -1341,8 +1351,6 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -1822,6 +1830,11 @@ void VM_PopulateDumpSharedSpace::dump_java_heap_objects() {
|
||||
}
|
||||
|
||||
G1HeapVerifier::verify_archive_regions();
|
||||
|
||||
{
|
||||
ArchiveCompactor::OtherROAllocMark mark;
|
||||
HeapShared::write_subgraph_info_table();
|
||||
}
|
||||
}
|
||||
|
||||
void VM_PopulateDumpSharedSpace::dump_archive_heap_oopmaps() {
|
||||
@ -1889,7 +1902,7 @@ void MetaspaceShared::dump_open_archive_heap_objects(
|
||||
|
||||
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;
|
||||
}
|
||||
@ -2145,9 +2158,6 @@ void MetaspaceShared::initialize_shared_spaces() {
|
||||
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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user