8309140: ResourceHashtable failed "assert(~(_allocation_t[0] | allocation_mask) == (uintptr_t)this) failed: lost resource object"

Reviewed-by: coleenp, matsaave, dholmes
This commit is contained in:
Justin Gu 2023-06-28 17:10:16 +00:00 committed by Coleen Phillimore
parent 9f98136c3a
commit b6c789faad
11 changed files with 98 additions and 58 deletions

View File

@ -109,7 +109,8 @@ class ConstraintSet { // copied into hashtable as
};
ResourceHashtable<SymbolHandle, ConstraintSet, 107, AnyObj::C_HEAP, mtClass, SymbolHandle::compute_hash> _loader_constraint_table;
using InternalLoaderConstraintTable = ResourceHashtable<SymbolHandle, ConstraintSet, 107, AnyObj::C_HEAP, mtClass, SymbolHandle::compute_hash>;
static InternalLoaderConstraintTable* _loader_constraint_table;
void LoaderConstraint::extend_loader_constraint(Symbol* class_name,
ClassLoaderData* loader,
@ -134,11 +135,15 @@ void LoaderConstraint::extend_loader_constraint(Symbol* class_name,
// SystemDictionary lock held. This is true even for readers as
// entries in the table could be being dynamically resized.
void LoaderConstraintTable::initialize() {
_loader_constraint_table = new (mtClass) InternalLoaderConstraintTable();
}
LoaderConstraint* LoaderConstraintTable::find_loader_constraint(
Symbol* name, ClassLoaderData* loader_data) {
assert_lock_strong(SystemDictionary_lock);
ConstraintSet* set = _loader_constraint_table.get(name);
ConstraintSet* set = _loader_constraint_table->get(name);
if (set == nullptr) {
return nullptr;
}
@ -167,7 +172,7 @@ void LoaderConstraintTable::add_loader_constraint(Symbol* name, InstanceKlass* k
// a parameter name to a method call. We impose this constraint that the
// class that is eventually loaded must match between these two loaders.
bool created;
ConstraintSet* set = _loader_constraint_table.put_if_absent(name, &created);
ConstraintSet* set = _loader_constraint_table->put_if_absent(name, &created);
if (created) {
set->initialize(constraint);
} else {
@ -249,7 +254,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
assert_locked_or_safepoint(SystemDictionary_lock);
// Remove unloaded entries from constraint table
PurgeUnloadedConstraints purge;
_loader_constraint_table.unlink(&purge);
_loader_constraint_table->unlink(&purge);
}
void log_ldr_constraint_msg(Symbol* class_name, const char* reason,
@ -441,7 +446,7 @@ void LoaderConstraintTable::merge_loader_constraints(Symbol* class_name,
}
// Remove src from set
ConstraintSet* set = _loader_constraint_table.get(class_name);
ConstraintSet* set = _loader_constraint_table->get(class_name);
set->remove_constraint(src);
}
@ -480,7 +485,7 @@ void LoaderConstraintTable::verify() {
}
};
assert_locked_or_safepoint(SystemDictionary_lock);
_loader_constraint_table.iterate_all(check);
_loader_constraint_table->iterate_all(check);
}
void LoaderConstraintTable::print_table_statistics(outputStream* st) {
@ -494,7 +499,7 @@ void LoaderConstraintTable::print_table_statistics(outputStream* st) {
}
return sum;
};
TableStatistics ts = _loader_constraint_table.statistics_calculate(size);
TableStatistics ts = _loader_constraint_table->statistics_calculate(size);
ts.print(st, "LoaderConstraintTable");
}
@ -516,8 +521,8 @@ void LoaderConstraintTable::print_on(outputStream* st) {
assert_locked_or_safepoint(SystemDictionary_lock);
ResourceMark rm;
st->print_cr("Java loader constraints (table_size=%d, constraints=%d)",
_loader_constraint_table.table_size(), _loader_constraint_table.number_of_entries());
_loader_constraint_table.iterate_all(printer);
_loader_constraint_table->table_size(), _loader_constraint_table->number_of_entries());
_loader_constraint_table->iterate_all(printer);
}
void LoaderConstraintTable::print() { print_on(tty); }

View File

@ -43,7 +43,7 @@ private:
static void merge_loader_constraints(Symbol* class_name, LoaderConstraint* pp1,
LoaderConstraint* pp2, InstanceKlass* klass);
public:
static void initialize();
// Check class loader constraints
static bool add_entry(Symbol* name, InstanceKlass* klass1, ClassLoaderData* loader1,
InstanceKlass* klass2, ClassLoaderData* loader2);

View File

@ -50,8 +50,9 @@ class PlaceholderKey {
};
const int _placeholder_table_size = 503; // Does this really have to be prime?
ResourceHashtable<PlaceholderKey, PlaceholderEntry, _placeholder_table_size, AnyObj::C_HEAP, mtClass,
PlaceholderKey::hash, PlaceholderKey::equals> _placeholders;
using InternalPlaceholderTable = ResourceHashtable<PlaceholderKey, PlaceholderEntry, _placeholder_table_size, AnyObj::C_HEAP, mtClass,
PlaceholderKey::hash, PlaceholderKey::equals>;
static InternalPlaceholderTable* _placeholders;
// SeenThread objects represent list of threads that are
// currently performing a load action on a class.
@ -207,7 +208,7 @@ PlaceholderEntry* add_entry(Symbol* class_name, ClassLoaderData* loader_data,
entry.set_supername(supername);
PlaceholderKey key(class_name, loader_data);
bool created;
PlaceholderEntry* table_copy = _placeholders.put_if_absent(key, entry, &created);
PlaceholderEntry* table_copy = _placeholders->put_if_absent(key, entry, &created);
assert(created, "better be absent");
return table_copy;
}
@ -217,14 +218,14 @@ void remove_entry(Symbol* class_name, ClassLoaderData* loader_data) {
assert_locked_or_safepoint(SystemDictionary_lock);
PlaceholderKey key(class_name, loader_data);
_placeholders.remove(key);
_placeholders->remove(key);
}
PlaceholderEntry* PlaceholderTable::get_entry(Symbol* class_name, ClassLoaderData* loader_data) {
assert_locked_or_safepoint(SystemDictionary_lock);
PlaceholderKey key(class_name, loader_data);
return _placeholders.get(key);
return _placeholders->get(key);
}
static const char* action_to_string(PlaceholderTable::classloadAction action) {
@ -271,6 +272,10 @@ PlaceholderEntry* PlaceholderTable::find_and_add(Symbol* name,
return probe;
}
void PlaceholderTable::initialize(){
_placeholders = new (mtClass) InternalPlaceholderTable();
}
// placeholder is used to track class loading internal states
// superthreadQ tracks class circularity, while loading superclass/superinterface
@ -340,8 +345,8 @@ void PlaceholderTable::print_on(outputStream* st) {
return true;
};
st->print_cr("Placeholder table (table_size=%d, placeholders=%d)",
_placeholders.table_size(), _placeholders.number_of_entries());
_placeholders.iterate(printer);
_placeholders->table_size(), _placeholders->number_of_entries());
_placeholders->iterate(printer);
}
void PlaceholderTable::print() { return print_on(tty); }

View File

@ -52,7 +52,7 @@ class PlaceholderTable : public AllStatic {
LOAD_SUPER = 2, // loading superclass for this class
DEFINE_CLASS = 3 // find_or_define class
};
static void initialize();
static PlaceholderEntry* get_entry(Symbol* name, ClassLoaderData* loader_data);
// find_and_add returns probe pointer - old or new

View File

@ -51,13 +51,17 @@ bool ProtectionDomainCacheTable::equals(const WeakHandle& protection_domain1, co
// WeakHandle is both the key and the value. We need it as the key to compare the oops that each point to
// for equality. We need it as the value to return the one that already exists to link in the DictionaryEntry.
ResourceHashtable<WeakHandle, WeakHandle, 1009, AnyObj::C_HEAP, mtClass,
using InternalProtectionDomainCacheTable = ResourceHashtable<WeakHandle, WeakHandle, 1009, AnyObj::C_HEAP, mtClass,
ProtectionDomainCacheTable::compute_hash,
ProtectionDomainCacheTable::equals> _pd_cache_table;
ProtectionDomainCacheTable::equals>;
static InternalProtectionDomainCacheTable* _pd_cache_table;
bool ProtectionDomainCacheTable::_dead_entries = false;
int ProtectionDomainCacheTable::_total_oops_removed = 0;
void ProtectionDomainCacheTable::initialize(){
_pd_cache_table = new (mtClass) InternalProtectionDomainCacheTable();
}
void ProtectionDomainCacheTable::trigger_cleanup() {
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
_dead_entries = true;
@ -159,7 +163,7 @@ void ProtectionDomainCacheTable::unlink() {
};
Deleter deleter;
_pd_cache_table.unlink(&deleter);
_pd_cache_table->unlink(&deleter);
_total_oops_removed += deleter._oops_removed;
_dead_entries = false;
@ -171,15 +175,15 @@ void ProtectionDomainCacheTable::print_on(outputStream* st) {
st->print_cr(" protection_domain: " PTR_FORMAT, p2i(value.peek()));
};
st->print_cr("Protection domain cache table (table_size=%d, protection domains=%d)",
_pd_cache_table.table_size(), _pd_cache_table.number_of_entries());
_pd_cache_table.iterate_all(printer);
_pd_cache_table->table_size(), _pd_cache_table->number_of_entries());
_pd_cache_table->iterate_all(printer);
}
void ProtectionDomainCacheTable::verify() {
auto verifier = [&] (WeakHandle& key, WeakHandle& value) {
guarantee(value.peek() == nullptr || oopDesc::is_oop(value.peek()), "must be an oop");
};
_pd_cache_table.iterate_all(verifier);
_pd_cache_table->iterate_all(verifier);
}
// The object_no_keepalive() call peeks at the phantomly reachable oop without
@ -192,7 +196,7 @@ WeakHandle ProtectionDomainCacheTable::add_if_absent(Handle protection_domain) {
assert_locked_or_safepoint(SystemDictionary_lock);
WeakHandle w(Universe::vm_weak(), protection_domain);
bool created;
WeakHandle* wk = _pd_cache_table.put_if_absent(w, w, &created);
WeakHandle* wk = _pd_cache_table->put_if_absent(w, w, &created);
if (!created) {
// delete the one created since we already had it in the table
w.release(Universe::vm_weak());
@ -215,10 +219,10 @@ void ProtectionDomainCacheTable::print_table_statistics(outputStream* st) {
// The only storage is in OopStorage for an oop
return sizeof(oop);
};
TableStatistics ts = _pd_cache_table.statistics_calculate(size);
TableStatistics ts = _pd_cache_table->statistics_calculate(size);
ts.print(st, "ProtectionDomainCacheTable");
}
int ProtectionDomainCacheTable::number_of_entries() {
return _pd_cache_table.number_of_entries();
return _pd_cache_table->number_of_entries();
}

View File

@ -39,6 +39,7 @@ class ProtectionDomainCacheTable : public AllStatic {
static int _total_oops_removed;
public:
static void initialize();
static unsigned int compute_hash(const WeakHandle& protection_domain);
static bool equals(const WeakHandle& protection_domain1, const WeakHandle& protection_domain2);

View File

@ -54,9 +54,15 @@ class ResolutionErrorKey {
}
};
ResourceHashtable<ResolutionErrorKey, ResolutionErrorEntry*, 107, AnyObj::C_HEAP, mtClass,
using InternalResolutionErrorTable = ResourceHashtable<ResolutionErrorKey, ResolutionErrorEntry*, 107, AnyObj::C_HEAP, mtClass,
ResolutionErrorKey::hash,
ResolutionErrorKey::equals> _resolution_error_table;
ResolutionErrorKey::equals>;
static InternalResolutionErrorTable* _resolution_error_table;
void ResolutionErrorTable::initialize() {
_resolution_error_table = new (mtClass) InternalResolutionErrorTable();
}
// create new error entry
void ResolutionErrorTable::add_entry(const constantPoolHandle& pool, int cp_index,
@ -68,7 +74,7 @@ void ResolutionErrorTable::add_entry(const constantPoolHandle& pool, int cp_inde
ResolutionErrorKey key(pool(), cp_index);
ResolutionErrorEntry *entry = new ResolutionErrorEntry(error, message, cause, cause_msg);
_resolution_error_table.put(key, entry);
_resolution_error_table->put(key, entry);
}
// create new nest host error entry
@ -80,14 +86,14 @@ void ResolutionErrorTable::add_entry(const constantPoolHandle& pool, int cp_inde
ResolutionErrorKey key(pool(), cp_index);
ResolutionErrorEntry *entry = new ResolutionErrorEntry(message);
_resolution_error_table.put(key, entry);
_resolution_error_table->put(key, entry);
}
// find entry in the table
ResolutionErrorEntry* ResolutionErrorTable::find_entry(const constantPoolHandle& pool, int cp_index) {
assert_locked_or_safepoint(SystemDictionary_lock);
ResolutionErrorKey key(pool(), cp_index);
ResolutionErrorEntry** entry = _resolution_error_table.get(key);
ResolutionErrorEntry** entry = _resolution_error_table->get(key);
return entry == nullptr ? nullptr : *entry;
}
@ -139,7 +145,7 @@ void ResolutionErrorTable::delete_entry(ConstantPool* c) {
assert_locked_or_safepoint(SystemDictionary_lock);
ResolutionErrorDeleteIterate deleteIterator(c);
_resolution_error_table.unlink(&deleteIterator);
_resolution_error_table->unlink(&deleteIterator);
}
class ResolutionIteratePurgeErrors : StackObj {
@ -160,5 +166,5 @@ void ResolutionErrorTable::purge_resolution_errors() {
assert_locked_or_safepoint(SystemDictionary_lock);
ResolutionIteratePurgeErrors purgeErrorsIterator;
_resolution_error_table.unlink(&purgeErrorsIterator);
_resolution_error_table->unlink(&purgeErrorsIterator);
}

View File

@ -35,6 +35,7 @@ class ResolutionErrorEntry;
class ResolutionErrorTable : AllStatic {
public:
static void initialize();
static void add_entry(const constantPoolHandle& pool, int which, Symbol* error, Symbol* message,
Symbol* cause, Symbol* cause_msg);

View File

@ -113,9 +113,11 @@ class InvokeMethodKey : public StackObj {
};
ResourceHashtable<InvokeMethodKey, Method*, 139, AnyObj::C_HEAP, mtClass,
InvokeMethodKey::compute_hash, InvokeMethodKey::key_comparison> _invoke_method_intrinsic_table;
ResourceHashtable<SymbolHandle, OopHandle, 139, AnyObj::C_HEAP, mtClass, SymbolHandle::compute_hash> _invoke_method_type_table;
using InvokeMethodIntrinsicTable = ResourceHashtable<InvokeMethodKey, Method*, 139, AnyObj::C_HEAP, mtClass,
InvokeMethodKey::compute_hash, InvokeMethodKey::key_comparison>;
static InvokeMethodIntrinsicTable* _invoke_method_intrinsic_table;
using InvokeMethodTypeTable = ResourceHashtable<SymbolHandle, OopHandle, 139, AnyObj::C_HEAP, mtClass, SymbolHandle::compute_hash>;
static InvokeMethodTypeTable* _invoke_method_type_table;
OopHandle SystemDictionary::_java_system_loader;
OopHandle SystemDictionary::_java_platform_loader;
@ -1592,7 +1594,7 @@ void SystemDictionary::methods_do(void f(Method*)) {
{
MutexLocker ml(InvokeMethodIntrinsicTable_lock);
_invoke_method_intrinsic_table.iterate_all(doit);
_invoke_method_intrinsic_table->iterate_all(doit);
}
}
@ -1601,10 +1603,15 @@ void SystemDictionary::methods_do(void f(Method*)) {
// Initialization
void SystemDictionary::initialize(TRAPS) {
_invoke_method_intrinsic_table = new (mtClass) InvokeMethodIntrinsicTable();
_invoke_method_type_table = new (mtClass) InvokeMethodTypeTable();
ResolutionErrorTable::initialize();
LoaderConstraintTable::initialize();
PlaceholderTable::initialize();
ProtectionDomainCacheTable::initialize();
#if INCLUDE_CDS
SystemDictionaryShared::initialize();
#endif
// Resolve basic classes
vmClasses::resolve_all(CHECK);
// Resolve classes used by archived heap objects
@ -1954,7 +1961,7 @@ Method* SystemDictionary::find_method_handle_intrinsic(vmIntrinsicID iid,
MonitorLocker ml(THREAD, InvokeMethodIntrinsicTable_lock);
while (true) {
bool created;
met = _invoke_method_intrinsic_table.put_if_absent(key, &created);
met = _invoke_method_intrinsic_table->put_if_absent(key, &created);
assert(met != nullptr, "either created or found");
if (*met != nullptr) {
return *met;
@ -1985,7 +1992,7 @@ Method* SystemDictionary::find_method_handle_intrinsic(vmIntrinsicID iid,
MonitorLocker ml(THREAD, InvokeMethodIntrinsicTable_lock);
if (throw_error) {
// Remove the entry and let another thread try, or get the same exception.
bool removed = _invoke_method_intrinsic_table.remove(key);
bool removed = _invoke_method_intrinsic_table->remove(key);
assert(removed, "must be the owner");
ml.notify_all();
} else {
@ -2148,7 +2155,7 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature,
OopHandle* o;
{
MutexLocker ml(THREAD, InvokeMethodTypeTable_lock);
o = _invoke_method_type_table.get(signature);
o = _invoke_method_type_table->get(signature);
}
if (o != nullptr) {
@ -2219,11 +2226,11 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature,
MutexLocker ml(THREAD, InvokeMethodTypeTable_lock);
bool created = false;
assert(method_type != nullptr, "unexpected null");
OopHandle* h = _invoke_method_type_table.get(signature);
OopHandle* h = _invoke_method_type_table->get(signature);
if (h == nullptr) {
signature->make_permanent(); // The signature is never unloaded.
OopHandle elem = OopHandle(Universe::vm_global(), method_type());
bool created = _invoke_method_type_table.put(signature, elem);
bool created = _invoke_method_type_table->put(signature, elem);
assert(created, "better be created");
}
}

View File

@ -978,8 +978,8 @@ void InstanceKlass::initialize_super_interfaces(TRAPS) {
}
}
ResourceHashtable<const InstanceKlass*, OopHandle, 107, AnyObj::C_HEAP, mtClass>
_initialization_error_table;
using InitializationErrorTable = ResourceHashtable<const InstanceKlass*, OopHandle, 107, AnyObj::C_HEAP, mtClass>;
static InitializationErrorTable* _initialization_error_table;
void InstanceKlass::add_initialization_error(JavaThread* current, Handle exception) {
// Create the same exception with a message indicating the thread name,
@ -1006,14 +1006,20 @@ void InstanceKlass::add_initialization_error(JavaThread* current, Handle excepti
MutexLocker ml(current, ClassInitError_lock);
OopHandle elem = OopHandle(Universe::vm_global(), init_error());
bool created;
_initialization_error_table.put_if_absent(this, elem, &created);
if (_initialization_error_table == nullptr) {
_initialization_error_table = new (mtClass) InitializationErrorTable();
}
_initialization_error_table->put_if_absent(this, elem, &created);
assert(created, "Initialization is single threaded");
log_trace(class, init)("Initialization error added for class %s", external_name());
}
oop InstanceKlass::get_initialization_error(JavaThread* current) {
MutexLocker ml(current, ClassInitError_lock);
OopHandle* h = _initialization_error_table.get(this);
if (_initialization_error_table == nullptr) {
return nullptr;
}
OopHandle* h = _initialization_error_table->get(this);
return (h != nullptr) ? h->resolve() : nullptr;
}
@ -1032,7 +1038,9 @@ void InstanceKlass::clean_initialization_error_table() {
assert_locked_or_safepoint(ClassInitError_lock);
InitErrorTableCleaner cleaner;
_initialization_error_table.unlink(&cleaner);
if (_initialization_error_table != nullptr) {
_initialization_error_table->unlink(&cleaner);
}
}
void InstanceKlass::initialize_impl(TRAPS) {
@ -4352,3 +4360,4 @@ void ClassHierarchyIterator::next() {
_current = _current->next_sibling();
return; // visit next sibling subclass
}

View File

@ -2627,17 +2627,18 @@ class AdapterFingerPrint : public CHeapObj<mtCode> {
};
// A hashtable mapping from AdapterFingerPrints to AdapterHandlerEntries
ResourceHashtable<AdapterFingerPrint*, AdapterHandlerEntry*, 293,
using AdapterHandlerTable = ResourceHashtable<AdapterFingerPrint*, AdapterHandlerEntry*, 293,
AnyObj::C_HEAP, mtCode,
AdapterFingerPrint::compute_hash,
AdapterFingerPrint::equals> _adapter_handler_table;
AdapterFingerPrint::equals>;
static AdapterHandlerTable* _adapter_handler_table;
// Find a entry with the same fingerprint if it exists
static AdapterHandlerEntry* lookup(int total_args_passed, BasicType* sig_bt) {
NOT_PRODUCT(_lookups++);
assert_lock_strong(AdapterHandlerLibrary_lock);
AdapterFingerPrint fp(total_args_passed, sig_bt);
AdapterHandlerEntry** entry = _adapter_handler_table.get(&fp);
AdapterHandlerEntry** entry = _adapter_handler_table->get(&fp);
if (entry != nullptr) {
#ifndef PRODUCT
if (fp.is_compact()) _compact++;
@ -2653,10 +2654,10 @@ static void print_table_statistics() {
auto size = [&] (AdapterFingerPrint* key, AdapterHandlerEntry* a) {
return sizeof(*key) + sizeof(*a);
};
TableStatistics ts = _adapter_handler_table.statistics_calculate(size);
TableStatistics ts = _adapter_handler_table->statistics_calculate(size);
ts.print(tty, "AdapterHandlerTable");
tty->print_cr("AdapterHandlerTable (table_size=%d, entries=%d)",
_adapter_handler_table.table_size(), _adapter_handler_table.number_of_entries());
_adapter_handler_table->table_size(), _adapter_handler_table->number_of_entries());
tty->print_cr("AdapterHandlerTable: lookups %d equals %d hits %d compact %d",
_lookups, _equals, _hits, _compact);
}
@ -2704,6 +2705,7 @@ void AdapterHandlerLibrary::initialize() {
AdapterBlob* obj_int_arg_blob = nullptr;
AdapterBlob* obj_obj_arg_blob = nullptr;
{
_adapter_handler_table = new (mtCode) AdapterHandlerTable();
MutexLocker mu(AdapterHandlerLibrary_lock);
// Create a special handler for abstract methods. Abstract methods
@ -2945,7 +2947,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::create_adapter(AdapterBlob*& new_ada
ttyLocker ttyl;
entry->print_adapter_on(tty);
tty->print_cr("i2c argument handler #%d for: %s %s (%d bytes generated)",
_adapter_handler_table.number_of_entries(), fingerprint->as_basic_args_string(),
_adapter_handler_table->number_of_entries(), fingerprint->as_basic_args_string(),
fingerprint->as_string(), insts_size);
tty->print_cr("c2i argument handler starts at " INTPTR_FORMAT, p2i(entry->get_c2i_entry()));
if (Verbose || PrintStubCode) {
@ -2963,7 +2965,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::create_adapter(AdapterBlob*& new_ada
// The checks are inserted only if -XX:+VerifyAdapterCalls is specified.
if (contains_all_checks || !VerifyAdapterCalls) {
assert_lock_strong(AdapterHandlerLibrary_lock);
_adapter_handler_table.put(fingerprint, entry);
_adapter_handler_table->put(fingerprint, entry);
}
return entry;
}
@ -3296,7 +3298,7 @@ bool AdapterHandlerLibrary::contains(const CodeBlob* b) {
return (found = (b == CodeCache::find_blob(a->get_i2c_entry())));
};
assert_locked_or_safepoint(AdapterHandlerLibrary_lock);
_adapter_handler_table.iterate(findblob);
_adapter_handler_table->iterate(findblob);
return found;
}
@ -3313,7 +3315,7 @@ void AdapterHandlerLibrary::print_handler_on(outputStream* st, const CodeBlob* b
}
};
assert_locked_or_safepoint(AdapterHandlerLibrary_lock);
_adapter_handler_table.iterate(findblob);
_adapter_handler_table->iterate(findblob);
assert(found, "Should have found handler");
}