8377703: Assert that all AOT heap objects have valid classes

Reviewed-by: kvn, eosterlund
This commit is contained in:
Ioi Lam 2026-03-30 23:14:13 +00:00
parent 0c4156d599
commit 6350c3641e
2 changed files with 62 additions and 1 deletions

View File

@ -36,6 +36,8 @@
#include "runtime/semaphore.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashTable.hpp"
#include "utilities/macros.hpp"
class BootstrapInfo;
@ -44,7 +46,6 @@ class ReservedSpace;
class VirtualSpace;
template<class E> class Array;
template<class E> class GrowableArray;
// ArchivePtrMarker is used to mark the location of pointers embedded in a CDS archive. E.g., when an
// InstanceKlass k is dumped, we mark the location of the k->_name pointer by effectively calling
@ -401,4 +402,39 @@ public:
void run_task(ArchiveWorkerTask* task);
};
// A utility class for writing an array of unique items into the
// AOT cache. For determinism, the order of the array is the same
// as calls to add(). I.e., if items are added in the order
// of A, B, A, C, B, D, then the array will be written as {A, B, C, D}
template <typename T, unsigned SIZE = 15889>
class ArchivableTable : public AnyObj {
using Table = HashTable<T, bool, SIZE, AnyObj::C_HEAP, mtClassShared>;
Table* _seen_items;
GrowableArray<T>* _ordered_array;
public:
ArchivableTable() {
_seen_items = new (mtClassShared)Table();
_ordered_array = new (mtClassShared)GrowableArray<T>(128, mtClassShared);
}
~ArchivableTable() {
delete _seen_items;
delete _ordered_array;
}
void add(T t) {
bool created;
_seen_items->put_if_absent(t, &created);
if (created) {
_ordered_array->append(t);
}
}
Array<T>* write_ordered_array() {
return ArchiveUtils::archive_array(_ordered_array);
}
};
using ArchivableKlassTable = ArchivableTable<Klass*>;
#endif // SHARE_CDS_ARCHIVEUTILS_HPP

View File

@ -112,6 +112,11 @@ static Klass* _test_class = nullptr;
static const ArchivedKlassSubGraphInfoRecord* _test_class_record = nullptr;
#endif
#ifdef ASSERT
// All classes that have at least one instance in the cached heap.
static ArchivableKlassTable* _dumptime_classes_with_cached_oops = nullptr;
static Array<Klass*>* _runtime_classes_with_cached_oops = nullptr;
#endif
//
// If you add new entries to the following tables, you should know what you're doing!
@ -391,6 +396,21 @@ void HeapShared::initialize_streaming() {
}
void HeapShared::enable_gc() {
#ifdef ASSERT
// At this point, a GC may start and will be able to see some or all
// of the cached oops. The class of each oop seen by the GC must have
// already been loaded. One function with such a requirement is
// ClaimMetadataVisitingOopIterateClosure::do_klass().
if (is_archived_heap_in_use()) {
Array<Klass*>* klasses = _runtime_classes_with_cached_oops;
for (int i = 0; i < klasses->length(); i++) {
assert(klasses->at(i)->class_loader_data() != nullptr,
"class of cached oop must have been loaded");
}
}
#endif
if (AOTStreamedHeapLoader::is_in_use()) {
AOTStreamedHeapLoader::enable_gc();
}
@ -567,6 +587,7 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra
AOTArtifactFinder::add_cached_class(obj->klass());
AOTOopChecker::check(obj); // Make sure contents of this oop are safe.
count_allocation(obj->size());
DEBUG_ONLY(_dumptime_classes_with_cached_oops->add(obj->klass()));
if (HeapShared::is_writing_streaming_mode()) {
AOTStreamedHeapWriter::add_source_obj(obj);
@ -686,6 +707,7 @@ void HeapShared::init_dumping() {
_scratch_objects_table = new (mtClass)MetaspaceObjToOopHandleTable();
_pending_roots = new GrowableArrayCHeap<oop, mtClassShared>(500);
_pending_roots->append(nullptr); // root index 0 represents a null oop
DEBUG_ONLY(_dumptime_classes_with_cached_oops = new (mtClassShared)ArchivableKlassTable());
}
void HeapShared::init_scratch_objects_for_basic_type_mirrors(TRAPS) {
@ -967,6 +989,8 @@ void HeapShared::write_heap(AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeap
ArchiveBuilder::OtherROAllocMark mark;
write_subgraph_info_table();
DEBUG_ONLY(_runtime_classes_with_cached_oops = _dumptime_classes_with_cached_oops->write_ordered_array());
delete _pending_roots;
_pending_roots = nullptr;
@ -1278,6 +1302,7 @@ void HeapShared::serialize_tables(SerializeClosure* soc) {
_run_time_subgraph_info_table.serialize_header(soc);
soc->do_ptr(&_run_time_special_subgraph);
DEBUG_ONLY(soc->do_ptr(&_runtime_classes_with_cached_oops));
}
static void verify_the_heap(Klass* k, const char* which) {