mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-19 10:34:38 +02:00
8218266: G1 crash in AccessInternal::PostRuntimeDispatch
Protection_domains can be unloaded in the dictionary pd_set. Reviewed-by: zgu, hseigel
This commit is contained in:
parent
29d842b5a0
commit
84a6e34fb0
8 changed files with 174 additions and 108 deletions
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/classLoaderData.inline.hpp"
|
||||
#include "classfile/dictionary.inline.hpp"
|
||||
#include "classfile/dictionary.hpp"
|
||||
#include "classfile/protectionDomainCache.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "logging/log.hpp"
|
||||
|
@ -35,6 +35,7 @@
|
|||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/safepointVerifiers.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
|
||||
|
@ -80,6 +81,8 @@ DictionaryEntry* Dictionary::new_entry(unsigned int hash, InstanceKlass* klass)
|
|||
void Dictionary::free_entry(DictionaryEntry* entry) {
|
||||
// avoid recursion when deleting linked list
|
||||
// pd_set is accessed during a safepoint.
|
||||
// This doesn't require a lock because nothing is reading this
|
||||
// entry anymore. The ClassLoader is dead.
|
||||
while (entry->pd_set() != NULL) {
|
||||
ProtectionDomainEntry* to_delete = entry->pd_set();
|
||||
entry->set_pd_set(to_delete->next());
|
||||
|
@ -146,11 +149,14 @@ bool Dictionary::resize_if_needed() {
|
|||
}
|
||||
|
||||
bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
|
||||
// Lock the pd_set list. This lock cannot safepoint since the caller holds
|
||||
// a Dictionary entry, which can be moved if the Dictionary is resized.
|
||||
MutexLockerEx ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
|
||||
#ifdef ASSERT
|
||||
if (oopDesc::equals(protection_domain, instance_klass()->protection_domain())) {
|
||||
// Ensure this doesn't show up in the pd_set (invariant)
|
||||
bool in_pd_set = false;
|
||||
for (ProtectionDomainEntry* current = pd_set_acquire();
|
||||
for (ProtectionDomainEntry* current = pd_set();
|
||||
current != NULL;
|
||||
current = current->next()) {
|
||||
if (oopDesc::equals(current->object_no_keepalive(), protection_domain)) {
|
||||
|
@ -170,7 +176,7 @@ bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
for (ProtectionDomainEntry* current = pd_set_acquire();
|
||||
for (ProtectionDomainEntry* current = pd_set();
|
||||
current != NULL;
|
||||
current = current->next()) {
|
||||
if (oopDesc::equals(current->object_no_keepalive(), protection_domain)) return true;
|
||||
|
@ -183,13 +189,12 @@ void DictionaryEntry::add_protection_domain(Dictionary* dict, Handle protection_
|
|||
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||
if (!contains_protection_domain(protection_domain())) {
|
||||
ProtectionDomainCacheEntry* entry = SystemDictionary::cache_get(protection_domain);
|
||||
// The pd_set in the dictionary entry is protected by a low level lock.
|
||||
// With concurrent PD table cleanup, these links could be broken.
|
||||
MutexLockerEx ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
|
||||
ProtectionDomainEntry* new_head =
|
||||
new ProtectionDomainEntry(entry, pd_set());
|
||||
// Warning: Preserve store ordering. The SystemDictionary is read
|
||||
// without locks. The new ProtectionDomainEntry must be
|
||||
// complete before other threads can be allowed to see it
|
||||
// via a store to _pd_set.
|
||||
release_set_pd_set(new_head);
|
||||
set_pd_set(new_head);
|
||||
}
|
||||
LogTarget(Trace, protectiondomain) lt;
|
||||
if (lt.is_enabled()) {
|
||||
|
@ -348,6 +353,56 @@ bool Dictionary::is_valid_protection_domain(unsigned int hash,
|
|||
return entry->is_valid_protection_domain(protection_domain);
|
||||
}
|
||||
|
||||
// During class loading we may have cached a protection domain that has
|
||||
// since been unreferenced, so this entry should be cleared.
|
||||
void Dictionary::clean_cached_protection_domains() {
|
||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||
|
||||
if (loader_data()->is_the_null_class_loader_data()) {
|
||||
// Classes in the boot loader are not loaded with protection domains
|
||||
return;
|
||||
}
|
||||
|
||||
for (int index = 0; index < table_size(); index++) {
|
||||
for (DictionaryEntry* probe = bucket(index);
|
||||
probe != NULL;
|
||||
probe = probe->next()) {
|
||||
Klass* e = probe->instance_klass();
|
||||
|
||||
MutexLockerEx ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
|
||||
ProtectionDomainEntry* current = probe->pd_set();
|
||||
ProtectionDomainEntry* prev = NULL;
|
||||
while (current != NULL) {
|
||||
if (current->object_no_keepalive() == NULL) {
|
||||
LogTarget(Debug, protectiondomain) lt;
|
||||
if (lt.is_enabled()) {
|
||||
ResourceMark rm;
|
||||
// Print out trace information
|
||||
LogStream ls(lt);
|
||||
ls.print_cr("PD in set is not alive:");
|
||||
ls.print("class loader: "); loader_data()->class_loader()->print_value_on(&ls);
|
||||
ls.print(" loading: "); probe->instance_klass()->print_value_on(&ls);
|
||||
ls.cr();
|
||||
}
|
||||
if (probe->pd_set() == current) {
|
||||
probe->set_pd_set(current->next());
|
||||
} else {
|
||||
assert(prev != NULL, "should be set by alive entry");
|
||||
prev->set_next(current->next());
|
||||
}
|
||||
ProtectionDomainEntry* to_delete = current;
|
||||
current = current->next();
|
||||
delete to_delete;
|
||||
} else {
|
||||
prev = current;
|
||||
current = current->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SymbolPropertyTable::SymbolPropertyTable(int table_size)
|
||||
: Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry))
|
||||
{
|
||||
|
@ -404,6 +459,25 @@ void SymbolPropertyTable::methods_do(void f(Method*)) {
|
|||
}
|
||||
}
|
||||
|
||||
void DictionaryEntry::verify_protection_domain_set() {
|
||||
MutexLockerEx ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
|
||||
for (ProtectionDomainEntry* current = pd_set(); // accessed at a safepoint
|
||||
current != NULL;
|
||||
current = current->_next) {
|
||||
guarantee(oopDesc::is_oop_or_null(current->_pd_cache->object_no_keepalive()), "Invalid oop");
|
||||
}
|
||||
}
|
||||
|
||||
void DictionaryEntry::print_count(outputStream *st) {
|
||||
MutexLockerEx ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
|
||||
int count = 0;
|
||||
for (ProtectionDomainEntry* current = pd_set(); // accessed inside SD lock
|
||||
current != NULL;
|
||||
current = current->_next) {
|
||||
count++;
|
||||
}
|
||||
st->print_cr("pd set count = #%d", count);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue