8292680: Convert Dictionary to ConcurrentHashTable

Reviewed-by: rehn, hseigel
This commit is contained in:
Coleen Phillimore 2022-08-25 19:02:52 +00:00
parent 2fe0ce0148
commit 4f50316a1a
30 changed files with 436 additions and 356 deletions

View file

@ -376,7 +376,7 @@ ciInstance* ciEnv::get_or_create_exception(jobject& handle, Symbol* name) {
VM_ENTRY_MARK;
if (handle == NULL) {
// Cf. universe.cpp, creation of Universe::_null_ptr_exception_instance.
InstanceKlass* ik = SystemDictionary::find_instance_klass(name, Handle(), Handle());
InstanceKlass* ik = SystemDictionary::find_instance_klass(THREAD, name, Handle(), Handle());
jobject objh = NULL;
if (ik != NULL) {
oop obj = ik->allocate_instance(THREAD);
@ -529,7 +529,7 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
if (!require_local) {
kls = SystemDictionary::find_constrained_instance_or_array_klass(current, sym, loader);
} else {
kls = SystemDictionary::find_instance_or_array_klass(sym, loader, domain);
kls = SystemDictionary::find_instance_or_array_klass(current, sym, loader, domain);
}
found_klass = kls;
}

View file

@ -572,18 +572,6 @@ void ClassLoaderDataGraph::purge(bool at_safepoint) {
}
}
int ClassLoaderDataGraph::resize_dictionaries() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
int resized = 0;
assert (Dictionary::does_any_dictionary_needs_resizing(), "some dictionary should need resizing");
FOR_ALL_DICTIONARY(cld) {
if (cld->dictionary()->resize_if_needed()) {
resized++;
}
}
return resized;
}
ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
: _next_klass(NULL) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");

View file

@ -104,8 +104,6 @@ class ClassLoaderDataGraph : public AllStatic {
static void print_dictionary(outputStream* st);
static void print_table_statistics(outputStream* st);
static int resize_dictionaries();
static bool has_metaspace_oom() { return _metaspace_oom; }
static void set_metaspace_oom(bool value) { _metaspace_oom = value; }

View file

@ -44,94 +44,69 @@
#include "runtime/javaCalls.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "utilities/concurrentHashTable.inline.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.inline.hpp"
#include "utilities/tableStatistics.hpp"
// Optimization: if any dictionary needs resizing, we set this flag,
// so that we don't have to walk all dictionaries to check if any actually
// needs resizing, which is costly to do at Safepoint.
bool Dictionary::_some_dictionary_needs_resizing = false;
// 2^24 is max size, like StringTable.
const size_t END_SIZE = 24;
// If a chain gets to 100 something might be wrong
const size_t REHASH_LEN = 100;
Dictionary::Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable)
: Hashtable<InstanceKlass*, mtClass>(table_size, (int)sizeof(DictionaryEntry)),
_resizable(resizable), _needs_resizing(false), _loader_data(loader_data) {
};
Dictionary::Dictionary(ClassLoaderData* loader_data, size_t table_size, bool resizable)
: _resizable(resizable), _number_of_entries(0), _loader_data(loader_data) {
Dictionary::Dictionary(ClassLoaderData* loader_data,
int table_size, HashtableBucket<mtClass>* t,
int number_of_entries, bool resizable)
: Hashtable<InstanceKlass*, mtClass>(table_size, (int)sizeof(DictionaryEntry), t, number_of_entries),
_resizable(resizable), _needs_resizing(false), _loader_data(loader_data) {
};
size_t start_size_log_2 = MAX2(ceil_log2(table_size), (size_t)2); // 2 is minimum size even though some dictionaries only have one entry
size_t current_size = ((size_t)1) << start_size_log_2;
log_info(class, loader, data)("Dictionary start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
current_size, start_size_log_2);
_table = new ConcurrentTable(start_size_log_2, END_SIZE, REHASH_LEN);
}
Dictionary::~Dictionary() {
DictionaryEntry* probe = NULL;
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
probe = *p;
*p = probe->next();
free_entry(probe);
}
}
assert(number_of_entries() == 0, "should have removed all entries");
// This deletes the table and all the nodes, by calling free_node in Config.
delete _table;
}
DictionaryEntry* Dictionary::new_entry(unsigned int hash, InstanceKlass* klass) {
DictionaryEntry* entry = (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::new_entry(hash, klass);
entry->release_set_pd_set(NULL);
assert(klass->is_instance_klass(), "Must be");
return entry;
uintx Dictionary::Config::get_hash(Value const& value, bool* is_dead) {
return value->instance_klass()->name()->identity_hash();
}
void Dictionary::free_entry(DictionaryEntry* entry) {
void* Dictionary::Config::allocate_node(void* context, size_t size, Value const& value) {
return AllocateHeap(size, mtClass);
}
void Dictionary::Config::free_node(void* context, void* memory, Value const& value) {
delete value; // Call DictionaryEntry destructor
FreeHeap(memory);
}
DictionaryEntry::DictionaryEntry(InstanceKlass* klass) : _instance_klass(klass) {
release_set_pd_set(nullptr);
}
DictionaryEntry::~DictionaryEntry() {
// 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_acquire() != NULL) {
ProtectionDomainEntry* to_delete = entry->pd_set_acquire();
entry->release_set_pd_set(to_delete->next_acquire());
while (pd_set_acquire() != NULL) {
ProtectionDomainEntry* to_delete = pd_set_acquire();
release_set_pd_set(to_delete->next_acquire());
delete to_delete;
}
BasicHashtable<mtClass>::free_entry(entry);
}
const int _resize_load_trigger = 5; // load factor that will trigger the resize
bool Dictionary::does_any_dictionary_needs_resizing() {
return Dictionary::_some_dictionary_needs_resizing;
int Dictionary::table_size() const {
return 1 << _table->get_size_log2(Thread::current());
}
void Dictionary::check_if_needs_resize() {
if (_resizable == true) {
if (number_of_entries() > (_resize_load_trigger*table_size())) {
_needs_resizing = true;
Dictionary::_some_dictionary_needs_resizing = true;
}
}
}
bool Dictionary::resize_if_needed() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
int desired_size = 0;
if (_needs_resizing == true) {
desired_size = calculate_resize(false);
assert(desired_size != 0, "bug in calculate_resize");
if (desired_size == table_size()) {
_resizable = false; // hit max
} else {
if (!resize(desired_size)) {
// Something went wrong, turn resizing off
_resizable = false;
}
}
}
_needs_resizing = false;
Dictionary::_some_dictionary_needs_resizing = false;
return (desired_size != 0);
bool Dictionary::check_if_needs_resize() {
return (_resizable &&
(_number_of_entries > (_resize_load_trigger * table_size())) &&
!_table->is_max_size_reached());
}
bool DictionaryEntry::is_valid_protection_domain(Handle protection_domain) {
@ -213,77 +188,84 @@ void DictionaryEntry::add_protection_domain(ClassLoaderData* loader_data, Handle
// Just the classes from defining class loaders
void Dictionary::classes_do(void f(InstanceKlass*)) {
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
InstanceKlass* k = probe->instance_klass();
auto doit = [&] (DictionaryEntry** value) {
InstanceKlass* k = (*value)->instance_klass();
if (loader_data() == k->class_loader_data()) {
f(k);
}
}
}
}
return true;
};
// Added for initialize_itable_for_klass to handle exceptions
// Just the classes from defining class loaders
void Dictionary::classes_do(void f(InstanceKlass*, TRAPS), TRAPS) {
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
InstanceKlass* k = probe->instance_klass();
if (loader_data() == k->class_loader_data()) {
f(k, CHECK);
}
}
}
_table->do_scan(Thread::current(), doit);
}
// All classes, and their class loaders, including initiating class loaders
void Dictionary::all_entries_do(KlassClosure* closure) {
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
InstanceKlass* k = probe->instance_klass();
auto all_doit = [&] (DictionaryEntry** value) {
InstanceKlass* k = (*value)->instance_klass();
closure->do_klass(k);
}
}
return true;
};
_table->do_scan(Thread::current(), all_doit);
}
// Used to scan and relocate the classes during CDS archive dump.
void Dictionary::classes_do(MetaspaceClosure* it) {
Arguments::assert_is_dumping_archive();
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
it->push(probe->klass_addr());
}
}
auto push = [&] (DictionaryEntry** value) {
InstanceKlass** k = (*value)->instance_klass_addr();
it->push(k);
return true;
};
_table->do_scan(Thread::current(), push);
}
class DictionaryLookup : StackObj {
private:
Symbol* _name;
public:
DictionaryLookup(Symbol* name) : _name(name) { }
uintx get_hash() const {
return _name->identity_hash();
}
bool equals(DictionaryEntry** value, bool* is_dead) {
DictionaryEntry *entry = *value;
*is_dead = false;
return (entry->instance_klass()->name() == _name);
}
};
// Add a loaded class to the dictionary.
// Readers of the SystemDictionary aren't always locked, so _buckets
// is volatile. The store of the next field in the constructor is
// also cast to volatile; we do this to ensure store order is maintained
// by the compilers.
void Dictionary::add_klass(unsigned int hash, Symbol* class_name,
void Dictionary::add_klass(JavaThread* current, Symbol* class_name,
InstanceKlass* obj) {
assert_locked_or_safepoint(SystemDictionary_lock);
assert_locked_or_safepoint(SystemDictionary_lock); // doesn't matter now
assert(obj != NULL, "adding NULL obj");
assert(obj->name() == class_name, "sanity check on name");
DictionaryEntry* entry = new_entry(hash, obj);
int index = hash_to_index(hash);
add_entry(index, entry);
check_if_needs_resize();
}
DictionaryEntry* entry = new DictionaryEntry(obj);
DictionaryLookup lookup(class_name);
bool needs_rehashing, clean_hint;
bool created = _table->insert(current, lookup, entry, &needs_rehashing, &clean_hint);
assert(created, "should be because we have a lock");
assert (!needs_rehashing, "should never need rehashing");
assert(!clean_hint, "no class should be unloaded");
_number_of_entries++; // still locked
// This table can be resized while another thread is reading it.
if (check_if_needs_resize()) {
_table->grow(current);
// It would be nice to have a JFR event here, add some logging.
LogTarget(Info, class, loader, data) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(&lt);
ls.print("Dictionary resized to %d entries %d for ", table_size(), _number_of_entries);
loader_data()->print_value_on(&ls);
}
}
}
// This routine does not lock the dictionary.
//
@ -293,27 +275,28 @@ void Dictionary::add_klass(unsigned int hash, Symbol* class_name,
// be updated in an MT-safe manner).
//
// Callers should be aware that an entry could be added just after
// _buckets[index] is read here, so the caller will not see the new entry.
DictionaryEntry* Dictionary::get_entry(int index, unsigned int hash,
// the table is read here, so the caller will not see the new entry.
// The entry may be accessed by the VM thread in verification.
DictionaryEntry* Dictionary::get_entry(Thread* current,
Symbol* class_name) {
for (DictionaryEntry* entry = bucket(index);
entry != NULL;
entry = entry->next()) {
if (entry->hash() == hash && entry->instance_klass()->name() == class_name) {
return entry;
}
}
return NULL;
DictionaryLookup lookup(class_name);
DictionaryEntry* result = nullptr;
auto get = [&] (DictionaryEntry** value) {
// function called if value is found so is never null
result = (*value);
};
bool needs_rehashing = false;
_table->get(current, lookup, get, &needs_rehashing);
assert (!needs_rehashing, "should never need rehashing");
return result;
}
InstanceKlass* Dictionary::find(unsigned int hash, Symbol* name,
InstanceKlass* Dictionary::find(Thread* current, Symbol* name,
Handle protection_domain) {
NoSafepointVerifier nsv;
int index = hash_to_index(hash);
DictionaryEntry* entry = get_entry(index, hash, name);
DictionaryEntry* entry = get_entry(current, name);
if (entry != NULL && entry->is_valid_protection_domain(protection_domain)) {
return entry->instance_klass();
} else {
@ -321,23 +304,19 @@ InstanceKlass* Dictionary::find(unsigned int hash, Symbol* name,
}
}
InstanceKlass* Dictionary::find_class(unsigned int hash,
InstanceKlass* Dictionary::find_class(Thread* current,
Symbol* name) {
assert_locked_or_safepoint(SystemDictionary_lock);
int index = hash_to_index(hash);
assert (index == index_for(name), "incorrect index?");
DictionaryEntry* entry = get_entry(index, hash, name);
DictionaryEntry* entry = get_entry(current, name);
return (entry != NULL) ? entry->instance_klass() : NULL;
}
void Dictionary::add_protection_domain(int index, unsigned int hash,
void Dictionary::add_protection_domain(JavaThread* current,
InstanceKlass* klass,
Handle protection_domain) {
assert(java_lang_System::allow_security_manager(), "only needed if security manager allowed");
Symbol* klass_name = klass->name();
DictionaryEntry* entry = get_entry(index, hash, klass_name);
DictionaryEntry* entry = get_entry(current, klass_name);
assert(entry != NULL,"entry must be present, we just created it");
assert(protection_domain() != NULL,
@ -354,16 +333,14 @@ void Dictionary::add_protection_domain(int index, unsigned int hash,
}
inline bool Dictionary::is_valid_protection_domain(unsigned int hash,
inline bool Dictionary::is_valid_protection_domain(JavaThread* current,
Symbol* name,
Handle protection_domain) {
int index = hash_to_index(hash);
DictionaryEntry* entry = get_entry(index, hash, name);
DictionaryEntry* entry = get_entry(current, name);
return entry->is_valid_protection_domain(protection_domain);
}
void Dictionary::validate_protection_domain(unsigned int name_hash,
InstanceKlass* klass,
void Dictionary::validate_protection_domain(InstanceKlass* klass,
Handle class_loader,
Handle protection_domain,
TRAPS) {
@ -372,7 +349,7 @@ void Dictionary::validate_protection_domain(unsigned int name_hash,
assert(protection_domain() != NULL, "Should not call this");
if (!java_lang_System::allow_security_manager() ||
is_valid_protection_domain(name_hash, klass->name(), protection_domain)) {
is_valid_protection_domain(THREAD, klass->name(), protection_domain)) {
return;
}
@ -424,8 +401,7 @@ void Dictionary::validate_protection_domain(unsigned int name_hash,
// and protection domain are expected to succeed.
{
MutexLocker mu(THREAD, SystemDictionary_lock);
int d_index = hash_to_index(name_hash);
add_protection_domain(d_index, name_hash, klass,
add_protection_domain(THREAD, klass,
protection_domain);
}
}
@ -442,10 +418,8 @@ void Dictionary::clean_cached_protection_domains(GrowableArray<ProtectionDomainE
return;
}
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
auto clean_entries = [&] (DictionaryEntry** value) {
DictionaryEntry* probe = *value;
Klass* e = probe->instance_klass();
ProtectionDomainEntry* current = probe->pd_set_acquire();
@ -458,7 +432,7 @@ void Dictionary::clean_cached_protection_domains(GrowableArray<ProtectionDomainE
// 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("class loader: "); _loader_data->class_loader()->print_value_on(&ls);
ls.print(" loading: "); probe->instance_klass()->print_value_on(&ls);
ls.cr();
}
@ -477,8 +451,10 @@ void Dictionary::clean_cached_protection_domains(GrowableArray<ProtectionDomainE
current = current->next_acquire();
}
}
}
}
return true;
};
_table->do_scan(Thread::current(), clean_entries);
}
void DictionaryEntry::verify_protection_domain_set() {
@ -505,7 +481,7 @@ void DictionaryEntry::print_count(outputStream *st) {
void Dictionary::print_size(outputStream* st) const {
st->print_cr("Java dictionary (table_size=%d, classes=%d, resizable=%s)",
table_size(), number_of_entries(), BOOL_TO_STR(_resizable));
table_size(), _number_of_entries, BOOL_TO_STR(_resizable));
}
void Dictionary::print_on(outputStream* st) const {
@ -516,16 +492,14 @@ void Dictionary::print_on(outputStream* st) const {
print_size(st);
st->print_cr("^ indicates that initiating loader is different from defining loader");
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
auto printer = [&] (DictionaryEntry** entry) {
DictionaryEntry* probe = *entry;
Klass* e = probe->instance_klass();
bool is_defining_class =
(loader_data() == e->class_loader_data());
st->print("%4d: %s%s", index, is_defining_class ? " " : "^", e->external_name());
(_loader_data == e->class_loader_data());
st->print(" %s%s", is_defining_class ? " " : "^", e->external_name());
ClassLoaderData* cld = e->class_loader_data();
if (!loader_data()->is_the_null_class_loader_data()) {
if (!_loader_data->is_the_null_class_loader_data()) {
// Class loader output for the dictionary for the null class loader data is
// redundant and obvious.
st->print(", ");
@ -534,7 +508,13 @@ void Dictionary::print_on(outputStream* st) const {
probe->print_count(st);
}
st->cr();
}
return true;
};
if (SafepointSynchronize::is_at_safepoint()) {
_table->do_safepoint_scan(printer);
} else {
_table->do_scan(Thread::current(), printer);
}
tty->cr();
}
@ -548,7 +528,7 @@ void DictionaryEntry::verify() {
}
void Dictionary::verify() {
guarantee(number_of_entries() >= 0, "Verify of dictionary failed");
guarantee(_number_of_entries >= 0, "Verify of dictionary failed");
ClassLoaderData* cld = loader_data();
// class loader must be present; a null class loader is the
@ -557,8 +537,19 @@ void Dictionary::verify() {
(cld->is_the_null_class_loader_data() || cld->class_loader_no_keepalive()->is_instance()),
"checking type of class_loader");
ResourceMark rm;
stringStream tempst;
tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id());
verify_table<DictionaryEntry>(tempst.as_string());
auto verifier = [&] (DictionaryEntry** val) {
(*val)->verify();
return true;
};
_table->do_safepoint_scan(verifier);
}
void Dictionary::print_table_statistics(outputStream* st, const char* table_name) {
static TableStatistics ts;
auto sz = [&] (DictionaryEntry** val) {
return sizeof(**val);
};
ts = _table->statistics_get(Thread::current(), sz, ts);
ts.print(st, table_name);
}

View file

@ -28,7 +28,7 @@
#include "oops/instanceKlass.hpp"
#include "oops/oop.hpp"
#include "oops/oopHandle.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/concurrentHashTable.hpp"
#include "utilities/ostream.hpp"
class DictionaryEntry;
@ -38,77 +38,68 @@ template <typename T> class GrowableArray;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The data structure for the class loader data dictionaries.
class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
friend class VMStructs;
class DictionaryEntry;
static bool _some_dictionary_needs_resizing;
class Dictionary : public CHeapObj<mtClass> {
bool _resizable;
bool _needs_resizing;
void check_if_needs_resize();
int _number_of_entries;
class Config {
public:
using Value = DictionaryEntry*;
static uintx get_hash(Value const& value, bool* is_dead);
static void* allocate_node(void* context, size_t size, Value const& value);
static void free_node(void* context, void* memory, Value const& value);
};
using ConcurrentTable = ConcurrentHashTable<Config, mtClass>;
ConcurrentTable* _table;
ClassLoaderData* _loader_data; // backpointer to owning loader
ClassLoaderData* loader_data() const { return _loader_data; }
DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name);
DictionaryEntry* get_entry(Thread* current, Symbol* name);
bool check_if_needs_resize();
int table_size() const;
public:
Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable = false);
Dictionary(ClassLoaderData* loader_data, int table_size, HashtableBucket<mtClass>* t, int number_of_entries, bool resizable = false);
Dictionary(ClassLoaderData* loader_data, size_t table_size, bool resizable = false);
~Dictionary();
static bool does_any_dictionary_needs_resizing();
bool resize_if_needed();
void add_klass(JavaThread* current, Symbol* class_name, InstanceKlass* obj);
void add_klass(unsigned int hash, Symbol* class_name, InstanceKlass* obj);
InstanceKlass* find_class(unsigned int hash, Symbol* name);
InstanceKlass* find_class(Thread* current, Symbol* name);
void classes_do(void f(InstanceKlass*));
void classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
void all_entries_do(KlassClosure* closure);
void classes_do(MetaspaceClosure* it);
void clean_cached_protection_domains(GrowableArray<ProtectionDomainEntry*>* delete_list);
// Protection domains
InstanceKlass* find(unsigned int hash, Symbol* name, Handle protection_domain);
void validate_protection_domain(unsigned int name_hash,
InstanceKlass* klass,
InstanceKlass* find(Thread* current, Symbol* name, Handle protection_domain);
void validate_protection_domain(InstanceKlass* klass,
Handle class_loader,
Handle protection_domain,
TRAPS);
void print_table_statistics(outputStream* st, const char* table_name);
void print_on(outputStream* st) const;
void print_size(outputStream* st) const;
void verify();
private:
DictionaryEntry* new_entry(unsigned int hash, InstanceKlass* klass);
DictionaryEntry* bucket(int i) const {
return (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i);
}
// The following method is not MT-safe and must be done under lock.
DictionaryEntry** bucket_addr(int i) {
return (DictionaryEntry**)Hashtable<InstanceKlass*, mtClass>::bucket_addr(i);
}
void free_entry(DictionaryEntry* entry);
bool is_valid_protection_domain(unsigned int hash,
Symbol* name,
bool is_valid_protection_domain(JavaThread* current, Symbol* name,
Handle protection_domain);
void add_protection_domain(int index, unsigned int hash,
InstanceKlass* klass,
void add_protection_domain(JavaThread* current, InstanceKlass* klass,
Handle protection_domain);
};
// An entry in the class loader data dictionaries, this describes a class as
// { InstanceKlass*, protection_domain }.
// { InstanceKlass*, protection_domain_set }.
class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
friend class VMStructs;
class DictionaryEntry : public CHeapObj<mtClass> {
private:
// Contains the set of approved protection domains that can access
// this dictionary entry.
@ -123,24 +114,20 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
// It is essentially a cache to avoid repeated Java up-calls to
// ClassLoader.checkPackageAccess().
//
InstanceKlass* _instance_klass;
ProtectionDomainEntry* volatile _pd_set;
public:
DictionaryEntry(InstanceKlass* instance_klass);
~DictionaryEntry();
// Tells whether a protection is in the approved set.
bool contains_protection_domain(oop protection_domain) const;
// Adds a protection domain to the approved set.
void add_protection_domain(ClassLoaderData* loader_data, Handle protection_domain);
InstanceKlass* instance_klass() const { return literal(); }
InstanceKlass** klass_addr() { return (InstanceKlass**)literal_addr(); }
DictionaryEntry* next() const {
return (DictionaryEntry*)HashtableEntry<InstanceKlass*, mtClass>::next();
}
DictionaryEntry** next_addr() {
return (DictionaryEntry**)HashtableEntry<InstanceKlass*, mtClass>::next_addr();
}
InstanceKlass* instance_klass() const { return _instance_klass; }
InstanceKlass** instance_klass_addr() { return &_instance_klass; }
ProtectionDomainEntry* pd_set_acquire() const { return Atomic::load_acquire(&_pd_set); }
void release_set_pd_set(ProtectionDomainEntry* entry) { Atomic::release_store(&_pd_set, entry); }

View file

@ -454,6 +454,7 @@ void LoaderConstraintTable::merge_loader_constraints(Symbol* class_name,
}
void LoaderConstraintTable::verify() {
Thread* thread = Thread::current();
auto check = [&] (Symbol*& key, ConstraintSet& set) {
// foreach constraint in the set, check the klass is in the dictionary or placeholder table.
int len = set.num_constraints();
@ -465,8 +466,7 @@ void LoaderConstraintTable::verify() {
Symbol* name = ik->name();
ClassLoaderData* loader_data = ik->class_loader_data();
Dictionary* dictionary = loader_data->dictionary();
unsigned int name_hash = dictionary->compute_hash(name);
InstanceKlass* k = dictionary->find_class(name_hash, name);
InstanceKlass* k = dictionary->find_class(thread, name);
if (k != NULL) {
// We found the class in the dictionary, so we should
// make sure that the Klass* matches what we already have.

View file

@ -212,12 +212,6 @@ class StringTableLookupOop : public StackObj {
}
};
static size_t ceil_log2(size_t val) {
size_t ret;
for (ret = 1; ((size_t)1 << ret) < val; ++ret);
return ret;
}
void StringTable::create_table() {
size_t start_size_log_2 = ceil_log2(StringTableSize);
_current_size = ((size_t)1) << start_size_log_2;

View file

@ -161,12 +161,6 @@ public:
}
};
static size_t ceil_log2(size_t value) {
size_t ret;
for (ret = 1; ((size_t)1 << ret) < value; ++ret);
return ret;
}
void SymbolTable::create_table () {
size_t start_size_log_2 = ceil_log2(SymbolTableSize);
_current_size = ((size_t)1) << start_size_log_2;

View file

@ -284,8 +284,7 @@ void verify_dictionary_entry(Symbol* class_name, InstanceKlass* k) {
ClassLoaderData* loader_data = k->class_loader_data();
Dictionary* dictionary = loader_data->dictionary();
assert(class_name == k->name(), "Must be the same");
unsigned int name_hash = dictionary->compute_hash(class_name);
InstanceKlass* kk = dictionary->find_class(name_hash, class_name);
InstanceKlass* kk = dictionary->find_class(JavaThread::current(), class_name);
assert(kk == k, "should be present in dictionary");
}
#endif
@ -431,13 +430,12 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name,
ClassLoaderData* loader_data = class_loader_data(class_loader);
Dictionary* dictionary = loader_data->dictionary();
unsigned int name_hash = dictionary->compute_hash(class_name);
// can't throw error holding a lock
bool throw_circularity_error = false;
{
MutexLocker mu(THREAD, SystemDictionary_lock);
InstanceKlass* klassk = dictionary->find_class(name_hash, class_name);
InstanceKlass* klassk = dictionary->find_class(THREAD, class_name);
InstanceKlass* quicksuperk;
// To support parallel loading: if class is done loading, just return the superclass
// if the super_name matches class->super()->name() and if the class loaders match.
@ -562,7 +560,6 @@ static bool should_wait_for_loading(Handle class_loader) {
// For bootstrap and non-parallelCapable class loaders, check and wait for
// another thread to complete loading this class.
InstanceKlass* SystemDictionary::handle_parallel_loading(JavaThread* current,
unsigned int name_hash,
Symbol* name,
ClassLoaderData* loader_data,
Handle lockObject,
@ -602,7 +599,7 @@ InstanceKlass* SystemDictionary::handle_parallel_loading(JavaThread* current,
}
// Check if classloading completed while we were waiting
InstanceKlass* check = loader_data->dictionary()->find_class(name_hash, name);
InstanceKlass* check = loader_data->dictionary()->find_class(current, name);
if (check != NULL) {
// Klass is already loaded, so just return it
return check;
@ -646,14 +643,13 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
ClassLoaderData* loader_data = register_loader(class_loader);
Dictionary* dictionary = loader_data->dictionary();
unsigned int name_hash = dictionary->compute_hash(name);
// Do lookup to see if class already exists and the protection domain
// has the right access.
// This call uses find which checks protection domain already matches
// All subsequent calls use find_class, and set loaded_class so that
// before we return a result, we call out to java to check for valid protection domain.
InstanceKlass* probe = dictionary->find(name_hash, name, protection_domain);
InstanceKlass* probe = dictionary->find(THREAD, name, protection_domain);
if (probe != NULL) return probe;
// Non-bootstrap class loaders will call out to class loader and
@ -680,7 +676,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
// Check again (after locking) if the class already exists in SystemDictionary
{
MutexLocker mu(THREAD, SystemDictionary_lock);
InstanceKlass* check = dictionary->find_class(name_hash, name);
InstanceKlass* check = dictionary->find_class(THREAD, name);
if (check != NULL) {
// InstanceKlass is already loaded, but we still need to check protection domain below.
loaded_class = check;
@ -728,7 +724,6 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
MutexLocker mu(THREAD, SystemDictionary_lock);
if (should_wait_for_loading(class_loader)) {
loaded_class = handle_parallel_loading(THREAD,
name_hash,
name,
loader_data,
lockObject,
@ -738,7 +733,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
// Recheck if the class has been loaded for all class loader cases and
// add a LOAD_INSTANCE placeholder while holding the SystemDictionary_lock.
if (!throw_circularity_error && loaded_class == NULL) {
InstanceKlass* check = dictionary->find_class(name_hash, name);
InstanceKlass* check = dictionary->find_class(THREAD, name);
if (check != NULL) {
loaded_class = check;
} else if (should_wait_for_loading(class_loader)) {
@ -766,7 +761,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
if (loaded_class == NULL) {
// Do actual loading
loaded_class = load_instance_class(name_hash, name, class_loader, THREAD);
loaded_class = load_instance_class(name, class_loader, THREAD);
}
if (load_placeholder_added) {
@ -793,7 +788,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
// Check if the protection domain is present it has the right access
if (protection_domain() != NULL) {
// Verify protection domain. If it fails an exception is thrown
dictionary->validate_protection_domain(name_hash, loaded_class, class_loader, protection_domain, CHECK_NULL);
dictionary->validate_protection_domain(loaded_class, class_loader, protection_domain, CHECK_NULL);
}
return loaded_class;
@ -808,10 +803,11 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
// unloading, when this class loader is no longer referenced.
//
// Callers should be aware that an entry could be added just after
// _dictionary->bucket(index) is read here, so the caller will not see
// Dictionary is read here, so the caller will not see
// the new entry.
InstanceKlass* SystemDictionary::find_instance_klass(Symbol* class_name,
InstanceKlass* SystemDictionary::find_instance_klass(Thread* current,
Symbol* class_name,
Handle class_loader,
Handle protection_domain) {
@ -828,13 +824,13 @@ InstanceKlass* SystemDictionary::find_instance_klass(Symbol* class_name,
}
Dictionary* dictionary = loader_data->dictionary();
unsigned int name_hash = dictionary->compute_hash(class_name);
return dictionary->find(name_hash, class_name, protection_domain);
return dictionary->find(current, class_name, protection_domain);
}
// Look for a loaded instance or array klass by name. Do not do any loading.
// return NULL in case of error.
Klass* SystemDictionary::find_instance_or_array_klass(Symbol* class_name,
Klass* SystemDictionary::find_instance_or_array_klass(Thread* current,
Symbol* class_name,
Handle class_loader,
Handle protection_domain) {
Klass* k = NULL;
@ -850,13 +846,13 @@ Klass* SystemDictionary::find_instance_or_array_klass(Symbol* class_name,
if (t != T_OBJECT) {
k = Universe::typeArrayKlassObj(t);
} else {
k = SystemDictionary::find_instance_klass(ss.as_symbol(), class_loader, protection_domain);
k = SystemDictionary::find_instance_klass(current, ss.as_symbol(), class_loader, protection_domain);
}
if (k != NULL) {
k = k->array_klass_or_null(ndims);
}
} else {
k = find_instance_klass(class_name, class_loader, protection_domain);
k = find_instance_klass(current, class_name, class_loader, protection_domain);
}
return k;
}
@ -1110,7 +1106,7 @@ bool SystemDictionary::check_shared_class_super_type(InstanceKlass* klass, Insta
if (!super_type->is_shared_unregistered_class() && super_type->class_loader_data() != NULL) {
// Check if the superclass is loaded by the current class_loader
Symbol* name = super_type->name();
InstanceKlass* check = find_instance_klass(name, class_loader, protection_domain);
InstanceKlass* check = find_instance_klass(THREAD, name, class_loader, protection_domain);
if (check == super_type) {
return true;
}
@ -1401,8 +1397,7 @@ InstanceKlass* SystemDictionary::load_instance_class_impl(Symbol* class_name, Ha
}
}
InstanceKlass* SystemDictionary::load_instance_class(unsigned int name_hash,
Symbol* name,
InstanceKlass* SystemDictionary::load_instance_class(Symbol* name,
Handle class_loader,
TRAPS) {
@ -1413,7 +1408,7 @@ InstanceKlass* SystemDictionary::load_instance_class(unsigned int name_hash,
if (loaded_class != NULL &&
loaded_class->class_loader() != class_loader()) {
check_constraints(name_hash, loaded_class, class_loader, false, CHECK_NULL);
check_constraints(loaded_class, class_loader, false, CHECK_NULL);
// Record dependency for non-parent delegation.
// This recording keeps the defining class loader of the klass (loaded_class) found
@ -1426,7 +1421,7 @@ InstanceKlass* SystemDictionary::load_instance_class(unsigned int name_hash,
{ // Grabbing the Compile_lock prevents systemDictionary updates
// during compilations.
MutexLocker mu(THREAD, Compile_lock);
update_dictionary(name_hash, loaded_class, class_loader);
update_dictionary(THREAD, loaded_class, class_loader);
}
if (JvmtiExport::should_post_class_load()) {
@ -1472,8 +1467,7 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, Handle class_load
// which will require a token to perform the define class
Symbol* name_h = k->name();
Dictionary* dictionary = loader_data->dictionary();
unsigned int name_hash = dictionary->compute_hash(name_h);
check_constraints(name_hash, k, class_loader, true, CHECK);
check_constraints(k, class_loader, true, CHECK);
// Register class just loaded with class loader (placed in ArrayList)
// Note we do this before updating the dictionary, as this can
@ -1497,7 +1491,7 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, Handle class_load
// Add to systemDictionary - so other classes can see it.
// Grabs and releases SystemDictionary_lock
update_dictionary(name_hash, k, class_loader);
update_dictionary(THREAD, k, class_loader);
}
// notify jvmti
@ -1534,14 +1528,12 @@ InstanceKlass* SystemDictionary::find_or_define_helper(Symbol* class_name, Handl
ClassLoaderData* loader_data = class_loader_data(class_loader);
Dictionary* dictionary = loader_data->dictionary();
unsigned int name_hash = dictionary->compute_hash(name_h);
// Hold SD lock around find_class and placeholder creation for DEFINE_CLASS
{
MutexLocker mu(THREAD, SystemDictionary_lock);
// First check if class already defined
if (is_parallelDefine(class_loader)) {
InstanceKlass* check = dictionary->find_class(name_hash, name_h);
InstanceKlass* check = dictionary->find_class(THREAD, name_h);
if (check != NULL) {
return check;
}
@ -1565,7 +1557,7 @@ InstanceKlass* SystemDictionary::find_or_define_helper(Symbol* class_name, Handl
PlaceholderTable::find_and_remove(name_h, loader_data, PlaceholderTable::DEFINE_CLASS, THREAD);
SystemDictionary_lock->notify_all();
#ifdef ASSERT
InstanceKlass* check = dictionary->find_class(name_hash, name_h);
InstanceKlass* check = dictionary->find_class(THREAD, name_h);
assert(check != NULL, "definer missed recording success");
#endif
return ik;
@ -1731,8 +1723,7 @@ void SystemDictionary::initialize(TRAPS) {
// if defining is true, then LinkageError if already in dictionary
// if initiating loader, then ok if InstanceKlass matches existing entry
void SystemDictionary::check_constraints(unsigned int name_hash,
InstanceKlass* k,
void SystemDictionary::check_constraints(InstanceKlass* k,
Handle class_loader,
bool defining,
TRAPS) {
@ -1746,7 +1737,7 @@ void SystemDictionary::check_constraints(unsigned int name_hash,
MutexLocker mu(THREAD, SystemDictionary_lock);
InstanceKlass* check = loader_data->dictionary()->find_class(name_hash, name);
InstanceKlass* check = loader_data->dictionary()->find_class(THREAD, name);
if (check != NULL) {
// If different InstanceKlass - duplicate class definition,
// else - ok, class loaded by a different thread in parallel.
@ -1790,7 +1781,7 @@ void SystemDictionary::check_constraints(unsigned int name_hash,
// Update class loader data dictionary - done after check_constraint and add_to_hierarchy
// have been called.
void SystemDictionary::update_dictionary(unsigned int hash,
void SystemDictionary::update_dictionary(JavaThread* current,
InstanceKlass* k,
Handle class_loader) {
// Compile_lock prevents systemDictionary updates during compilations
@ -1803,9 +1794,9 @@ void SystemDictionary::update_dictionary(unsigned int hash,
// Make a new dictionary entry.
Dictionary* dictionary = loader_data->dictionary();
InstanceKlass* sd_check = dictionary->find_class(hash, name);
InstanceKlass* sd_check = dictionary->find_class(current, name);
if (sd_check == NULL) {
dictionary->add_klass(hash, name, k);
dictionary->add_klass(current, name, k);
}
SystemDictionary_lock->notify_all();
}
@ -1821,7 +1812,7 @@ Klass* SystemDictionary::find_constrained_instance_or_array_klass(
// First see if it has been loaded directly.
// Force the protection domain to be null. (This removes protection checks.)
Handle no_protection_domain;
Klass* klass = find_instance_or_array_klass(class_name, class_loader,
Klass* klass = find_instance_or_array_klass(current, class_name, class_loader,
no_protection_domain);
if (klass != NULL)
return klass;
@ -1881,15 +1872,13 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name,
}
Dictionary* dictionary1 = loader_data1->dictionary();
unsigned int name_hash1 = dictionary1->compute_hash(constraint_name);
Dictionary* dictionary2 = loader_data2->dictionary();
unsigned int name_hash2 = dictionary2->compute_hash(constraint_name);
JavaThread* current = JavaThread::current();
{
MutexLocker mu_s(SystemDictionary_lock);
InstanceKlass* klass1 = dictionary1->find_class(name_hash1, constraint_name);
InstanceKlass* klass2 = dictionary2->find_class(name_hash2, constraint_name);
InstanceKlass* klass1 = dictionary1->find_class(current, constraint_name);
InstanceKlass* klass2 = dictionary2->find_class(current, constraint_name);
bool result = LoaderConstraintTable::add_entry(constraint_name, klass1, class_loader1,
klass2, class_loader2);
#if INCLUDE_CDS

View file

@ -144,12 +144,13 @@ class SystemDictionary : AllStatic {
TRAPS);
// Lookup an already loaded class. If not found NULL is returned.
static InstanceKlass* find_instance_klass(Symbol* class_name, Handle class_loader, Handle protection_domain);
static InstanceKlass* find_instance_klass(Thread* current, Symbol* class_name,
Handle class_loader, Handle protection_domain);
// Lookup an already loaded instance or array class.
// Do not make any queries to class loaders; consult only the cache.
// If not found NULL is returned.
static Klass* find_instance_or_array_klass(Symbol* class_name,
static Klass* find_instance_or_array_klass(Thread* current, Symbol* class_name,
Handle class_loader,
Handle protection_domain);
@ -324,7 +325,6 @@ private:
Handle class_loader,
Handle protection_domain, TRAPS);
static InstanceKlass* handle_parallel_loading(JavaThread* current,
unsigned int name_hash,
Symbol* name,
ClassLoaderData* loader_data,
Handle lockObject,
@ -335,8 +335,7 @@ private:
Handle class_loader,
InstanceKlass* k, TRAPS);
static InstanceKlass* load_instance_class_impl(Symbol* class_name, Handle class_loader, TRAPS);
static InstanceKlass* load_instance_class(unsigned int name_hash,
Symbol* class_name,
static InstanceKlass* load_instance_class(Symbol* class_name,
Handle class_loader, TRAPS);
static bool is_shared_class_visible(Symbol* class_name, InstanceKlass* ik,
@ -400,11 +399,9 @@ protected:
static Symbol* find_placeholder(Symbol* name, ClassLoaderData* loader_data);
// Class loader constraints
static void check_constraints(unsigned int hash,
InstanceKlass* k, Handle loader,
static void check_constraints(InstanceKlass* k, Handle loader,
bool defining, TRAPS);
static void update_dictionary(unsigned int hash,
InstanceKlass* k, Handle loader);
static void update_dictionary(JavaThread* current, InstanceKlass* k, Handle loader);
};
#endif // SHARE_CLASSFILE_SYSTEMDICTIONARY_HPP

View file

@ -401,7 +401,6 @@ InstanceKlass* SystemDictionaryShared::find_or_load_shared_class(
THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
ClassLoaderData *loader_data = register_loader(class_loader);
Dictionary* dictionary = loader_data->dictionary();
unsigned int d_hash = dictionary->compute_hash(name);
// Note: currently, find_or_load_shared_class is called only from
// JVM_FindLoadedClass and used for PlatformClassLoader and AppClassLoader,
@ -409,7 +408,7 @@ InstanceKlass* SystemDictionaryShared::find_or_load_shared_class(
assert(get_loader_lock_or_null(class_loader) == NULL, "ObjectLocker not required");
{
MutexLocker mu(THREAD, SystemDictionary_lock);
InstanceKlass* check = dictionary->find_class(d_hash, name);
InstanceKlass* check = dictionary->find_class(THREAD, name);
if (check != NULL) {
return check;
}

View file

@ -247,8 +247,7 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load
klass->restore_unshareable_info(loader_data, domain, NULL, THREAD);
SystemDictionary::load_shared_class_misc(klass, loader_data);
Dictionary* dictionary = loader_data->dictionary();
unsigned int hash = dictionary->compute_hash(klass->name());
dictionary->add_klass(hash, klass->name(), klass);
dictionary->add_klass(THREAD, klass->name(), klass);
SystemDictionary::add_to_hierarchy(klass);
assert(klass->is_loaded(), "Must be in at least loaded state");
}

View file

@ -516,7 +516,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU
// This is a name from a signature. Strip off the trimmings.
// Call recursive to keep scope of strippedsym.
TempNewSymbol strippedsym = Signature::strip_envelope(class_name);
resolved_klass = SystemDictionary::find_instance_klass(strippedsym,
resolved_klass = SystemDictionary::find_instance_klass(THREAD, strippedsym,
class_loader,
protection_domain);
} else if (Signature::is_array(class_name)) {
@ -524,7 +524,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU
int ndim = ss.skip_array_prefix();
if (ss.type() == T_OBJECT) {
Symbol* strippedsym = ss.as_symbol();
resolved_klass = SystemDictionary::find_instance_klass(strippedsym,
resolved_klass = SystemDictionary::find_instance_klass(THREAD, strippedsym,
class_loader,
protection_domain);
if (!resolved_klass.is_null()) {
@ -534,7 +534,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU
resolved_klass = TypeArrayKlass::cast(Universe::typeArrayKlassObj(ss.type()))->array_klass(ndim, CHECK_NULL);
}
} else {
resolved_klass = SystemDictionary::find_instance_klass(class_name,
resolved_klass = SystemDictionary::find_instance_klass(THREAD, class_name,
class_loader,
protection_domain);
}

View file

@ -1656,7 +1656,7 @@ Klass* JVMCIRuntime::get_klass_by_name_impl(Klass*& accessing_klass,
if (!require_local) {
found_klass = SystemDictionary::find_constrained_instance_or_array_klass(THREAD, sym, loader);
} else {
found_klass = SystemDictionary::find_instance_or_array_klass(sym, loader, domain);
found_klass = SystemDictionary::find_instance_or_array_klass(THREAD, sym, loader, domain);
}
}

View file

@ -584,7 +584,7 @@ Klass* ConstantPool::klass_at_if_loaded(const constantPoolHandle& this_cp, int w
oop protection_domain = this_cp->pool_holder()->protection_domain();
Handle h_prot (current, protection_domain);
Handle h_loader (current, loader);
Klass* k = SystemDictionary::find_instance_klass(name, h_loader, h_prot);
Klass* k = SystemDictionary::find_instance_klass(current, name, h_loader, h_prot);
// Avoid constant pool verification at a safepoint, as it takes the Module_lock.
if (k != NULL && current->is_Java_thread()) {

View file

@ -971,7 +971,7 @@ bool Method::is_klass_loaded_by_klass_index(int klass_index) const {
Symbol* klass_name = constants()->klass_name_at(klass_index);
Handle loader(thread, method_holder()->class_loader());
Handle prot (thread, method_holder()->protection_domain());
return SystemDictionary::find_instance_klass(klass_name, loader, prot) != NULL;
return SystemDictionary::find_instance_klass(thread, klass_name, loader, prot) != NULL;
} else {
return true;
}

View file

@ -1095,7 +1095,7 @@ JVM_ENTRY(jclass, JVM_FindLoadedClass(JNIEnv *env, jobject loader, jstring name)
// The Java level wrapper will perform the necessary security check allowing
// us to pass the NULL as the initiating class loader.
Handle h_loader(THREAD, JNIHandles::resolve(loader));
Klass* k = SystemDictionary::find_instance_or_array_klass(klass_name,
Klass* k = SystemDictionary::find_instance_or_array_klass(THREAD, klass_name,
h_loader,
Handle());
#if INCLUDE_CDS

View file

@ -958,10 +958,10 @@ Deoptimization::DeoptAction Deoptimization::_unloaded_action
template<typename CacheType>
class BoxCacheBase : public CHeapObj<mtCompiler> {
protected:
static InstanceKlass* find_cache_klass(Symbol* klass_name) {
ResourceMark rm;
static InstanceKlass* find_cache_klass(Thread* thread, Symbol* klass_name) {
ResourceMark rm(thread);
char* klass_name_str = klass_name->as_C_string();
InstanceKlass* ik = SystemDictionary::find_instance_klass(klass_name, Handle(), Handle());
InstanceKlass* ik = SystemDictionary::find_instance_klass(thread, klass_name, Handle(), Handle());
guarantee(ik != NULL, "%s must be loaded", klass_name_str);
guarantee(ik->is_initialized(), "%s must be initialized", klass_name_str);
CacheType::compute_offsets(ik);
@ -976,7 +976,7 @@ template<typename PrimitiveType, typename CacheType, typename BoxType> class Box
protected:
static BoxCache<PrimitiveType, CacheType, BoxType> *_singleton;
BoxCache(Thread* thread) {
InstanceKlass* ik = BoxCacheBase<CacheType>::find_cache_klass(CacheType::symbol());
InstanceKlass* ik = BoxCacheBase<CacheType>::find_cache_klass(thread, CacheType::symbol());
objArrayOop cache = CacheType::cache(ik);
assert(cache->length() > 0, "Empty cache");
_low = BoxType::value(cache->obj_at(0));
@ -1032,7 +1032,7 @@ class BooleanBoxCache : public BoxCacheBase<java_lang_Boolean> {
protected:
static BooleanBoxCache *_singleton;
BooleanBoxCache(Thread *thread) {
InstanceKlass* ik = find_cache_klass(java_lang_Boolean::symbol());
InstanceKlass* ik = find_cache_klass(thread, java_lang_Boolean::symbol());
_true_cache = JNIHandles::make_global(Handle(thread, java_lang_Boolean::get_TRUE(ik)));
_false_cache = JNIHandles::make_global(Handle(thread, java_lang_Boolean::get_FALSE(ik)));
}

View file

@ -24,7 +24,6 @@
#include "precompiled.hpp"
#include "classfile/classLoaderDataGraph.hpp"
#include "classfile/dictionary.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "code/codeCache.hpp"
@ -559,13 +558,6 @@ public:
}
}
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_SYSTEM_DICTIONARY_RESIZE)) {
if (Dictionary::does_any_dictionary_needs_resizing()) {
Tracer t("resizing system dictionaries");
ClassLoaderDataGraph::resize_dictionaries();
}
}
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING)) {
if (_do_lazy_roots) {
Tracer t("lazy partial thread root processing");

View file

@ -74,7 +74,6 @@ class SafepointSynchronize : AllStatic {
SAFEPOINT_CLEANUP_UPDATE_INLINE_CACHES,
SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH,
SAFEPOINT_CLEANUP_STRING_TABLE_REHASH,
SAFEPOINT_CLEANUP_SYSTEM_DICTIONARY_RESIZE,
SAFEPOINT_CLEANUP_REQUEST_OOPSTORAGE_CLEANUP,
// Leave this one last.
SAFEPOINT_CLEANUP_NUM_TASKS

View file

@ -507,7 +507,7 @@ Klass* SignatureStream::as_klass(Handle class_loader, Handle protection_domain,
} else if (failure_mode == CachedOrNull) {
NoSafepointVerifier nsv; // no loading, now, we mean it!
assert(!HAS_PENDING_EXCEPTION, "");
k = SystemDictionary::find_instance_klass(name, class_loader, protection_domain);
k = SystemDictionary::find_instance_klass(THREAD, name, class_loader, protection_domain);
// SD::find does not trigger loading, so there should be no throws
// Still, bad things can happen, so we CHECK_NULL and ask callers
// to do likewise.

View file

@ -373,7 +373,7 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) {
// Get the Java runtime name, version, and vendor info after java.lang.System is initialized.
// Some values are actually configure-time constants but some can be set via the jlink tool and
// so must be read dynamically. We treat them all the same.
InstanceKlass* ik = SystemDictionary::find_instance_klass(vmSymbols::java_lang_VersionProps(),
InstanceKlass* ik = SystemDictionary::find_instance_klass(THREAD, vmSymbols::java_lang_VersionProps(),
Handle(), Handle());
{
ResourceMark rm(main_thread);

View file

@ -166,12 +166,6 @@ static const size_t DEFAULT_TABLE_SIZE = 2048;
static const size_t MAX_SIZE = 24;
static volatile bool _has_work = false;
static size_t ceil_log2(size_t value) {
size_t ret;
for (ret = 1; ((size_t)1 << ret) < value; ++ret);
return ret;
}
class FinalizerEntryLookupResult {
private:
FinalizerEntry* _result;

View file

@ -80,12 +80,6 @@ class ThreadIdTableConfig : public AllStatic {
}
};
static size_t ceil_log2(size_t val) {
size_t ret;
for (ret = 1; ((size_t)1 << ret) < val; ++ret);
return ret;
}
// Lazily creates the table and populates it with the given
// thread list
void ThreadIdTable::lazy_initialize(const ThreadsList *threads) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1229,7 +1229,11 @@ inline TableStatistics ConcurrentHashTable<CONFIG, F>::
summary.add((double)count);
}
if (_stats_rate == nullptr) {
return TableStatistics(summary, literal_bytes, sizeof(Bucket), sizeof(Node));
} else {
return TableStatistics(*_stats_rate, summary, literal_bytes, sizeof(Bucket), sizeof(Node));
}
}
template <typename CONFIG, MEMFLAGS F>

View file

@ -1133,7 +1133,6 @@ inline intx byte_size(void* from, void* to) {
return (address)to - (address)from;
}
// Pack and extract shorts to/from ints:
inline int extract_low_short_from_int(jint x) {

View file

@ -263,5 +263,4 @@ template class Hashtable<InstanceKlass*, mtClass>;
template class Hashtable<WeakHandle, mtClass>;
template class Hashtable<WeakHandle, mtServiceability>;
template void BasicHashtable<mtClass>::verify_table<DictionaryEntry>(char const*);
template void BasicHashtable<mtClass>::verify_table<ProtectionDomainCacheEntry>(char const*);

View file

@ -120,4 +120,12 @@ inline T next_power_of_2(T value) {
return round_up_power_of_2(value + 1);
}
// Find log2 value greater than this input
template <typename T, ENABLE_IF(std::is_integral<T>::value)>
inline T ceil_log2(T value) {
T ret;
for (ret = 1; ((T)1 << ret) < value; ++ret);
return ret;
}
#endif // SHARE_UTILITIES_POWEROFTWO_HPP

View file

@ -132,7 +132,7 @@ public class TestResize {
// -Xlog:safepoint+cleanup will print out cleanup details at safepoint
// that will allow us to detect if the system dictionary resized.
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintClassLoaderDataGraphAtExit",
"-Xlog:safepoint+cleanup",
"-Xlog:safepoint+cleanup,class+loader+data",
"TriggerResize",
String.valueOf(CLASSES_TO_LOAD));
analyzeOutputOn(pb);

View file

@ -0,0 +1,155 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Test of diagnostic command VM.systemdictionary which prints dictionary stats
* @library /test/lib
* @modules java.base/jdk.internal.misc
* jdk.compiler
* jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng DictionaryStatsTest
*/
import org.testng.Assert;
import org.testng.annotations.Test;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.dcmd.CommandExecutor;
import jdk.test.lib.dcmd.JMXExecutor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.lang.ref.Reference;
public class DictionaryStatsTest {
// Expecting some output like:
// System Dictionary for 'TestClassLoader' @10ba88b9 class loader statistics:
// Number of buckets : 128 = 1024 bytes, each 8
// Number of entries : 6 = 96 bytes, each 16
// Number of literals : 6 = 96 bytes, avg 16.000
// Total footprint : = 1216 bytes
// Average bucket size : 0.047
// Variance of bucket size : 0.045
// Std. dev. of bucket size: 0.211
// Maximum bucket size : 1
public void run(CommandExecutor executor) throws ClassNotFoundException {
ClassLoader named_cl = new TestClassLoader("TestClassLoader", null);
Class<?> c2 = Class.forName("TestClass2", true, named_cl);
if (c2.getClassLoader() != named_cl) {
Assert.fail("TestClass defined by wrong classloader: " + c2.getClassLoader());
}
// First test: simple output, no classes displayed
OutputAnalyzer output = executor.execute("VM.systemdictionary");
output.shouldContain("System Dictionary for 'bootstrap'");
output.shouldMatch("System Dictionary for 'TestClassLoader'");
output.shouldContain("class loader statistics:");
output.shouldContain("Number of buckets");
output.shouldContain("Number of entries");
output.shouldContain("Number of literals");
output.shouldContain("Total footprint");
output.shouldContain("Average bucket size");
output.shouldContain("Variance of bucket size");
output.shouldContain("Std. dev. of bucket size");
output.shouldContain("Maximum bucket size");
// what is this?
Reference.reachabilityFence(named_cl);
}
static class TestClassLoader extends ClassLoader {
public TestClassLoader() {
super();
}
public TestClassLoader(String name, ClassLoader parent) {
super(name, parent);
}
public static final String CLASS_NAME = "TestClass2";
static ByteBuffer readClassFile(String name)
{
File f = new File(System.getProperty("test.classes", "."),
name);
try (FileInputStream fin = new FileInputStream(f);
FileChannel fc = fin.getChannel())
{
return fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
} catch (IOException e) {
Assert.fail("Can't open file: " + name, e);
}
/* Will not reach here as Assert.fail() throws exception */
return null;
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class<?> c;
if (!CLASS_NAME.equals(name)) {
c = super.loadClass(name, resolve);
} else {
// should not delegate to the system class loader
c = findClass(name);
if (resolve) {
resolveClass(c);
}
}
return c;
}
protected Class<?> findClass(String name)
throws ClassNotFoundException
{
if (!CLASS_NAME.equals(name)) {
throw new ClassNotFoundException("Unexpected class: " + name);
}
return defineClass(name, readClassFile(name + ".class"), null);
}
}
@Test
public void jmx() throws ClassNotFoundException {
run(new JMXExecutor());
}
}
class TestClass2 {
static {
Runnable r = () -> System.out.println("Hello");
r.run();
}
}