mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-18 01:54:47 +02:00
8293182: Improve testing of CDS archive heap
Reviewed-by: ccheung, coleenp
This commit is contained in:
parent
51de765867
commit
f84386cf6e
11 changed files with 594 additions and 81 deletions
|
@ -65,9 +65,33 @@
|
|||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
struct ArchivableStaticFieldInfo {
|
||||
const char* klass_name;
|
||||
const char* field_name;
|
||||
InstanceKlass* klass;
|
||||
int offset;
|
||||
BasicType type;
|
||||
|
||||
ArchivableStaticFieldInfo(const char* k, const char* f)
|
||||
: klass_name(k), field_name(f), klass(NULL), offset(0), type(T_ILLEGAL) {}
|
||||
|
||||
bool valid() {
|
||||
return klass_name != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
bool HeapShared::_disable_writing = false;
|
||||
DumpedInternedStrings *HeapShared::_dumped_interned_strings = NULL;
|
||||
|
||||
#ifndef PRODUCT
|
||||
#define ARCHIVE_TEST_FIELD_NAME "archivedObjects"
|
||||
static Array<char>* _archived_ArchiveHeapTestClass = NULL;
|
||||
static const char* _test_class_name = NULL;
|
||||
static const Klass* _test_class = NULL;
|
||||
static const ArchivedKlassSubGraphInfoRecord* _test_class_record = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// If you add new entries to the following tables, you should know what you're doing!
|
||||
//
|
||||
|
@ -83,6 +107,7 @@ static ArchivableStaticFieldInfo closed_archive_subgraph_entry_fields[] = {
|
|||
{"java/lang/Character$CharacterCache", "archivedCache"},
|
||||
{"java/util/jar/Attributes$Name", "KNOWN_NAMES"},
|
||||
{"sun/util/locale/BaseLocale", "constantBaseLocales"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
// Entry fields for subgraphs archived in the open archive heap region.
|
||||
static ArchivableStaticFieldInfo open_archive_subgraph_entry_fields[] = {
|
||||
|
@ -91,6 +116,10 @@ static ArchivableStaticFieldInfo open_archive_subgraph_entry_fields[] = {
|
|||
{"java/lang/ModuleLayer", "EMPTY_LAYER"},
|
||||
{"java/lang/module/Configuration", "EMPTY_CONFIGURATION"},
|
||||
{"jdk/internal/math/FDBigInteger", "archivedCaches"},
|
||||
#ifndef PRODUCT
|
||||
{NULL, NULL}, // Extra slot for -XX:ArchiveHeapTestClass
|
||||
#endif
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
// Entry fields for subgraphs archived in the open archive heap region (full module graph).
|
||||
|
@ -98,15 +127,9 @@ static ArchivableStaticFieldInfo fmg_open_archive_subgraph_entry_fields[] = {
|
|||
{"jdk/internal/loader/ArchivedClassLoaders", "archivedClassLoaders"},
|
||||
{"jdk/internal/module/ArchivedBootLayer", "archivedBootLayer"},
|
||||
{"java/lang/Module$ArchivedData", "archivedData"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
const static int num_closed_archive_subgraph_entry_fields =
|
||||
sizeof(closed_archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
|
||||
const static int num_open_archive_subgraph_entry_fields =
|
||||
sizeof(open_archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
|
||||
const static int num_fmg_open_archive_subgraph_entry_fields =
|
||||
sizeof(fmg_open_archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
|
||||
|
||||
GrowableArrayCHeap<oop, mtClassShared>* HeapShared::_pending_roots = NULL;
|
||||
OopHandle HeapShared::_roots;
|
||||
|
||||
|
@ -118,8 +141,8 @@ bool HeapShared::is_archived_object_during_dumptime(oop p) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static bool is_subgraph_root_class_of(ArchivableStaticFieldInfo fields[], int num, InstanceKlass* ik) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
static bool is_subgraph_root_class_of(ArchivableStaticFieldInfo fields[], InstanceKlass* ik) {
|
||||
for (int i = 0; fields[i].valid(); i++) {
|
||||
if (fields[i].klass == ik) {
|
||||
return true;
|
||||
}
|
||||
|
@ -128,12 +151,9 @@ static bool is_subgraph_root_class_of(ArchivableStaticFieldInfo fields[], int nu
|
|||
}
|
||||
|
||||
bool HeapShared::is_subgraph_root_class(InstanceKlass* ik) {
|
||||
return is_subgraph_root_class_of(closed_archive_subgraph_entry_fields,
|
||||
num_closed_archive_subgraph_entry_fields, ik) ||
|
||||
is_subgraph_root_class_of(open_archive_subgraph_entry_fields,
|
||||
num_open_archive_subgraph_entry_fields, ik) ||
|
||||
is_subgraph_root_class_of(fmg_open_archive_subgraph_entry_fields,
|
||||
num_fmg_open_archive_subgraph_entry_fields, ik);
|
||||
return is_subgraph_root_class_of(closed_archive_subgraph_entry_fields, ik) ||
|
||||
is_subgraph_root_class_of(open_archive_subgraph_entry_fields, ik) ||
|
||||
is_subgraph_root_class_of(fmg_open_archive_subgraph_entry_fields, ik);
|
||||
}
|
||||
|
||||
unsigned HeapShared::oop_hash(oop const& p) {
|
||||
|
@ -477,7 +497,6 @@ void HeapShared::copy_closed_objects(GrowableArray<MemRegion>* closed_regions) {
|
|||
StringTable::write_to_archive(_dumped_interned_strings);
|
||||
|
||||
archive_object_subgraphs(closed_archive_subgraph_entry_fields,
|
||||
num_closed_archive_subgraph_entry_fields,
|
||||
true /* is_closed_archive */,
|
||||
false /* is_full_module_graph */);
|
||||
|
||||
|
@ -495,12 +514,10 @@ void HeapShared::copy_open_objects(GrowableArray<MemRegion>* open_regions) {
|
|||
archive_klass_objects();
|
||||
|
||||
archive_object_subgraphs(open_archive_subgraph_entry_fields,
|
||||
num_open_archive_subgraph_entry_fields,
|
||||
false /* is_closed_archive */,
|
||||
false /* is_full_module_graph */);
|
||||
if (MetaspaceShared::use_full_module_graph()) {
|
||||
archive_object_subgraphs(fmg_open_archive_subgraph_entry_fields,
|
||||
num_fmg_open_archive_subgraph_entry_fields,
|
||||
false /* is_closed_archive */,
|
||||
true /* is_full_module_graph */);
|
||||
ClassLoaderDataShared::init_archived_oops();
|
||||
|
@ -612,11 +629,13 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) {
|
|||
// to the sub-graph object class list.
|
||||
return;
|
||||
}
|
||||
check_allowed_klass(InstanceKlass::cast(orig_k));
|
||||
} else if (relocated_k->is_objArray_klass()) {
|
||||
Klass* abk = ObjArrayKlass::cast(relocated_k)->bottom_klass();
|
||||
if (abk->is_instance_klass()) {
|
||||
assert(InstanceKlass::cast(abk)->is_shared_boot_class(),
|
||||
"must be boot class");
|
||||
check_allowed_klass(InstanceKlass::cast(ObjArrayKlass::cast(orig_k)->bottom_klass()));
|
||||
}
|
||||
if (relocated_k == Universe::objectArrayKlassObj()) {
|
||||
// Initialized early during Universe::genesis. No need to be added
|
||||
|
@ -640,6 +659,28 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) {
|
|||
_has_non_early_klasses |= is_non_early_klass(orig_k);
|
||||
}
|
||||
|
||||
void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) {
|
||||
if (ik->module()->name() == vmSymbols::java_base()) {
|
||||
assert(ik->package() != NULL, "classes in java.base cannot be in unnamed package");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (!ik->module()->is_named() && ik->package() == NULL) {
|
||||
// This class is loaded by ArchiveHeapTestClass
|
||||
return;
|
||||
}
|
||||
const char* extra_msg = ", or in an unnamed package of an unnamed module";
|
||||
#else
|
||||
const char* extra_msg = "";
|
||||
#endif
|
||||
|
||||
ResourceMark rm;
|
||||
log_error(cds, heap)("Class %s not allowed in archive heap. Must be in java.base%s",
|
||||
ik->external_name(), extra_msg);
|
||||
os::_exit(1);
|
||||
}
|
||||
|
||||
bool KlassSubGraphInfo::is_non_early_klass(Klass* k) {
|
||||
if (k->is_objArray_klass()) {
|
||||
k = ObjArrayKlass::cast(k)->bottom_klass();
|
||||
|
@ -753,6 +794,15 @@ void HeapShared::write_subgraph_info_table() {
|
|||
CopyKlassSubGraphInfoToArchive copy(&writer);
|
||||
d_table->iterate(©);
|
||||
writer.dump(&_run_time_subgraph_info_table, "subgraphs");
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (ArchiveHeapTestClass != NULL) {
|
||||
size_t len = strlen(ArchiveHeapTestClass) + 1;
|
||||
Array<char>* array = ArchiveBuilder::new_ro_array<char>((int)len);
|
||||
strncpy(array->adr_at(0), ArchiveHeapTestClass, len);
|
||||
_archived_ArchiveHeapTestClass = array;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void HeapShared::serialize(SerializeClosure* soc) {
|
||||
|
@ -772,6 +822,14 @@ void HeapShared::serialize(SerializeClosure* soc) {
|
|||
soc->do_oop(&roots_oop); // write to archive
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
soc->do_ptr((void**)&_archived_ArchiveHeapTestClass);
|
||||
if (soc->reading() && _archived_ArchiveHeapTestClass != NULL) {
|
||||
_test_class_name = _archived_ArchiveHeapTestClass->adr_at(0);
|
||||
setup_test_class(_test_class_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
_run_time_subgraph_info_table.serialize_header(soc);
|
||||
}
|
||||
|
||||
|
@ -809,23 +867,18 @@ static void verify_the_heap(Klass* k, const char* which) {
|
|||
// ClassFileLoadHook is enabled, it's possible for this class to be dynamically replaced. In
|
||||
// this case, we will not load the ArchivedKlassSubGraphInfoRecord and will clear its roots.
|
||||
void HeapShared::resolve_classes(JavaThread* THREAD) {
|
||||
assert(UseSharedSpaces, "runtime only!");
|
||||
if (!ArchiveHeapLoader::is_fully_available()) {
|
||||
return; // nothing to do
|
||||
}
|
||||
resolve_classes_for_subgraphs(closed_archive_subgraph_entry_fields,
|
||||
num_closed_archive_subgraph_entry_fields,
|
||||
THREAD);
|
||||
resolve_classes_for_subgraphs(open_archive_subgraph_entry_fields,
|
||||
num_open_archive_subgraph_entry_fields,
|
||||
THREAD);
|
||||
resolve_classes_for_subgraphs(fmg_open_archive_subgraph_entry_fields,
|
||||
num_fmg_open_archive_subgraph_entry_fields,
|
||||
THREAD);
|
||||
resolve_classes_for_subgraphs(closed_archive_subgraph_entry_fields, THREAD);
|
||||
resolve_classes_for_subgraphs(open_archive_subgraph_entry_fields, THREAD);
|
||||
resolve_classes_for_subgraphs(fmg_open_archive_subgraph_entry_fields, THREAD);
|
||||
}
|
||||
|
||||
void HeapShared::resolve_classes_for_subgraphs(ArchivableStaticFieldInfo fields[],
|
||||
int num, JavaThread* THREAD) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
JavaThread* THREAD) {
|
||||
for (int i = 0; fields[i].valid(); i++) {
|
||||
ArchivableStaticFieldInfo* info = &fields[i];
|
||||
TempNewSymbol klass_name = SymbolTable::new_symbol(info->klass_name);
|
||||
InstanceKlass* k = SystemDictionaryShared::find_builtin_class(klass_name);
|
||||
|
@ -878,6 +931,13 @@ HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAP
|
|||
unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(k);
|
||||
const ArchivedKlassSubGraphInfoRecord* record = _run_time_subgraph_info_table.lookup(k, hash, 0);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (_test_class_name != NULL && k->name()->equals(_test_class_name) && record != NULL) {
|
||||
_test_class = k;
|
||||
_test_class_record = record;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize from archived data. Currently this is done only
|
||||
// during VM initialization time. No lock is needed.
|
||||
if (record != NULL) {
|
||||
|
@ -899,6 +959,11 @@ HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAP
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (log_is_enabled(Info, cds, heap)) {
|
||||
ResourceMark rm;
|
||||
log_info(cds, heap)("%s subgraph %s ", do_init ? "init" : "resolve", k->external_name());
|
||||
}
|
||||
|
||||
resolve_or_init(k, do_init, CHECK_NULL);
|
||||
|
||||
// Load/link/initialize the klasses of the objects in the subgraph.
|
||||
|
@ -1400,10 +1465,11 @@ public:
|
|||
|
||||
virtual void do_field(fieldDescriptor* fd) {
|
||||
if (fd->name() == _field_name) {
|
||||
assert(!_found, "fields cannot be overloaded");
|
||||
assert(is_reference_type(fd->field_type()), "can archive only fields that are references");
|
||||
_found = true;
|
||||
_offset = fd->offset();
|
||||
assert(!_found, "fields can never be overloaded");
|
||||
if (is_reference_type(fd->field_type())) {
|
||||
_found = true;
|
||||
_offset = fd->offset();
|
||||
}
|
||||
}
|
||||
}
|
||||
bool found() { return _found; }
|
||||
|
@ -1411,21 +1477,79 @@ public:
|
|||
};
|
||||
|
||||
void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
|
||||
int num, TRAPS) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
TRAPS) {
|
||||
for (int i = 0; fields[i].valid(); i++) {
|
||||
ArchivableStaticFieldInfo* info = &fields[i];
|
||||
TempNewSymbol klass_name = SymbolTable::new_symbol(info->klass_name);
|
||||
TempNewSymbol field_name = SymbolTable::new_symbol(info->field_name);
|
||||
ResourceMark rm; // for stringStream::as_string() etc.
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool is_test_class = (ArchiveHeapTestClass != NULL) && (strcmp(info->klass_name, ArchiveHeapTestClass) == 0);
|
||||
#else
|
||||
bool is_test_class = false;
|
||||
#endif
|
||||
|
||||
if (is_test_class) {
|
||||
log_warning(cds)("Loading ArchiveHeapTestClass %s ...", ArchiveHeapTestClass);
|
||||
}
|
||||
|
||||
Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
stringStream st;
|
||||
st.print("Fail to initialize archive heap: %s cannot be loaded by the boot loader", info->klass_name);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||
}
|
||||
|
||||
if (!k->is_instance_klass()) {
|
||||
stringStream st;
|
||||
st.print("Fail to initialize archive heap: %s is not an instance class", info->klass_name);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||
}
|
||||
|
||||
Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, CHECK);
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
assert(InstanceKlass::cast(ik)->is_shared_boot_class(),
|
||||
"Only support boot classes");
|
||||
|
||||
if (is_test_class) {
|
||||
if (ik->module()->is_named()) {
|
||||
// We don't want ArchiveHeapTestClass to be abused to easily load/initialize arbitrary
|
||||
// core-lib classes. You need to at least append to the bootclasspath.
|
||||
stringStream st;
|
||||
st.print("ArchiveHeapTestClass %s is not in unnamed module", ArchiveHeapTestClass);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||
}
|
||||
|
||||
if (ik->package() != NULL) {
|
||||
// This restriction makes HeapShared::is_a_test_class_in_unnamed_module() easy.
|
||||
stringStream st;
|
||||
st.print("ArchiveHeapTestClass %s is not in unnamed package", ArchiveHeapTestClass);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||
}
|
||||
} else {
|
||||
if (ik->module()->name() != vmSymbols::java_base()) {
|
||||
// We don't want to deal with cases when a module is unavailable at runtime.
|
||||
// FUTURE -- load from archived heap only when module graph has not changed
|
||||
// between dump and runtime.
|
||||
stringStream st;
|
||||
st.print("%s is not in java.base module", info->klass_name);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||
}
|
||||
}
|
||||
|
||||
if (is_test_class) {
|
||||
log_warning(cds)("Initializing ArchiveHeapTestClass %s ...", ArchiveHeapTestClass);
|
||||
}
|
||||
ik->initialize(CHECK);
|
||||
|
||||
ArchivableStaticFieldFinder finder(ik, field_name);
|
||||
ik->do_local_static_fields(&finder);
|
||||
assert(finder.found(), "field must exist");
|
||||
if (!finder.found()) {
|
||||
stringStream st;
|
||||
st.print("Unable to find the static T_OBJECT field %s::%s", info->klass_name, info->field_name);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||
}
|
||||
|
||||
info->klass = ik;
|
||||
info->offset = finder.offset();
|
||||
|
@ -1435,28 +1559,84 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
|
|||
void HeapShared::init_subgraph_entry_fields(TRAPS) {
|
||||
assert(HeapShared::can_write(), "must be");
|
||||
_dump_time_subgraph_info_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeKlassSubGraphInfoTable();
|
||||
init_subgraph_entry_fields(closed_archive_subgraph_entry_fields,
|
||||
num_closed_archive_subgraph_entry_fields,
|
||||
CHECK);
|
||||
init_subgraph_entry_fields(open_archive_subgraph_entry_fields,
|
||||
num_open_archive_subgraph_entry_fields,
|
||||
CHECK);
|
||||
init_subgraph_entry_fields(closed_archive_subgraph_entry_fields, CHECK);
|
||||
init_subgraph_entry_fields(open_archive_subgraph_entry_fields, CHECK);
|
||||
if (MetaspaceShared::use_full_module_graph()) {
|
||||
init_subgraph_entry_fields(fmg_open_archive_subgraph_entry_fields,
|
||||
num_fmg_open_archive_subgraph_entry_fields,
|
||||
CHECK);
|
||||
init_subgraph_entry_fields(fmg_open_archive_subgraph_entry_fields, CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void HeapShared::setup_test_class(const char* test_class_name) {
|
||||
ArchivableStaticFieldInfo* p = open_archive_subgraph_entry_fields;
|
||||
int num_slots = sizeof(open_archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
|
||||
assert(p[num_slots - 2].klass_name == NULL, "must have empty slot that's patched below");
|
||||
assert(p[num_slots - 1].klass_name == NULL, "must have empty slot that marks the end of the list");
|
||||
|
||||
if (test_class_name != NULL) {
|
||||
p[num_slots - 2].klass_name = test_class_name;
|
||||
p[num_slots - 2].field_name = ARCHIVE_TEST_FIELD_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
// See if ik is one of the test classes that are pulled in by -XX:ArchiveHeapTestClass
|
||||
// during runtime. This may be called before the module system is initialized so
|
||||
// we cannot rely on InstanceKlass::module(), etc.
|
||||
bool HeapShared::is_a_test_class_in_unnamed_module(Klass* ik) {
|
||||
if (_test_class != NULL) {
|
||||
if (ik == _test_class) {
|
||||
return true;
|
||||
}
|
||||
Array<Klass*>* klasses = _test_class_record->subgraph_object_klasses();
|
||||
if (klasses == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < klasses->length(); i++) {
|
||||
Klass* k = klasses->at(i);
|
||||
if (k == ik) {
|
||||
Symbol* name;
|
||||
if (k->is_instance_klass()) {
|
||||
name = InstanceKlass::cast(k)->name();
|
||||
} else if (k->is_objArray_klass()) {
|
||||
Klass* bk = ObjArrayKlass::cast(k)->bottom_klass();
|
||||
if (!bk->is_instance_klass()) {
|
||||
return false;
|
||||
}
|
||||
name = bk->name();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See KlassSubGraphInfo::check_allowed_klass() - only two types of
|
||||
// classes are allowed:
|
||||
// (A) java.base classes (which must not be in the unnamed module)
|
||||
// (B) test classes which must be in the unnamed package of the unnamed module.
|
||||
// So if we see a '/' character in the class name, it must be in (A);
|
||||
// otherwise it must be in (B).
|
||||
if (name->index_of_at(0, "/", 1) >= 0) {
|
||||
return false; // (A)
|
||||
}
|
||||
|
||||
return true; // (B)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void HeapShared::init_for_dumping(TRAPS) {
|
||||
if (HeapShared::can_write()) {
|
||||
setup_test_class(ArchiveHeapTestClass);
|
||||
_dumped_interned_strings = new (ResourceObj::C_HEAP, mtClass)DumpedInternedStrings();
|
||||
init_subgraph_entry_fields(CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
|
||||
int num, bool is_closed_archive,
|
||||
bool is_closed_archive,
|
||||
bool is_full_module_graph) {
|
||||
_num_total_subgraph_recordings = 0;
|
||||
_num_total_walked_objs = 0;
|
||||
|
@ -1471,7 +1651,7 @@ void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
|
|||
// At runtime, these classes are initialized before X's archived fields
|
||||
// are restored by HeapShared::initialize_from_archived_subgraph().
|
||||
int i;
|
||||
for (i = 0; i < num; ) {
|
||||
for (int i = 0; fields[i].valid(); ) {
|
||||
ArchivableStaticFieldInfo* info = &fields[i];
|
||||
const char* klass_name = info->klass_name;
|
||||
start_recording_subgraph(info->klass, klass_name, is_full_module_graph);
|
||||
|
@ -1480,7 +1660,7 @@ void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
|
|||
// fields[], these will be archived in the same
|
||||
// {start_recording_subgraph ... done_recording_subgraph} pass to
|
||||
// save time.
|
||||
for (; i < num; i++) {
|
||||
for (; fields[i].valid(); i++) {
|
||||
ArchivableStaticFieldInfo* f = &fields[i];
|
||||
if (f->klass_name != klass_name) {
|
||||
break;
|
||||
|
@ -1501,7 +1681,7 @@ void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
|
|||
log_info(cds, heap)(" Recorded %d klasses", _num_total_recorded_klasses);
|
||||
|
||||
#ifndef PRODUCT
|
||||
for (int i = 0; i < num; i++) {
|
||||
for (int i = 0; fields[i].valid(); i++) {
|
||||
ArchivableStaticFieldInfo* f = &fields[i];
|
||||
verify_subgraph_from_static_field(f->klass, f->offset);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue