Skip to content

Commit d309560

Browse files
Thomas Schatzliklam
andcommitted
8253081: G1 fails on stale objects in archived module graph in Open Archive regions
Change the handling of Open Archive areas, instead of assuming that everything in there is live always, a root containing references to all live root objects is provided. Adapt G1 to handle Open Archive regions as any other old region apart from never compacting or evacuating them. Co-authored-by: Ioi Lam <iklam@openjdk.org> Reviewed-by: kbarrett, sjohanss, redestad
1 parent c089214 commit d309560

32 files changed

+584
-230
lines changed

src/hotspot/share/classfile/classLoaderDataShared.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class ArchivedClassLoaderData {
5959
}
6060

6161
void restore(ClassLoaderData* loader_data, bool do_entries, bool do_oops);
62+
void clear_archived_oops();
6263
};
6364

6465
static ArchivedClassLoaderData _archived_boot_loader_data;
@@ -123,6 +124,15 @@ void ArchivedClassLoaderData::restore(ClassLoaderData* loader_data, bool do_entr
123124
}
124125
}
125126

127+
void ArchivedClassLoaderData::clear_archived_oops() {
128+
assert(UseSharedSpaces, "must be");
129+
if (_modules != NULL) {
130+
for (int i = 0; i < _modules->length(); i++) {
131+
_modules->at(i)->clear_archived_oops();
132+
}
133+
}
134+
}
135+
126136
// ------------------------------
127137

128138
static ClassLoaderData* null_class_loader_data() {
@@ -183,6 +193,13 @@ void ClassLoaderDataShared::serialize(SerializeClosure* f) {
183193
}
184194
}
185195

196+
void ClassLoaderDataShared::clear_archived_oops() {
197+
assert(UseSharedSpaces && !MetaspaceShared::use_full_module_graph(), "must be");
198+
_archived_boot_loader_data.clear_archived_oops();
199+
_archived_platform_loader_data.clear_archived_oops();
200+
_archived_system_loader_data.clear_archived_oops();
201+
}
202+
186203
oop ClassLoaderDataShared::restore_archived_oops_for_null_class_loader_data() {
187204
assert(UseSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
188205
_archived_boot_loader_data.restore(null_class_loader_data(), false, true);

src/hotspot/share/classfile/classLoaderDataShared.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class ClassLoaderDataShared : AllStatic {
3939
static void init_archived_tables();
4040
static void init_archived_oops();
4141
static void serialize(SerializeClosure* f);
42+
static void clear_archived_oops();
4243
static oop restore_archived_oops_for_null_class_loader_data();
4344
static void restore_java_platform_loader_from_archive(ClassLoaderData* loader_data);
4445
static void restore_java_system_loader_from_archive(ClassLoaderData* loader_data);

src/hotspot/share/classfile/javaClasses.cpp

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -890,14 +890,14 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) {
890890
}
891891
}
892892

893-
if (k->is_shared() && k->has_raw_archived_mirror()) {
893+
if (k->is_shared() && k->has_archived_mirror_index()) {
894894
if (HeapShared::open_archive_heap_region_mapped()) {
895895
bool present = restore_archived_mirror(k, Handle(), Handle(), Handle(), CHECK);
896896
assert(present, "Missing archived mirror for %s", k->external_name());
897897
return;
898898
} else {
899899
k->clear_java_mirror_handle();
900-
k->clear_has_raw_archived_mirror();
900+
k->clear_archived_mirror_index();
901901
}
902902
}
903903
create_mirror(k, Handle(), Handle(), Handle(), Handle(), CHECK);
@@ -1163,9 +1163,9 @@ oop java_lang_Class::archive_mirror(Klass* k, TRAPS) {
11631163
"HeapShared::is_heap_object_archiving_allowed() must be true");
11641164

11651165
// Mirror is already archived
1166-
if (k->has_raw_archived_mirror()) {
1167-
assert(k->archived_java_mirror_raw() != NULL, "no archived mirror");
1168-
return k->archived_java_mirror_raw();
1166+
if (k->has_archived_mirror_index()) {
1167+
assert(k->archived_java_mirror() != NULL, "no archived mirror");
1168+
return k->archived_java_mirror();
11691169
}
11701170

11711171
// No mirror
@@ -1197,9 +1197,7 @@ oop java_lang_Class::archive_mirror(Klass* k, TRAPS) {
11971197
return NULL;
11981198
}
11991199

1200-
k->set_archived_java_mirror_raw(archived_mirror);
1201-
1202-
k->set_has_raw_archived_mirror();
1200+
k->set_archived_java_mirror(archived_mirror);
12031201

12041202
ResourceMark rm;
12051203
log_trace(cds, heap, mirror)(
@@ -1317,10 +1315,11 @@ bool java_lang_Class::restore_archived_mirror(Klass *k,
13171315
return true;
13181316
}
13191317

1320-
oop m = HeapShared::materialize_archived_object(k->archived_java_mirror_raw_narrow());
1321-
if (m == NULL) {
1322-
return false;
1323-
}
1318+
oop m = k->archived_java_mirror();
1319+
assert(m != NULL, "must have stored non-null archived mirror");
1320+
1321+
// Sanity: clear it now to prevent re-initialization if any of the following fails
1322+
k->clear_archived_mirror_index();
13241323

13251324
// mirror is archived, restore
13261325
log_debug(cds, mirror)("Archived mirror is: " PTR_FORMAT, p2i(m));
@@ -1346,7 +1345,6 @@ bool java_lang_Class::restore_archived_mirror(Klass *k,
13461345
}
13471346

13481347
k->set_java_mirror(mirror);
1349-
k->clear_has_raw_archived_mirror();
13501348

13511349
set_mirror_module_field(k, mirror, module, THREAD);
13521350

src/hotspot/share/classfile/moduleEntry.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ void ModuleEntry::init_archived_oops() {
467467
if (module_obj != NULL) {
468468
oop m = HeapShared::find_archived_heap_object(module_obj);
469469
assert(m != NULL, "sanity");
470-
_archived_module_narrow_oop = CompressedOops::encode(m);
470+
_archived_module_index = HeapShared::append_root(m);
471471
}
472472
assert(shared_protection_domain() == NULL, "never set during -Xshare:dump");
473473
// Clear handles and restore at run time. Handles cannot be archived.
@@ -481,8 +481,8 @@ void ModuleEntry::load_from_archive(ClassLoaderData* loader_data) {
481481
JFR_ONLY(INIT_ID(this);)
482482
}
483483

484-
void ModuleEntry::restore_archive_oops(ClassLoaderData* loader_data) {
485-
Handle module_handle(Thread::current(), HeapShared::materialize_archived_object(_archived_module_narrow_oop));
484+
void ModuleEntry::restore_archived_oops(ClassLoaderData* loader_data) {
485+
Handle module_handle(Thread::current(), HeapShared::get_root(_archived_module_index, /*clear=*/true));
486486
assert(module_handle.not_null(), "huh");
487487
set_module(loader_data->add_handle(module_handle));
488488

@@ -495,6 +495,10 @@ void ModuleEntry::restore_archive_oops(ClassLoaderData* loader_data) {
495495
}
496496
}
497497

498+
void ModuleEntry::clear_archived_oops() {
499+
HeapShared::clear_root(_archived_module_index);
500+
}
501+
498502
static int compare_module_by_name(ModuleEntry* a, ModuleEntry* b) {
499503
assert(a == b || a->name() != b->name(), "no duplicated names");
500504
return a->name()->fast_compare(b->name());
@@ -561,7 +565,7 @@ void ModuleEntryTable::restore_archived_oops(ClassLoaderData* loader_data, Array
561565
assert(UseSharedSpaces, "runtime only");
562566
for (int i = 0; i < archived_modules->length(); i++) {
563567
ModuleEntry* archived_entry = archived_modules->at(i);
564-
archived_entry->restore_archive_oops(loader_data);
568+
archived_entry->restore_archived_oops(loader_data);
565569
}
566570
}
567571
#endif // INCLUDE_CDS_JAVA_HEAP

src/hotspot/share/classfile/moduleEntry.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class ModuleEntry : public HashtableEntry<Symbol*, mtModule> {
7676
bool _must_walk_reads; // walk module's reads list at GC safepoints to purge out dead modules
7777
bool _is_open; // whether the packages in the module are all unqualifiedly exported
7878
bool _is_patched; // whether the module is patched via --patch-module
79-
CDS_JAVA_HEAP_ONLY(narrowOop _archived_module_narrow_oop;)
79+
CDS_JAVA_HEAP_ONLY(int _archived_module_index;)
8080

8181
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
8282
enum {MODULE_READS_SIZE = 101}; // Initial size of list of modules that the module can read.
@@ -201,7 +201,8 @@ class ModuleEntry : public HashtableEntry<Symbol*, mtModule> {
201201
static Array<ModuleEntry*>* write_growable_array(GrowableArray<ModuleEntry*>* array);
202202
static GrowableArray<ModuleEntry*>* restore_growable_array(Array<ModuleEntry*>* archived_array);
203203
void load_from_archive(ClassLoaderData* loader_data);
204-
void restore_archive_oops(ClassLoaderData* loader_data);
204+
void restore_archived_oops(ClassLoaderData* loader_data);
205+
void clear_archived_oops();
205206
#endif
206207
};
207208

src/hotspot/share/classfile/systemDictionary.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1979,8 +1979,12 @@ void SystemDictionary::initialize(TRAPS) {
19791979
oop lock_obj = oopFactory::new_intArray(0, CHECK);
19801980
_system_loader_lock_obj = OopHandle(Universe::vm_global(), lock_obj);
19811981

1982-
// Initialize basic classes
1982+
// Resolve basic classes
19831983
resolve_well_known_classes(CHECK);
1984+
// Resolve classes used by archived heap objects
1985+
if (UseSharedSpaces) {
1986+
HeapShared::resolve_classes(CHECK);
1987+
}
19841988
}
19851989

19861990
// Compact table of directions on the initialization of klasses:

src/hotspot/share/classfile/systemDictionaryShared.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ bool SystemDictionaryShared::_dump_in_progress = false;
7575

7676
class DumpTimeSharedClassInfo: public CHeapObj<mtClass> {
7777
bool _excluded;
78+
bool _is_early_klass;
7879
public:
7980
struct DTLoaderConstraint {
8081
Symbol* _name;
@@ -121,6 +122,7 @@ class DumpTimeSharedClassInfo: public CHeapObj<mtClass> {
121122
_clsfile_size = -1;
122123
_clsfile_crc32 = -1;
123124
_excluded = false;
125+
_is_early_klass = JvmtiExport::is_early_phase();
124126
_verifier_constraints = NULL;
125127
_verifier_constraint_flags = NULL;
126128
_loader_constraints = NULL;
@@ -177,6 +179,11 @@ class DumpTimeSharedClassInfo: public CHeapObj<mtClass> {
177179
return _excluded || _failed_verification || _klass == NULL;
178180
}
179181

182+
// Was this class loaded while JvmtiExport::is_early_phase()==true
183+
bool is_early_klass() {
184+
return _is_early_klass;
185+
}
186+
180187
void set_failed_verification() {
181188
_failed_verification = true;
182189
}
@@ -1325,6 +1332,11 @@ bool SystemDictionaryShared::is_hidden_lambda_proxy(InstanceKlass* ik) {
13251332
}
13261333
}
13271334

1335+
bool SystemDictionaryShared::is_early_klass(InstanceKlass* ik) {
1336+
DumpTimeSharedClassInfo* info = _dumptime_table->get(ik);
1337+
return (info != NULL) ? info->is_early_klass() : false;
1338+
}
1339+
13281340
void SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) {
13291341
ResourceMark rm;
13301342
log_warning(cds)("Skipping %s: %s", k->name()->as_C_string(), reason);
@@ -2302,8 +2314,8 @@ bool SystemDictionaryShared::empty_dumptime_table() {
23022314
class ArchivedMirrorPatcher {
23032315
protected:
23042316
static void update(Klass* k) {
2305-
if (k->has_raw_archived_mirror()) {
2306-
oop m = HeapShared::materialize_archived_object(k->archived_java_mirror_raw_narrow());
2317+
if (k->has_archived_mirror_index()) {
2318+
oop m = k->archived_java_mirror();
23072319
if (m != NULL) {
23082320
java_lang_Class::update_archived_mirror_native_pointers(m);
23092321
}

src/hotspot/share/classfile/systemDictionaryShared.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ class SystemDictionaryShared: public SystemDictionary {
229229

230230
public:
231231
static bool is_hidden_lambda_proxy(InstanceKlass* ik);
232+
static bool is_early_klass(InstanceKlass* k); // Was k loaded while JvmtiExport::is_early_phase()==true
232233
static Handle init_security_info(Handle class_loader, InstanceKlass* ik, PackageEntry* pkg_entry, TRAPS);
233234
static InstanceKlass* find_builtin_class(Symbol* class_name);
234235

src/hotspot/share/gc/g1/g1CollectedHeap.cpp

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -804,17 +804,6 @@ void G1CollectedHeap::dealloc_archive_regions(MemRegion* ranges, size_t count) {
804804
decrease_used(size_used);
805805
}
806806

807-
oop G1CollectedHeap::materialize_archived_object(oop obj) {
808-
assert(is_archived_object(obj), "not an archived obj");
809-
810-
// Loading an archived object makes it strongly reachable. If it is
811-
// loaded during concurrent marking, it must be enqueued to the SATB
812-
// queue, shading the previously white object gray.
813-
G1BarrierSet::enqueue(obj);
814-
815-
return obj;
816-
}
817-
818807
HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
819808
ResourceMark rm; // For retrieving the thread names in log messages.
820809

@@ -4021,11 +4010,13 @@ void G1CollectedHeap::free_humongous_region(HeapRegion* hr,
40214010
free_region(hr, free_list);
40224011
}
40234012

4024-
void G1CollectedHeap::remove_from_old_sets(const uint old_regions_removed,
4025-
const uint humongous_regions_removed) {
4026-
if (old_regions_removed > 0 || humongous_regions_removed > 0) {
4013+
void G1CollectedHeap::remove_from_old_gen_sets(const uint old_regions_removed,
4014+
const uint archive_regions_removed,
4015+
const uint humongous_regions_removed) {
4016+
if (old_regions_removed > 0 || archive_regions_removed > 0 || humongous_regions_removed > 0) {
40274017
MutexLocker x(OldSets_lock, Mutex::_no_safepoint_check_flag);
40284018
_old_set.bulk_remove(old_regions_removed);
4019+
_archive_set.bulk_remove(archive_regions_removed);
40294020
_humongous_set.bulk_remove(humongous_regions_removed);
40304021
}
40314022

@@ -4453,7 +4444,7 @@ void G1CollectedHeap::eagerly_reclaim_humongous_regions() {
44534444
G1FreeHumongousRegionClosure cl(&local_cleanup_list);
44544445
heap_region_iterate(&cl);
44554446

4456-
remove_from_old_sets(0, cl.humongous_regions_reclaimed());
4447+
remove_from_old_gen_sets(0, 0, cl.humongous_regions_reclaimed());
44574448

44584449
G1HRPrinter* hrp = hr_printer();
44594450
if (hrp->is_active()) {
@@ -4528,22 +4519,23 @@ bool G1CollectedHeap::check_young_list_empty() {
45284519

45294520
#endif // ASSERT
45304521

4531-
// Remove the given HeapRegion from the appropriate region set.
4522+
// Remove the given HeapRegion from the appropriate region set.
45324523
void G1CollectedHeap::prepare_region_for_full_compaction(HeapRegion* hr) {
4533-
if (hr->is_old()) {
4524+
if (hr->is_archive()) {
4525+
_archive_set.remove(hr);
4526+
} else if (hr->is_humongous()) {
4527+
_humongous_set.remove(hr);
4528+
} else if (hr->is_old()) {
45344529
_old_set.remove(hr);
45354530
} else if (hr->is_young()) {
4536-
// Note that emptying the _young_list is postponed and instead done as
4537-
// the first step when rebuilding the regions sets again. The reason for
4538-
// this is that during a full GC string deduplication needs to know if
4531+
// Note that emptying the eden and survivor lists is postponed and instead
4532+
// done as the first step when rebuilding the regions sets again. The reason
4533+
// for this is that during a full GC string deduplication needs to know if
45394534
// a collected region was young or old when the full GC was initiated.
45404535
hr->uninstall_surv_rate_group();
45414536
} else {
45424537
// We ignore free regions, we'll empty the free list afterwards.
4543-
// We ignore humongous and archive regions, we're not tearing down these
4544-
// sets.
4545-
assert(hr->is_archive() || hr->is_free() || hr->is_humongous(),
4546-
"it cannot be another type");
4538+
assert(hr->is_free(), "it cannot be another type");
45474539
}
45484540
}
45494541

@@ -4567,19 +4559,26 @@ class RebuildRegionSetsClosure : public HeapRegionClosure {
45674559
bool _free_list_only;
45684560

45694561
HeapRegionSet* _old_set;
4562+
HeapRegionSet* _archive_set;
4563+
HeapRegionSet* _humongous_set;
4564+
45704565
HeapRegionManager* _hrm;
45714566

45724567
size_t _total_used;
45734568

45744569
public:
45754570
RebuildRegionSetsClosure(bool free_list_only,
45764571
HeapRegionSet* old_set,
4572+
HeapRegionSet* archive_set,
4573+
HeapRegionSet* humongous_set,
45774574
HeapRegionManager* hrm) :
4578-
_free_list_only(free_list_only),
4579-
_old_set(old_set), _hrm(hrm), _total_used(0) {
4575+
_free_list_only(free_list_only), _old_set(old_set), _archive_set(archive_set),
4576+
_humongous_set(humongous_set), _hrm(hrm), _total_used(0) {
45804577
assert(_hrm->num_free_regions() == 0, "pre-condition");
45814578
if (!free_list_only) {
45824579
assert(_old_set->is_empty(), "pre-condition");
4580+
assert(_archive_set->is_empty(), "pre-condition");
4581+
assert(_humongous_set->is_empty(), "pre-condition");
45834582
}
45844583
}
45854584

@@ -4592,11 +4591,14 @@ class RebuildRegionSetsClosure : public HeapRegionClosure {
45924591
} else if (!_free_list_only) {
45934592
assert(r->rem_set()->is_empty(), "At this point remembered sets must have been cleared.");
45944593

4595-
if (r->is_archive() || r->is_humongous()) {
4596-
// We ignore archive and humongous regions. We left these sets unchanged.
4594+
if (r->is_humongous()) {
4595+
_humongous_set->add(r);
4596+
} else if (r->is_archive()) {
4597+
_archive_set->add(r);
45974598
} else {
45984599
assert(r->is_young() || r->is_free() || r->is_old(), "invariant");
4599-
// We now move all (non-humongous, non-old, non-archive) regions to old gen, and register them as such.
4600+
// We now move all (non-humongous, non-old, non-archive) regions to old gen,
4601+
// and register them as such.
46004602
r->move_to_old();
46014603
_old_set->add(r);
46024604
}
@@ -4619,7 +4621,9 @@ void G1CollectedHeap::rebuild_region_sets(bool free_list_only) {
46194621
_survivor.clear();
46204622
}
46214623

4622-
RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_hrm);
4624+
RebuildRegionSetsClosure cl(free_list_only,
4625+
&_old_set, &_archive_set, &_humongous_set,
4626+
&_hrm);
46234627
heap_region_iterate(&cl);
46244628

46254629
if (!free_list_only) {

0 commit comments

Comments
 (0)