mirror of
https://github.com/openjdk/jdk.git
synced 2026-06-01 00:02:37 +00:00
8377703: Assert that all AOT heap objects have valid classes
Reviewed-by: kvn, eosterlund
This commit is contained in:
parent
0c4156d599
commit
6350c3641e
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user