mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 09:34:38 +02:00
8292680: Convert Dictionary to ConcurrentHashTable
Reviewed-by: rehn, hseigel
This commit is contained in:
parent
2fe0ce0148
commit
4f50316a1a
30 changed files with 436 additions and 356 deletions
|
@ -376,7 +376,7 @@ ciInstance* ciEnv::get_or_create_exception(jobject& handle, Symbol* name) {
|
||||||
VM_ENTRY_MARK;
|
VM_ENTRY_MARK;
|
||||||
if (handle == NULL) {
|
if (handle == NULL) {
|
||||||
// Cf. universe.cpp, creation of Universe::_null_ptr_exception_instance.
|
// 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;
|
jobject objh = NULL;
|
||||||
if (ik != NULL) {
|
if (ik != NULL) {
|
||||||
oop obj = ik->allocate_instance(THREAD);
|
oop obj = ik->allocate_instance(THREAD);
|
||||||
|
@ -529,7 +529,7 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
|
||||||
if (!require_local) {
|
if (!require_local) {
|
||||||
kls = SystemDictionary::find_constrained_instance_or_array_klass(current, sym, loader);
|
kls = SystemDictionary::find_constrained_instance_or_array_klass(current, sym, loader);
|
||||||
} else {
|
} 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;
|
found_klass = kls;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
|
||||||
: _next_klass(NULL) {
|
: _next_klass(NULL) {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
||||||
|
|
|
@ -104,8 +104,6 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||||
static void print_dictionary(outputStream* st);
|
static void print_dictionary(outputStream* st);
|
||||||
static void print_table_statistics(outputStream* st);
|
static void print_table_statistics(outputStream* st);
|
||||||
|
|
||||||
static int resize_dictionaries();
|
|
||||||
|
|
||||||
static bool has_metaspace_oom() { return _metaspace_oom; }
|
static bool has_metaspace_oom() { return _metaspace_oom; }
|
||||||
static void set_metaspace_oom(bool value) { _metaspace_oom = value; }
|
static void set_metaspace_oom(bool value) { _metaspace_oom = value; }
|
||||||
|
|
||||||
|
|
|
@ -44,94 +44,69 @@
|
||||||
#include "runtime/javaCalls.hpp"
|
#include "runtime/javaCalls.hpp"
|
||||||
#include "runtime/mutexLocker.hpp"
|
#include "runtime/mutexLocker.hpp"
|
||||||
#include "runtime/safepointVerifiers.hpp"
|
#include "runtime/safepointVerifiers.hpp"
|
||||||
|
#include "utilities/concurrentHashTable.inline.hpp"
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/hashtable.inline.hpp"
|
#include "utilities/tableStatistics.hpp"
|
||||||
|
|
||||||
// Optimization: if any dictionary needs resizing, we set this flag,
|
// 2^24 is max size, like StringTable.
|
||||||
// so that we don't have to walk all dictionaries to check if any actually
|
const size_t END_SIZE = 24;
|
||||||
// needs resizing, which is costly to do at Safepoint.
|
// If a chain gets to 100 something might be wrong
|
||||||
bool Dictionary::_some_dictionary_needs_resizing = false;
|
const size_t REHASH_LEN = 100;
|
||||||
|
|
||||||
Dictionary::Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable)
|
Dictionary::Dictionary(ClassLoaderData* loader_data, size_t table_size, bool resizable)
|
||||||
: Hashtable<InstanceKlass*, mtClass>(table_size, (int)sizeof(DictionaryEntry)),
|
: _resizable(resizable), _number_of_entries(0), _loader_data(loader_data) {
|
||||||
_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
|
||||||
Dictionary::Dictionary(ClassLoaderData* loader_data,
|
size_t current_size = ((size_t)1) << start_size_log_2;
|
||||||
int table_size, HashtableBucket<mtClass>* t,
|
log_info(class, loader, data)("Dictionary start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
|
||||||
int number_of_entries, bool resizable)
|
current_size, start_size_log_2);
|
||||||
: Hashtable<InstanceKlass*, mtClass>(table_size, (int)sizeof(DictionaryEntry), t, number_of_entries),
|
_table = new ConcurrentTable(start_size_log_2, END_SIZE, REHASH_LEN);
|
||||||
_resizable(resizable), _needs_resizing(false), _loader_data(loader_data) {
|
}
|
||||||
};
|
|
||||||
|
|
||||||
Dictionary::~Dictionary() {
|
Dictionary::~Dictionary() {
|
||||||
DictionaryEntry* probe = NULL;
|
// This deletes the table and all the nodes, by calling free_node in Config.
|
||||||
for (int index = 0; index < table_size(); index++) {
|
delete _table;
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DictionaryEntry* Dictionary::new_entry(unsigned int hash, InstanceKlass* klass) {
|
uintx Dictionary::Config::get_hash(Value const& value, bool* is_dead) {
|
||||||
DictionaryEntry* entry = (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::new_entry(hash, klass);
|
return value->instance_klass()->name()->identity_hash();
|
||||||
entry->release_set_pd_set(NULL);
|
|
||||||
assert(klass->is_instance_klass(), "Must be");
|
|
||||||
return entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// avoid recursion when deleting linked list
|
||||||
// pd_set is accessed during a safepoint.
|
// pd_set is accessed during a safepoint.
|
||||||
// This doesn't require a lock because nothing is reading this
|
// This doesn't require a lock because nothing is reading this
|
||||||
// entry anymore. The ClassLoader is dead.
|
// entry anymore. The ClassLoader is dead.
|
||||||
while (entry->pd_set_acquire() != NULL) {
|
while (pd_set_acquire() != NULL) {
|
||||||
ProtectionDomainEntry* to_delete = entry->pd_set_acquire();
|
ProtectionDomainEntry* to_delete = pd_set_acquire();
|
||||||
entry->release_set_pd_set(to_delete->next_acquire());
|
release_set_pd_set(to_delete->next_acquire());
|
||||||
delete to_delete;
|
delete to_delete;
|
||||||
}
|
}
|
||||||
BasicHashtable<mtClass>::free_entry(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int _resize_load_trigger = 5; // load factor that will trigger the resize
|
const int _resize_load_trigger = 5; // load factor that will trigger the resize
|
||||||
|
|
||||||
bool Dictionary::does_any_dictionary_needs_resizing() {
|
int Dictionary::table_size() const {
|
||||||
return Dictionary::_some_dictionary_needs_resizing;
|
return 1 << _table->get_size_log2(Thread::current());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dictionary::check_if_needs_resize() {
|
bool Dictionary::check_if_needs_resize() {
|
||||||
if (_resizable == true) {
|
return (_resizable &&
|
||||||
if (number_of_entries() > (_resize_load_trigger*table_size())) {
|
(_number_of_entries > (_resize_load_trigger * table_size())) &&
|
||||||
_needs_resizing = true;
|
!_table->is_max_size_reached());
|
||||||
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 DictionaryEntry::is_valid_protection_domain(Handle protection_domain) {
|
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
|
// Just the classes from defining class loaders
|
||||||
void Dictionary::classes_do(void f(InstanceKlass*)) {
|
void Dictionary::classes_do(void f(InstanceKlass*)) {
|
||||||
for (int index = 0; index < table_size(); index++) {
|
auto doit = [&] (DictionaryEntry** value) {
|
||||||
for (DictionaryEntry* probe = bucket(index);
|
InstanceKlass* k = (*value)->instance_klass();
|
||||||
probe != NULL;
|
if (loader_data() == k->class_loader_data()) {
|
||||||
probe = probe->next()) {
|
f(k);
|
||||||
InstanceKlass* k = probe->instance_klass();
|
|
||||||
if (loader_data() == k->class_loader_data()) {
|
|
||||||
f(k);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Added for initialize_itable_for_klass to handle exceptions
|
_table->do_scan(Thread::current(), doit);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All classes, and their class loaders, including initiating class loaders
|
// All classes, and their class loaders, including initiating class loaders
|
||||||
void Dictionary::all_entries_do(KlassClosure* closure) {
|
void Dictionary::all_entries_do(KlassClosure* closure) {
|
||||||
for (int index = 0; index < table_size(); index++) {
|
auto all_doit = [&] (DictionaryEntry** value) {
|
||||||
for (DictionaryEntry* probe = bucket(index);
|
InstanceKlass* k = (*value)->instance_klass();
|
||||||
probe != NULL;
|
closure->do_klass(k);
|
||||||
probe = probe->next()) {
|
return true;
|
||||||
InstanceKlass* k = probe->instance_klass();
|
};
|
||||||
closure->do_klass(k);
|
|
||||||
}
|
_table->do_scan(Thread::current(), all_doit);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to scan and relocate the classes during CDS archive dump.
|
// Used to scan and relocate the classes during CDS archive dump.
|
||||||
void Dictionary::classes_do(MetaspaceClosure* it) {
|
void Dictionary::classes_do(MetaspaceClosure* it) {
|
||||||
Arguments::assert_is_dumping_archive();
|
Arguments::assert_is_dumping_archive();
|
||||||
for (int index = 0; index < table_size(); index++) {
|
|
||||||
for (DictionaryEntry* probe = bucket(index);
|
auto push = [&] (DictionaryEntry** value) {
|
||||||
probe != NULL;
|
InstanceKlass** k = (*value)->instance_klass_addr();
|
||||||
probe = probe->next()) {
|
it->push(k);
|
||||||
it->push(probe->klass_addr());
|
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.
|
// Add a loaded class to the dictionary.
|
||||||
// Readers of the SystemDictionary aren't always locked, so _buckets
|
void Dictionary::add_klass(JavaThread* current, Symbol* class_name,
|
||||||
// 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,
|
|
||||||
InstanceKlass* obj) {
|
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 != NULL, "adding NULL obj");
|
||||||
assert(obj->name() == class_name, "sanity check on name");
|
assert(obj->name() == class_name, "sanity check on name");
|
||||||
|
|
||||||
DictionaryEntry* entry = new_entry(hash, obj);
|
DictionaryEntry* entry = new DictionaryEntry(obj);
|
||||||
int index = hash_to_index(hash);
|
DictionaryLookup lookup(class_name);
|
||||||
add_entry(index, entry);
|
bool needs_rehashing, clean_hint;
|
||||||
check_if_needs_resize();
|
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(<);
|
||||||
|
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.
|
// 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).
|
// be updated in an MT-safe manner).
|
||||||
//
|
//
|
||||||
// Callers should be aware that an entry could be added just after
|
// 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.
|
// the table is read here, so the caller will not see the new entry.
|
||||||
DictionaryEntry* Dictionary::get_entry(int index, unsigned int hash,
|
// The entry may be accessed by the VM thread in verification.
|
||||||
|
DictionaryEntry* Dictionary::get_entry(Thread* current,
|
||||||
Symbol* class_name) {
|
Symbol* class_name) {
|
||||||
for (DictionaryEntry* entry = bucket(index);
|
DictionaryLookup lookup(class_name);
|
||||||
entry != NULL;
|
DictionaryEntry* result = nullptr;
|
||||||
entry = entry->next()) {
|
auto get = [&] (DictionaryEntry** value) {
|
||||||
if (entry->hash() == hash && entry->instance_klass()->name() == class_name) {
|
// function called if value is found so is never null
|
||||||
return entry;
|
result = (*value);
|
||||||
}
|
};
|
||||||
}
|
bool needs_rehashing = false;
|
||||||
return NULL;
|
_table->get(current, lookup, get, &needs_rehashing);
|
||||||
|
assert (!needs_rehashing, "should never need rehashing");
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
InstanceKlass* Dictionary::find(Thread* current, Symbol* name,
|
||||||
InstanceKlass* Dictionary::find(unsigned int hash, Symbol* name,
|
|
||||||
Handle protection_domain) {
|
Handle protection_domain) {
|
||||||
NoSafepointVerifier nsv;
|
NoSafepointVerifier nsv;
|
||||||
|
|
||||||
int index = hash_to_index(hash);
|
DictionaryEntry* entry = get_entry(current, name);
|
||||||
DictionaryEntry* entry = get_entry(index, hash, name);
|
|
||||||
if (entry != NULL && entry->is_valid_protection_domain(protection_domain)) {
|
if (entry != NULL && entry->is_valid_protection_domain(protection_domain)) {
|
||||||
return entry->instance_klass();
|
return entry->instance_klass();
|
||||||
} else {
|
} 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) {
|
Symbol* name) {
|
||||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||||
|
DictionaryEntry* entry = get_entry(current, name);
|
||||||
int index = hash_to_index(hash);
|
|
||||||
assert (index == index_for(name), "incorrect index?");
|
|
||||||
|
|
||||||
DictionaryEntry* entry = get_entry(index, hash, name);
|
|
||||||
return (entry != NULL) ? entry->instance_klass() : NULL;
|
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,
|
InstanceKlass* klass,
|
||||||
Handle protection_domain) {
|
Handle protection_domain) {
|
||||||
assert(java_lang_System::allow_security_manager(), "only needed if security manager allowed");
|
assert(java_lang_System::allow_security_manager(), "only needed if security manager allowed");
|
||||||
Symbol* klass_name = klass->name();
|
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(entry != NULL,"entry must be present, we just created it");
|
||||||
assert(protection_domain() != NULL,
|
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,
|
Symbol* name,
|
||||||
Handle protection_domain) {
|
Handle protection_domain) {
|
||||||
int index = hash_to_index(hash);
|
DictionaryEntry* entry = get_entry(current, name);
|
||||||
DictionaryEntry* entry = get_entry(index, hash, name);
|
|
||||||
return entry->is_valid_protection_domain(protection_domain);
|
return entry->is_valid_protection_domain(protection_domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dictionary::validate_protection_domain(unsigned int name_hash,
|
void Dictionary::validate_protection_domain(InstanceKlass* klass,
|
||||||
InstanceKlass* klass,
|
|
||||||
Handle class_loader,
|
Handle class_loader,
|
||||||
Handle protection_domain,
|
Handle protection_domain,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
|
@ -372,7 +349,7 @@ void Dictionary::validate_protection_domain(unsigned int name_hash,
|
||||||
assert(protection_domain() != NULL, "Should not call this");
|
assert(protection_domain() != NULL, "Should not call this");
|
||||||
|
|
||||||
if (!java_lang_System::allow_security_manager() ||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,8 +401,7 @@ void Dictionary::validate_protection_domain(unsigned int name_hash,
|
||||||
// and protection domain are expected to succeed.
|
// and protection domain are expected to succeed.
|
||||||
{
|
{
|
||||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
MutexLocker mu(THREAD, SystemDictionary_lock);
|
||||||
int d_index = hash_to_index(name_hash);
|
add_protection_domain(THREAD, klass,
|
||||||
add_protection_domain(d_index, name_hash, klass,
|
|
||||||
protection_domain);
|
protection_domain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,10 +418,8 @@ void Dictionary::clean_cached_protection_domains(GrowableArray<ProtectionDomainE
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < table_size(); index++) {
|
auto clean_entries = [&] (DictionaryEntry** value) {
|
||||||
for (DictionaryEntry* probe = bucket(index);
|
DictionaryEntry* probe = *value;
|
||||||
probe != NULL;
|
|
||||||
probe = probe->next()) {
|
|
||||||
Klass* e = probe->instance_klass();
|
Klass* e = probe->instance_klass();
|
||||||
|
|
||||||
ProtectionDomainEntry* current = probe->pd_set_acquire();
|
ProtectionDomainEntry* current = probe->pd_set_acquire();
|
||||||
|
@ -458,7 +432,7 @@ void Dictionary::clean_cached_protection_domains(GrowableArray<ProtectionDomainE
|
||||||
// Print out trace information
|
// Print out trace information
|
||||||
LogStream ls(lt);
|
LogStream ls(lt);
|
||||||
ls.print_cr("PD in set is not alive:");
|
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.print(" loading: "); probe->instance_klass()->print_value_on(&ls);
|
||||||
ls.cr();
|
ls.cr();
|
||||||
}
|
}
|
||||||
|
@ -477,8 +451,10 @@ void Dictionary::clean_cached_protection_domains(GrowableArray<ProtectionDomainE
|
||||||
current = current->next_acquire();
|
current = current->next_acquire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
_table->do_scan(Thread::current(), clean_entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DictionaryEntry::verify_protection_domain_set() {
|
void DictionaryEntry::verify_protection_domain_set() {
|
||||||
|
@ -505,7 +481,7 @@ void DictionaryEntry::print_count(outputStream *st) {
|
||||||
|
|
||||||
void Dictionary::print_size(outputStream* st) const {
|
void Dictionary::print_size(outputStream* st) const {
|
||||||
st->print_cr("Java dictionary (table_size=%d, classes=%d, resizable=%s)",
|
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 {
|
void Dictionary::print_on(outputStream* st) const {
|
||||||
|
@ -516,25 +492,29 @@ void Dictionary::print_on(outputStream* st) const {
|
||||||
print_size(st);
|
print_size(st);
|
||||||
st->print_cr("^ indicates that initiating loader is different from defining loader");
|
st->print_cr("^ indicates that initiating loader is different from defining loader");
|
||||||
|
|
||||||
for (int index = 0; index < table_size(); index++) {
|
auto printer = [&] (DictionaryEntry** entry) {
|
||||||
for (DictionaryEntry* probe = bucket(index);
|
DictionaryEntry* probe = *entry;
|
||||||
probe != NULL;
|
Klass* e = probe->instance_klass();
|
||||||
probe = probe->next()) {
|
bool is_defining_class =
|
||||||
Klass* e = probe->instance_klass();
|
(_loader_data == e->class_loader_data());
|
||||||
bool is_defining_class =
|
st->print(" %s%s", is_defining_class ? " " : "^", e->external_name());
|
||||||
(loader_data() == e->class_loader_data());
|
ClassLoaderData* cld = e->class_loader_data();
|
||||||
st->print("%4d: %s%s", index, is_defining_class ? " " : "^", e->external_name());
|
if (!_loader_data->is_the_null_class_loader_data()) {
|
||||||
ClassLoaderData* cld = e->class_loader_data();
|
// Class loader output for the dictionary for the null class loader data is
|
||||||
if (!loader_data()->is_the_null_class_loader_data()) {
|
// redundant and obvious.
|
||||||
// Class loader output for the dictionary for the null class loader data is
|
st->print(", ");
|
||||||
// redundant and obvious.
|
cld->print_value_on(st);
|
||||||
st->print(", ");
|
st->print(", ");
|
||||||
cld->print_value_on(st);
|
probe->print_count(st);
|
||||||
st->print(", ");
|
|
||||||
probe->print_count(st);
|
|
||||||
}
|
|
||||||
st->cr();
|
|
||||||
}
|
}
|
||||||
|
st->cr();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (SafepointSynchronize::is_at_safepoint()) {
|
||||||
|
_table->do_safepoint_scan(printer);
|
||||||
|
} else {
|
||||||
|
_table->do_scan(Thread::current(), printer);
|
||||||
}
|
}
|
||||||
tty->cr();
|
tty->cr();
|
||||||
}
|
}
|
||||||
|
@ -548,7 +528,7 @@ void DictionaryEntry::verify() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dictionary::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();
|
ClassLoaderData* cld = loader_data();
|
||||||
// class loader must be present; a null class loader is the
|
// 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()),
|
(cld->is_the_null_class_loader_data() || cld->class_loader_no_keepalive()->is_instance()),
|
||||||
"checking type of class_loader");
|
"checking type of class_loader");
|
||||||
|
|
||||||
ResourceMark rm;
|
auto verifier = [&] (DictionaryEntry** val) {
|
||||||
stringStream tempst;
|
(*val)->verify();
|
||||||
tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id());
|
return true;
|
||||||
verify_table<DictionaryEntry>(tempst.as_string());
|
};
|
||||||
|
|
||||||
|
_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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#include "oops/instanceKlass.hpp"
|
#include "oops/instanceKlass.hpp"
|
||||||
#include "oops/oop.hpp"
|
#include "oops/oop.hpp"
|
||||||
#include "oops/oopHandle.hpp"
|
#include "oops/oopHandle.hpp"
|
||||||
#include "utilities/hashtable.hpp"
|
#include "utilities/concurrentHashTable.hpp"
|
||||||
#include "utilities/ostream.hpp"
|
#include "utilities/ostream.hpp"
|
||||||
|
|
||||||
class DictionaryEntry;
|
class DictionaryEntry;
|
||||||
|
@ -38,77 +38,68 @@ template <typename T> class GrowableArray;
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// The data structure for the class loader data dictionaries.
|
// The data structure for the class loader data dictionaries.
|
||||||
|
|
||||||
class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
|
class DictionaryEntry;
|
||||||
friend class VMStructs;
|
|
||||||
|
|
||||||
static bool _some_dictionary_needs_resizing;
|
class Dictionary : public CHeapObj<mtClass> {
|
||||||
bool _resizable;
|
bool _resizable;
|
||||||
bool _needs_resizing;
|
int _number_of_entries;
|
||||||
void check_if_needs_resize();
|
|
||||||
|
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; // backpointer to owning loader
|
||||||
ClassLoaderData* loader_data() const { return _loader_data; }
|
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:
|
public:
|
||||||
Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable = false);
|
Dictionary(ClassLoaderData* loader_data, size_t table_size, bool resizable = false);
|
||||||
Dictionary(ClassLoaderData* loader_data, int table_size, HashtableBucket<mtClass>* t, int number_of_entries, bool resizable = false);
|
|
||||||
~Dictionary();
|
~Dictionary();
|
||||||
|
|
||||||
static bool does_any_dictionary_needs_resizing();
|
void add_klass(JavaThread* current, Symbol* class_name, InstanceKlass* obj);
|
||||||
bool resize_if_needed();
|
|
||||||
|
|
||||||
void add_klass(unsigned int hash, Symbol* class_name, InstanceKlass* obj);
|
InstanceKlass* find_class(Thread* current, Symbol* name);
|
||||||
|
|
||||||
InstanceKlass* find_class(unsigned int hash, Symbol* name);
|
|
||||||
|
|
||||||
void classes_do(void f(InstanceKlass*));
|
void classes_do(void f(InstanceKlass*));
|
||||||
void classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
|
|
||||||
void all_entries_do(KlassClosure* closure);
|
void all_entries_do(KlassClosure* closure);
|
||||||
void classes_do(MetaspaceClosure* it);
|
void classes_do(MetaspaceClosure* it);
|
||||||
|
|
||||||
void clean_cached_protection_domains(GrowableArray<ProtectionDomainEntry*>* delete_list);
|
void clean_cached_protection_domains(GrowableArray<ProtectionDomainEntry*>* delete_list);
|
||||||
|
|
||||||
// Protection domains
|
// Protection domains
|
||||||
InstanceKlass* find(unsigned int hash, Symbol* name, Handle protection_domain);
|
InstanceKlass* find(Thread* current, Symbol* name, Handle protection_domain);
|
||||||
void validate_protection_domain(unsigned int name_hash,
|
void validate_protection_domain(InstanceKlass* klass,
|
||||||
InstanceKlass* klass,
|
|
||||||
Handle class_loader,
|
Handle class_loader,
|
||||||
Handle protection_domain,
|
Handle protection_domain,
|
||||||
TRAPS);
|
TRAPS);
|
||||||
|
|
||||||
|
void print_table_statistics(outputStream* st, const char* table_name);
|
||||||
|
|
||||||
void print_on(outputStream* st) const;
|
void print_on(outputStream* st) const;
|
||||||
void print_size(outputStream* st) const;
|
void print_size(outputStream* st) const;
|
||||||
void verify();
|
void verify();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DictionaryEntry* new_entry(unsigned int hash, InstanceKlass* klass);
|
bool is_valid_protection_domain(JavaThread* current, Symbol* name,
|
||||||
|
|
||||||
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,
|
|
||||||
Handle protection_domain);
|
Handle protection_domain);
|
||||||
void add_protection_domain(int index, unsigned int hash,
|
void add_protection_domain(JavaThread* current, InstanceKlass* klass,
|
||||||
InstanceKlass* klass,
|
|
||||||
Handle protection_domain);
|
Handle protection_domain);
|
||||||
};
|
};
|
||||||
|
|
||||||
// An entry in the class loader data dictionaries, this describes a class as
|
// 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> {
|
class DictionaryEntry : public CHeapObj<mtClass> {
|
||||||
friend class VMStructs;
|
|
||||||
private:
|
private:
|
||||||
// Contains the set of approved protection domains that can access
|
// Contains the set of approved protection domains that can access
|
||||||
// this dictionary entry.
|
// 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
|
// It is essentially a cache to avoid repeated Java up-calls to
|
||||||
// ClassLoader.checkPackageAccess().
|
// ClassLoader.checkPackageAccess().
|
||||||
//
|
//
|
||||||
|
InstanceKlass* _instance_klass;
|
||||||
ProtectionDomainEntry* volatile _pd_set;
|
ProtectionDomainEntry* volatile _pd_set;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
DictionaryEntry(InstanceKlass* instance_klass);
|
||||||
|
~DictionaryEntry();
|
||||||
|
|
||||||
// Tells whether a protection is in the approved set.
|
// Tells whether a protection is in the approved set.
|
||||||
bool contains_protection_domain(oop protection_domain) const;
|
bool contains_protection_domain(oop protection_domain) const;
|
||||||
// Adds a protection domain to the approved set.
|
// Adds a protection domain to the approved set.
|
||||||
void add_protection_domain(ClassLoaderData* loader_data, Handle protection_domain);
|
void add_protection_domain(ClassLoaderData* loader_data, Handle protection_domain);
|
||||||
|
|
||||||
InstanceKlass* instance_klass() const { return literal(); }
|
InstanceKlass* instance_klass() const { return _instance_klass; }
|
||||||
InstanceKlass** klass_addr() { return (InstanceKlass**)literal_addr(); }
|
InstanceKlass** instance_klass_addr() { return &_instance_klass; }
|
||||||
|
|
||||||
DictionaryEntry* next() const {
|
|
||||||
return (DictionaryEntry*)HashtableEntry<InstanceKlass*, mtClass>::next();
|
|
||||||
}
|
|
||||||
|
|
||||||
DictionaryEntry** next_addr() {
|
|
||||||
return (DictionaryEntry**)HashtableEntry<InstanceKlass*, mtClass>::next_addr();
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtectionDomainEntry* pd_set_acquire() const { return Atomic::load_acquire(&_pd_set); }
|
ProtectionDomainEntry* pd_set_acquire() const { return Atomic::load_acquire(&_pd_set); }
|
||||||
void release_set_pd_set(ProtectionDomainEntry* entry) { Atomic::release_store(&_pd_set, entry); }
|
void release_set_pd_set(ProtectionDomainEntry* entry) { Atomic::release_store(&_pd_set, entry); }
|
||||||
|
|
|
@ -454,6 +454,7 @@ void LoaderConstraintTable::merge_loader_constraints(Symbol* class_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoaderConstraintTable::verify() {
|
void LoaderConstraintTable::verify() {
|
||||||
|
Thread* thread = Thread::current();
|
||||||
auto check = [&] (Symbol*& key, ConstraintSet& set) {
|
auto check = [&] (Symbol*& key, ConstraintSet& set) {
|
||||||
// foreach constraint in the set, check the klass is in the dictionary or placeholder table.
|
// foreach constraint in the set, check the klass is in the dictionary or placeholder table.
|
||||||
int len = set.num_constraints();
|
int len = set.num_constraints();
|
||||||
|
@ -465,8 +466,7 @@ void LoaderConstraintTable::verify() {
|
||||||
Symbol* name = ik->name();
|
Symbol* name = ik->name();
|
||||||
ClassLoaderData* loader_data = ik->class_loader_data();
|
ClassLoaderData* loader_data = ik->class_loader_data();
|
||||||
Dictionary* dictionary = loader_data->dictionary();
|
Dictionary* dictionary = loader_data->dictionary();
|
||||||
unsigned int name_hash = dictionary->compute_hash(name);
|
InstanceKlass* k = dictionary->find_class(thread, name);
|
||||||
InstanceKlass* k = dictionary->find_class(name_hash, name);
|
|
||||||
if (k != NULL) {
|
if (k != NULL) {
|
||||||
// We found the class in the dictionary, so we should
|
// We found the class in the dictionary, so we should
|
||||||
// make sure that the Klass* matches what we already have.
|
// make sure that the Klass* matches what we already have.
|
||||||
|
|
|
@ -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() {
|
void StringTable::create_table() {
|
||||||
size_t start_size_log_2 = ceil_log2(StringTableSize);
|
size_t start_size_log_2 = ceil_log2(StringTableSize);
|
||||||
_current_size = ((size_t)1) << start_size_log_2;
|
_current_size = ((size_t)1) << start_size_log_2;
|
||||||
|
|
|
@ -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 () {
|
void SymbolTable::create_table () {
|
||||||
size_t start_size_log_2 = ceil_log2(SymbolTableSize);
|
size_t start_size_log_2 = ceil_log2(SymbolTableSize);
|
||||||
_current_size = ((size_t)1) << start_size_log_2;
|
_current_size = ((size_t)1) << start_size_log_2;
|
||||||
|
|
|
@ -284,8 +284,7 @@ void verify_dictionary_entry(Symbol* class_name, InstanceKlass* k) {
|
||||||
ClassLoaderData* loader_data = k->class_loader_data();
|
ClassLoaderData* loader_data = k->class_loader_data();
|
||||||
Dictionary* dictionary = loader_data->dictionary();
|
Dictionary* dictionary = loader_data->dictionary();
|
||||||
assert(class_name == k->name(), "Must be the same");
|
assert(class_name == k->name(), "Must be the same");
|
||||||
unsigned int name_hash = dictionary->compute_hash(class_name);
|
InstanceKlass* kk = dictionary->find_class(JavaThread::current(), class_name);
|
||||||
InstanceKlass* kk = dictionary->find_class(name_hash, class_name);
|
|
||||||
assert(kk == k, "should be present in dictionary");
|
assert(kk == k, "should be present in dictionary");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -431,13 +430,12 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name,
|
||||||
|
|
||||||
ClassLoaderData* loader_data = class_loader_data(class_loader);
|
ClassLoaderData* loader_data = class_loader_data(class_loader);
|
||||||
Dictionary* dictionary = loader_data->dictionary();
|
Dictionary* dictionary = loader_data->dictionary();
|
||||||
unsigned int name_hash = dictionary->compute_hash(class_name);
|
|
||||||
|
|
||||||
// can't throw error holding a lock
|
// can't throw error holding a lock
|
||||||
bool throw_circularity_error = false;
|
bool throw_circularity_error = false;
|
||||||
{
|
{
|
||||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
MutexLocker mu(THREAD, SystemDictionary_lock);
|
||||||
InstanceKlass* klassk = dictionary->find_class(name_hash, class_name);
|
InstanceKlass* klassk = dictionary->find_class(THREAD, class_name);
|
||||||
InstanceKlass* quicksuperk;
|
InstanceKlass* quicksuperk;
|
||||||
// To support parallel loading: if class is done loading, just return the superclass
|
// 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.
|
// 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
|
// For bootstrap and non-parallelCapable class loaders, check and wait for
|
||||||
// another thread to complete loading this class.
|
// another thread to complete loading this class.
|
||||||
InstanceKlass* SystemDictionary::handle_parallel_loading(JavaThread* current,
|
InstanceKlass* SystemDictionary::handle_parallel_loading(JavaThread* current,
|
||||||
unsigned int name_hash,
|
|
||||||
Symbol* name,
|
Symbol* name,
|
||||||
ClassLoaderData* loader_data,
|
ClassLoaderData* loader_data,
|
||||||
Handle lockObject,
|
Handle lockObject,
|
||||||
|
@ -602,7 +599,7 @@ InstanceKlass* SystemDictionary::handle_parallel_loading(JavaThread* current,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if classloading completed while we were waiting
|
// 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) {
|
if (check != NULL) {
|
||||||
// Klass is already loaded, so just return it
|
// Klass is already loaded, so just return it
|
||||||
return check;
|
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()));
|
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
|
||||||
ClassLoaderData* loader_data = register_loader(class_loader);
|
ClassLoaderData* loader_data = register_loader(class_loader);
|
||||||
Dictionary* dictionary = loader_data->dictionary();
|
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
|
// Do lookup to see if class already exists and the protection domain
|
||||||
// has the right access.
|
// has the right access.
|
||||||
// This call uses find which checks protection domain already matches
|
// This call uses find which checks protection domain already matches
|
||||||
// All subsequent calls use find_class, and set loaded_class so that
|
// 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.
|
// 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;
|
if (probe != NULL) return probe;
|
||||||
|
|
||||||
// Non-bootstrap class loaders will call out to class loader and
|
// 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
|
// Check again (after locking) if the class already exists in SystemDictionary
|
||||||
{
|
{
|
||||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
MutexLocker mu(THREAD, SystemDictionary_lock);
|
||||||
InstanceKlass* check = dictionary->find_class(name_hash, name);
|
InstanceKlass* check = dictionary->find_class(THREAD, name);
|
||||||
if (check != NULL) {
|
if (check != NULL) {
|
||||||
// InstanceKlass is already loaded, but we still need to check protection domain below.
|
// InstanceKlass is already loaded, but we still need to check protection domain below.
|
||||||
loaded_class = check;
|
loaded_class = check;
|
||||||
|
@ -728,7 +724,6 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
|
||||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
MutexLocker mu(THREAD, SystemDictionary_lock);
|
||||||
if (should_wait_for_loading(class_loader)) {
|
if (should_wait_for_loading(class_loader)) {
|
||||||
loaded_class = handle_parallel_loading(THREAD,
|
loaded_class = handle_parallel_loading(THREAD,
|
||||||
name_hash,
|
|
||||||
name,
|
name,
|
||||||
loader_data,
|
loader_data,
|
||||||
lockObject,
|
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
|
// Recheck if the class has been loaded for all class loader cases and
|
||||||
// add a LOAD_INSTANCE placeholder while holding the SystemDictionary_lock.
|
// add a LOAD_INSTANCE placeholder while holding the SystemDictionary_lock.
|
||||||
if (!throw_circularity_error && loaded_class == NULL) {
|
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) {
|
if (check != NULL) {
|
||||||
loaded_class = check;
|
loaded_class = check;
|
||||||
} else if (should_wait_for_loading(class_loader)) {
|
} 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) {
|
if (loaded_class == NULL) {
|
||||||
// Do actual loading
|
// 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) {
|
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
|
// Check if the protection domain is present it has the right access
|
||||||
if (protection_domain() != NULL) {
|
if (protection_domain() != NULL) {
|
||||||
// Verify protection domain. If it fails an exception is thrown
|
// 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;
|
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.
|
// unloading, when this class loader is no longer referenced.
|
||||||
//
|
//
|
||||||
// Callers should be aware that an entry could be added just after
|
// 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.
|
// 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 class_loader,
|
||||||
Handle protection_domain) {
|
Handle protection_domain) {
|
||||||
|
|
||||||
|
@ -828,13 +824,13 @@ InstanceKlass* SystemDictionary::find_instance_klass(Symbol* class_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary* dictionary = loader_data->dictionary();
|
Dictionary* dictionary = loader_data->dictionary();
|
||||||
unsigned int name_hash = dictionary->compute_hash(class_name);
|
return dictionary->find(current, class_name, protection_domain);
|
||||||
return dictionary->find(name_hash, class_name, protection_domain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for a loaded instance or array klass by name. Do not do any loading.
|
// Look for a loaded instance or array klass by name. Do not do any loading.
|
||||||
// return NULL in case of error.
|
// 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 class_loader,
|
||||||
Handle protection_domain) {
|
Handle protection_domain) {
|
||||||
Klass* k = NULL;
|
Klass* k = NULL;
|
||||||
|
@ -850,13 +846,13 @@ Klass* SystemDictionary::find_instance_or_array_klass(Symbol* class_name,
|
||||||
if (t != T_OBJECT) {
|
if (t != T_OBJECT) {
|
||||||
k = Universe::typeArrayKlassObj(t);
|
k = Universe::typeArrayKlassObj(t);
|
||||||
} else {
|
} 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) {
|
if (k != NULL) {
|
||||||
k = k->array_klass_or_null(ndims);
|
k = k->array_klass_or_null(ndims);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
k = find_instance_klass(class_name, class_loader, protection_domain);
|
k = find_instance_klass(current, class_name, class_loader, protection_domain);
|
||||||
}
|
}
|
||||||
return k;
|
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) {
|
if (!super_type->is_shared_unregistered_class() && super_type->class_loader_data() != NULL) {
|
||||||
// Check if the superclass is loaded by the current class_loader
|
// Check if the superclass is loaded by the current class_loader
|
||||||
Symbol* name = super_type->name();
|
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) {
|
if (check == super_type) {
|
||||||
return true;
|
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,
|
InstanceKlass* SystemDictionary::load_instance_class(Symbol* name,
|
||||||
Symbol* name,
|
|
||||||
Handle class_loader,
|
Handle class_loader,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
|
|
||||||
|
@ -1413,7 +1408,7 @@ InstanceKlass* SystemDictionary::load_instance_class(unsigned int name_hash,
|
||||||
if (loaded_class != NULL &&
|
if (loaded_class != NULL &&
|
||||||
loaded_class->class_loader() != class_loader()) {
|
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.
|
// Record dependency for non-parent delegation.
|
||||||
// This recording keeps the defining class loader of the klass (loaded_class) found
|
// 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
|
{ // Grabbing the Compile_lock prevents systemDictionary updates
|
||||||
// during compilations.
|
// during compilations.
|
||||||
MutexLocker mu(THREAD, Compile_lock);
|
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()) {
|
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
|
// which will require a token to perform the define class
|
||||||
Symbol* name_h = k->name();
|
Symbol* name_h = k->name();
|
||||||
Dictionary* dictionary = loader_data->dictionary();
|
Dictionary* dictionary = loader_data->dictionary();
|
||||||
unsigned int name_hash = dictionary->compute_hash(name_h);
|
check_constraints(k, class_loader, true, CHECK);
|
||||||
check_constraints(name_hash, k, class_loader, true, CHECK);
|
|
||||||
|
|
||||||
// Register class just loaded with class loader (placed in ArrayList)
|
// Register class just loaded with class loader (placed in ArrayList)
|
||||||
// Note we do this before updating the dictionary, as this can
|
// 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.
|
// Add to systemDictionary - so other classes can see it.
|
||||||
// Grabs and releases SystemDictionary_lock
|
// Grabs and releases SystemDictionary_lock
|
||||||
update_dictionary(name_hash, k, class_loader);
|
update_dictionary(THREAD, k, class_loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify jvmti
|
// notify jvmti
|
||||||
|
@ -1534,14 +1528,12 @@ InstanceKlass* SystemDictionary::find_or_define_helper(Symbol* class_name, Handl
|
||||||
ClassLoaderData* loader_data = class_loader_data(class_loader);
|
ClassLoaderData* loader_data = class_loader_data(class_loader);
|
||||||
Dictionary* dictionary = loader_data->dictionary();
|
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
|
// Hold SD lock around find_class and placeholder creation for DEFINE_CLASS
|
||||||
{
|
{
|
||||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
MutexLocker mu(THREAD, SystemDictionary_lock);
|
||||||
// First check if class already defined
|
// First check if class already defined
|
||||||
if (is_parallelDefine(class_loader)) {
|
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) {
|
if (check != NULL) {
|
||||||
return check;
|
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);
|
PlaceholderTable::find_and_remove(name_h, loader_data, PlaceholderTable::DEFINE_CLASS, THREAD);
|
||||||
SystemDictionary_lock->notify_all();
|
SystemDictionary_lock->notify_all();
|
||||||
#ifdef ASSERT
|
#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");
|
assert(check != NULL, "definer missed recording success");
|
||||||
#endif
|
#endif
|
||||||
return ik;
|
return ik;
|
||||||
|
@ -1731,8 +1723,7 @@ void SystemDictionary::initialize(TRAPS) {
|
||||||
// if defining is true, then LinkageError if already in dictionary
|
// if defining is true, then LinkageError if already in dictionary
|
||||||
// if initiating loader, then ok if InstanceKlass matches existing entry
|
// if initiating loader, then ok if InstanceKlass matches existing entry
|
||||||
|
|
||||||
void SystemDictionary::check_constraints(unsigned int name_hash,
|
void SystemDictionary::check_constraints(InstanceKlass* k,
|
||||||
InstanceKlass* k,
|
|
||||||
Handle class_loader,
|
Handle class_loader,
|
||||||
bool defining,
|
bool defining,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
|
@ -1746,7 +1737,7 @@ void SystemDictionary::check_constraints(unsigned int name_hash,
|
||||||
|
|
||||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
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 (check != NULL) {
|
||||||
// If different InstanceKlass - duplicate class definition,
|
// If different InstanceKlass - duplicate class definition,
|
||||||
// else - ok, class loaded by a different thread in parallel.
|
// 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
|
// Update class loader data dictionary - done after check_constraint and add_to_hierarchy
|
||||||
// have been called.
|
// have been called.
|
||||||
void SystemDictionary::update_dictionary(unsigned int hash,
|
void SystemDictionary::update_dictionary(JavaThread* current,
|
||||||
InstanceKlass* k,
|
InstanceKlass* k,
|
||||||
Handle class_loader) {
|
Handle class_loader) {
|
||||||
// Compile_lock prevents systemDictionary updates during compilations
|
// Compile_lock prevents systemDictionary updates during compilations
|
||||||
|
@ -1803,9 +1794,9 @@ void SystemDictionary::update_dictionary(unsigned int hash,
|
||||||
|
|
||||||
// Make a new dictionary entry.
|
// Make a new dictionary entry.
|
||||||
Dictionary* dictionary = loader_data->dictionary();
|
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) {
|
if (sd_check == NULL) {
|
||||||
dictionary->add_klass(hash, name, k);
|
dictionary->add_klass(current, name, k);
|
||||||
}
|
}
|
||||||
SystemDictionary_lock->notify_all();
|
SystemDictionary_lock->notify_all();
|
||||||
}
|
}
|
||||||
|
@ -1821,7 +1812,7 @@ Klass* SystemDictionary::find_constrained_instance_or_array_klass(
|
||||||
// First see if it has been loaded directly.
|
// First see if it has been loaded directly.
|
||||||
// Force the protection domain to be null. (This removes protection checks.)
|
// Force the protection domain to be null. (This removes protection checks.)
|
||||||
Handle no_protection_domain;
|
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);
|
no_protection_domain);
|
||||||
if (klass != NULL)
|
if (klass != NULL)
|
||||||
return klass;
|
return klass;
|
||||||
|
@ -1881,17 +1872,15 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary* dictionary1 = loader_data1->dictionary();
|
Dictionary* dictionary1 = loader_data1->dictionary();
|
||||||
unsigned int name_hash1 = dictionary1->compute_hash(constraint_name);
|
|
||||||
|
|
||||||
Dictionary* dictionary2 = loader_data2->dictionary();
|
Dictionary* dictionary2 = loader_data2->dictionary();
|
||||||
unsigned int name_hash2 = dictionary2->compute_hash(constraint_name);
|
|
||||||
|
|
||||||
|
JavaThread* current = JavaThread::current();
|
||||||
{
|
{
|
||||||
MutexLocker mu_s(SystemDictionary_lock);
|
MutexLocker mu_s(SystemDictionary_lock);
|
||||||
InstanceKlass* klass1 = dictionary1->find_class(name_hash1, constraint_name);
|
InstanceKlass* klass1 = dictionary1->find_class(current, constraint_name);
|
||||||
InstanceKlass* klass2 = dictionary2->find_class(name_hash2, constraint_name);
|
InstanceKlass* klass2 = dictionary2->find_class(current, constraint_name);
|
||||||
bool result = LoaderConstraintTable::add_entry(constraint_name, klass1, class_loader1,
|
bool result = LoaderConstraintTable::add_entry(constraint_name, klass1, class_loader1,
|
||||||
klass2, class_loader2);
|
klass2, class_loader2);
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
if (Arguments::is_dumping_archive() && klass_being_linked != NULL &&
|
if (Arguments::is_dumping_archive() && klass_being_linked != NULL &&
|
||||||
!klass_being_linked->is_shared()) {
|
!klass_being_linked->is_shared()) {
|
||||||
|
|
|
@ -144,12 +144,13 @@ class SystemDictionary : AllStatic {
|
||||||
TRAPS);
|
TRAPS);
|
||||||
|
|
||||||
// Lookup an already loaded class. If not found NULL is returned.
|
// 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.
|
// Lookup an already loaded instance or array class.
|
||||||
// Do not make any queries to class loaders; consult only the cache.
|
// Do not make any queries to class loaders; consult only the cache.
|
||||||
// If not found NULL is returned.
|
// 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 class_loader,
|
||||||
Handle protection_domain);
|
Handle protection_domain);
|
||||||
|
|
||||||
|
@ -324,7 +325,6 @@ private:
|
||||||
Handle class_loader,
|
Handle class_loader,
|
||||||
Handle protection_domain, TRAPS);
|
Handle protection_domain, TRAPS);
|
||||||
static InstanceKlass* handle_parallel_loading(JavaThread* current,
|
static InstanceKlass* handle_parallel_loading(JavaThread* current,
|
||||||
unsigned int name_hash,
|
|
||||||
Symbol* name,
|
Symbol* name,
|
||||||
ClassLoaderData* loader_data,
|
ClassLoaderData* loader_data,
|
||||||
Handle lockObject,
|
Handle lockObject,
|
||||||
|
@ -335,8 +335,7 @@ private:
|
||||||
Handle class_loader,
|
Handle class_loader,
|
||||||
InstanceKlass* k, TRAPS);
|
InstanceKlass* k, TRAPS);
|
||||||
static InstanceKlass* load_instance_class_impl(Symbol* class_name, Handle class_loader, TRAPS);
|
static InstanceKlass* load_instance_class_impl(Symbol* class_name, Handle class_loader, TRAPS);
|
||||||
static InstanceKlass* load_instance_class(unsigned int name_hash,
|
static InstanceKlass* load_instance_class(Symbol* class_name,
|
||||||
Symbol* class_name,
|
|
||||||
Handle class_loader, TRAPS);
|
Handle class_loader, TRAPS);
|
||||||
|
|
||||||
static bool is_shared_class_visible(Symbol* class_name, InstanceKlass* ik,
|
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);
|
static Symbol* find_placeholder(Symbol* name, ClassLoaderData* loader_data);
|
||||||
|
|
||||||
// Class loader constraints
|
// Class loader constraints
|
||||||
static void check_constraints(unsigned int hash,
|
static void check_constraints(InstanceKlass* k, Handle loader,
|
||||||
InstanceKlass* k, Handle loader,
|
|
||||||
bool defining, TRAPS);
|
bool defining, TRAPS);
|
||||||
static void update_dictionary(unsigned int hash,
|
static void update_dictionary(JavaThread* current, InstanceKlass* k, Handle loader);
|
||||||
InstanceKlass* k, Handle loader);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_CLASSFILE_SYSTEMDICTIONARY_HPP
|
#endif // SHARE_CLASSFILE_SYSTEMDICTIONARY_HPP
|
||||||
|
|
|
@ -401,7 +401,6 @@ InstanceKlass* SystemDictionaryShared::find_or_load_shared_class(
|
||||||
THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
|
THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
|
||||||
ClassLoaderData *loader_data = register_loader(class_loader);
|
ClassLoaderData *loader_data = register_loader(class_loader);
|
||||||
Dictionary* dictionary = loader_data->dictionary();
|
Dictionary* dictionary = loader_data->dictionary();
|
||||||
unsigned int d_hash = dictionary->compute_hash(name);
|
|
||||||
|
|
||||||
// Note: currently, find_or_load_shared_class is called only from
|
// Note: currently, find_or_load_shared_class is called only from
|
||||||
// JVM_FindLoadedClass and used for PlatformClassLoader and AppClassLoader,
|
// 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");
|
assert(get_loader_lock_or_null(class_loader) == NULL, "ObjectLocker not required");
|
||||||
{
|
{
|
||||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
MutexLocker mu(THREAD, SystemDictionary_lock);
|
||||||
InstanceKlass* check = dictionary->find_class(d_hash, name);
|
InstanceKlass* check = dictionary->find_class(THREAD, name);
|
||||||
if (check != NULL) {
|
if (check != NULL) {
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,8 +247,7 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load
|
||||||
klass->restore_unshareable_info(loader_data, domain, NULL, THREAD);
|
klass->restore_unshareable_info(loader_data, domain, NULL, THREAD);
|
||||||
SystemDictionary::load_shared_class_misc(klass, loader_data);
|
SystemDictionary::load_shared_class_misc(klass, loader_data);
|
||||||
Dictionary* dictionary = loader_data->dictionary();
|
Dictionary* dictionary = loader_data->dictionary();
|
||||||
unsigned int hash = dictionary->compute_hash(klass->name());
|
dictionary->add_klass(THREAD, klass->name(), klass);
|
||||||
dictionary->add_klass(hash, klass->name(), klass);
|
|
||||||
SystemDictionary::add_to_hierarchy(klass);
|
SystemDictionary::add_to_hierarchy(klass);
|
||||||
assert(klass->is_loaded(), "Must be in at least loaded state");
|
assert(klass->is_loaded(), "Must be in at least loaded state");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
// This is a name from a signature. Strip off the trimmings.
|
||||||
// Call recursive to keep scope of strippedsym.
|
// Call recursive to keep scope of strippedsym.
|
||||||
TempNewSymbol strippedsym = Signature::strip_envelope(class_name);
|
TempNewSymbol strippedsym = Signature::strip_envelope(class_name);
|
||||||
resolved_klass = SystemDictionary::find_instance_klass(strippedsym,
|
resolved_klass = SystemDictionary::find_instance_klass(THREAD, strippedsym,
|
||||||
class_loader,
|
class_loader,
|
||||||
protection_domain);
|
protection_domain);
|
||||||
} else if (Signature::is_array(class_name)) {
|
} 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();
|
int ndim = ss.skip_array_prefix();
|
||||||
if (ss.type() == T_OBJECT) {
|
if (ss.type() == T_OBJECT) {
|
||||||
Symbol* strippedsym = ss.as_symbol();
|
Symbol* strippedsym = ss.as_symbol();
|
||||||
resolved_klass = SystemDictionary::find_instance_klass(strippedsym,
|
resolved_klass = SystemDictionary::find_instance_klass(THREAD, strippedsym,
|
||||||
class_loader,
|
class_loader,
|
||||||
protection_domain);
|
protection_domain);
|
||||||
if (!resolved_klass.is_null()) {
|
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);
|
resolved_klass = TypeArrayKlass::cast(Universe::typeArrayKlassObj(ss.type()))->array_klass(ndim, CHECK_NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resolved_klass = SystemDictionary::find_instance_klass(class_name,
|
resolved_klass = SystemDictionary::find_instance_klass(THREAD, class_name,
|
||||||
class_loader,
|
class_loader,
|
||||||
protection_domain);
|
protection_domain);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1656,7 +1656,7 @@ Klass* JVMCIRuntime::get_klass_by_name_impl(Klass*& accessing_klass,
|
||||||
if (!require_local) {
|
if (!require_local) {
|
||||||
found_klass = SystemDictionary::find_constrained_instance_or_array_klass(THREAD, sym, loader);
|
found_klass = SystemDictionary::find_constrained_instance_or_array_klass(THREAD, sym, loader);
|
||||||
} else {
|
} else {
|
||||||
found_klass = SystemDictionary::find_instance_or_array_klass(sym, loader, domain);
|
found_klass = SystemDictionary::find_instance_or_array_klass(THREAD, sym, loader, domain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
oop protection_domain = this_cp->pool_holder()->protection_domain();
|
||||||
Handle h_prot (current, protection_domain);
|
Handle h_prot (current, protection_domain);
|
||||||
Handle h_loader (current, loader);
|
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.
|
// Avoid constant pool verification at a safepoint, as it takes the Module_lock.
|
||||||
if (k != NULL && current->is_Java_thread()) {
|
if (k != NULL && current->is_Java_thread()) {
|
||||||
|
|
|
@ -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);
|
Symbol* klass_name = constants()->klass_name_at(klass_index);
|
||||||
Handle loader(thread, method_holder()->class_loader());
|
Handle loader(thread, method_holder()->class_loader());
|
||||||
Handle prot (thread, method_holder()->protection_domain());
|
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 {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1095,9 +1095,9 @@ JVM_ENTRY(jclass, JVM_FindLoadedClass(JNIEnv *env, jobject loader, jstring name)
|
||||||
// The Java level wrapper will perform the necessary security check allowing
|
// The Java level wrapper will perform the necessary security check allowing
|
||||||
// us to pass the NULL as the initiating class loader.
|
// us to pass the NULL as the initiating class loader.
|
||||||
Handle h_loader(THREAD, JNIHandles::resolve(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,
|
h_loader,
|
||||||
Handle());
|
Handle());
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
if (k == NULL) {
|
if (k == NULL) {
|
||||||
// If the class is not already loaded, try to see if it's in the shared
|
// If the class is not already loaded, try to see if it's in the shared
|
||||||
|
|
|
@ -958,10 +958,10 @@ Deoptimization::DeoptAction Deoptimization::_unloaded_action
|
||||||
template<typename CacheType>
|
template<typename CacheType>
|
||||||
class BoxCacheBase : public CHeapObj<mtCompiler> {
|
class BoxCacheBase : public CHeapObj<mtCompiler> {
|
||||||
protected:
|
protected:
|
||||||
static InstanceKlass* find_cache_klass(Symbol* klass_name) {
|
static InstanceKlass* find_cache_klass(Thread* thread, Symbol* klass_name) {
|
||||||
ResourceMark rm;
|
ResourceMark rm(thread);
|
||||||
char* klass_name_str = klass_name->as_C_string();
|
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 != NULL, "%s must be loaded", klass_name_str);
|
||||||
guarantee(ik->is_initialized(), "%s must be initialized", klass_name_str);
|
guarantee(ik->is_initialized(), "%s must be initialized", klass_name_str);
|
||||||
CacheType::compute_offsets(ik);
|
CacheType::compute_offsets(ik);
|
||||||
|
@ -976,7 +976,7 @@ template<typename PrimitiveType, typename CacheType, typename BoxType> class Box
|
||||||
protected:
|
protected:
|
||||||
static BoxCache<PrimitiveType, CacheType, BoxType> *_singleton;
|
static BoxCache<PrimitiveType, CacheType, BoxType> *_singleton;
|
||||||
BoxCache(Thread* thread) {
|
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);
|
objArrayOop cache = CacheType::cache(ik);
|
||||||
assert(cache->length() > 0, "Empty cache");
|
assert(cache->length() > 0, "Empty cache");
|
||||||
_low = BoxType::value(cache->obj_at(0));
|
_low = BoxType::value(cache->obj_at(0));
|
||||||
|
@ -1032,7 +1032,7 @@ class BooleanBoxCache : public BoxCacheBase<java_lang_Boolean> {
|
||||||
protected:
|
protected:
|
||||||
static BooleanBoxCache *_singleton;
|
static BooleanBoxCache *_singleton;
|
||||||
BooleanBoxCache(Thread *thread) {
|
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)));
|
_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)));
|
_false_cache = JNIHandles::make_global(Handle(thread, java_lang_Boolean::get_FALSE(ik)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderDataGraph.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "code/codeCache.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 (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING)) {
|
||||||
if (_do_lazy_roots) {
|
if (_do_lazy_roots) {
|
||||||
Tracer t("lazy partial thread root processing");
|
Tracer t("lazy partial thread root processing");
|
||||||
|
|
|
@ -74,7 +74,6 @@ class SafepointSynchronize : AllStatic {
|
||||||
SAFEPOINT_CLEANUP_UPDATE_INLINE_CACHES,
|
SAFEPOINT_CLEANUP_UPDATE_INLINE_CACHES,
|
||||||
SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH,
|
SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH,
|
||||||
SAFEPOINT_CLEANUP_STRING_TABLE_REHASH,
|
SAFEPOINT_CLEANUP_STRING_TABLE_REHASH,
|
||||||
SAFEPOINT_CLEANUP_SYSTEM_DICTIONARY_RESIZE,
|
|
||||||
SAFEPOINT_CLEANUP_REQUEST_OOPSTORAGE_CLEANUP,
|
SAFEPOINT_CLEANUP_REQUEST_OOPSTORAGE_CLEANUP,
|
||||||
// Leave this one last.
|
// Leave this one last.
|
||||||
SAFEPOINT_CLEANUP_NUM_TASKS
|
SAFEPOINT_CLEANUP_NUM_TASKS
|
||||||
|
|
|
@ -507,7 +507,7 @@ Klass* SignatureStream::as_klass(Handle class_loader, Handle protection_domain,
|
||||||
} else if (failure_mode == CachedOrNull) {
|
} else if (failure_mode == CachedOrNull) {
|
||||||
NoSafepointVerifier nsv; // no loading, now, we mean it!
|
NoSafepointVerifier nsv; // no loading, now, we mean it!
|
||||||
assert(!HAS_PENDING_EXCEPTION, "");
|
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
|
// SD::find does not trigger loading, so there should be no throws
|
||||||
// Still, bad things can happen, so we CHECK_NULL and ask callers
|
// Still, bad things can happen, so we CHECK_NULL and ask callers
|
||||||
// to do likewise.
|
// to do likewise.
|
||||||
|
|
|
@ -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.
|
// 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
|
// 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.
|
// 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());
|
Handle(), Handle());
|
||||||
{
|
{
|
||||||
ResourceMark rm(main_thread);
|
ResourceMark rm(main_thread);
|
||||||
|
|
|
@ -166,12 +166,6 @@ static const size_t DEFAULT_TABLE_SIZE = 2048;
|
||||||
static const size_t MAX_SIZE = 24;
|
static const size_t MAX_SIZE = 24;
|
||||||
static volatile bool _has_work = false;
|
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 {
|
class FinalizerEntryLookupResult {
|
||||||
private:
|
private:
|
||||||
FinalizerEntry* _result;
|
FinalizerEntry* _result;
|
||||||
|
|
|
@ -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
|
// Lazily creates the table and populates it with the given
|
||||||
// thread list
|
// thread list
|
||||||
void ThreadIdTable::lazy_initialize(const ThreadsList *threads) {
|
void ThreadIdTable::lazy_initialize(const ThreadsList *threads) {
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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);
|
summary.add((double)count);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TableStatistics(*_stats_rate, summary, literal_bytes, sizeof(Bucket), sizeof(Node));
|
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>
|
template <typename CONFIG, MEMFLAGS F>
|
||||||
|
|
|
@ -1133,7 +1133,6 @@ inline intx byte_size(void* from, void* to) {
|
||||||
return (address)to - (address)from;
|
return (address)to - (address)from;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Pack and extract shorts to/from ints:
|
// Pack and extract shorts to/from ints:
|
||||||
|
|
||||||
inline int extract_low_short_from_int(jint x) {
|
inline int extract_low_short_from_int(jint x) {
|
||||||
|
|
|
@ -263,5 +263,4 @@ template class Hashtable<InstanceKlass*, mtClass>;
|
||||||
template class Hashtable<WeakHandle, mtClass>;
|
template class Hashtable<WeakHandle, mtClass>;
|
||||||
template class Hashtable<WeakHandle, mtServiceability>;
|
template class Hashtable<WeakHandle, mtServiceability>;
|
||||||
|
|
||||||
template void BasicHashtable<mtClass>::verify_table<DictionaryEntry>(char const*);
|
|
||||||
template void BasicHashtable<mtClass>::verify_table<ProtectionDomainCacheEntry>(char const*);
|
template void BasicHashtable<mtClass>::verify_table<ProtectionDomainCacheEntry>(char const*);
|
||||||
|
|
|
@ -120,4 +120,12 @@ inline T next_power_of_2(T value) {
|
||||||
return round_up_power_of_2(value + 1);
|
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
|
#endif // SHARE_UTILITIES_POWEROFTWO_HPP
|
||||||
|
|
|
@ -132,7 +132,7 @@ public class TestResize {
|
||||||
// -Xlog:safepoint+cleanup will print out cleanup details at safepoint
|
// -Xlog:safepoint+cleanup will print out cleanup details at safepoint
|
||||||
// that will allow us to detect if the system dictionary resized.
|
// that will allow us to detect if the system dictionary resized.
|
||||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintClassLoaderDataGraphAtExit",
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintClassLoaderDataGraphAtExit",
|
||||||
"-Xlog:safepoint+cleanup",
|
"-Xlog:safepoint+cleanup,class+loader+data",
|
||||||
"TriggerResize",
|
"TriggerResize",
|
||||||
String.valueOf(CLASSES_TO_LOAD));
|
String.valueOf(CLASSES_TO_LOAD));
|
||||||
analyzeOutputOn(pb);
|
analyzeOutputOn(pb);
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue