8292286: Convert PlaceholderTable to ResourceHashtable
Reviewed-by: hseigel, iklam
This commit is contained in:
parent
ea2c82e74f
commit
6e6ae596d6
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -429,7 +429,7 @@ void LoaderConstraintTable::merge_loader_constraints(
|
||||
}
|
||||
|
||||
|
||||
void LoaderConstraintTable::verify(PlaceholderTable* placeholders) {
|
||||
void LoaderConstraintTable::verify() {
|
||||
Thread *thread = Thread::current();
|
||||
for (int cindex = 0; cindex < table_size(); cindex++) {
|
||||
for (LoaderConstraintEntry* probe = bucket(cindex);
|
||||
@ -450,7 +450,7 @@ void LoaderConstraintTable::verify(PlaceholderTable* placeholders) {
|
||||
} else {
|
||||
// If we don't find the class in the dictionary, it
|
||||
// has to be in the placeholders table.
|
||||
PlaceholderEntry* entry = placeholders->get_entry(name_hash, name, loader_data);
|
||||
PlaceholderEntry* entry = PlaceholderTable::get_entry(name, loader_data);
|
||||
|
||||
// The InstanceKlass might not be on the entry, so the only
|
||||
// thing we can check here is whether we were successful in
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -79,7 +79,7 @@ public:
|
||||
|
||||
void purge_loader_constraints();
|
||||
|
||||
void verify(PlaceholderTable* placeholders);
|
||||
void verify();
|
||||
void print() const;
|
||||
void print_on(outputStream* st) const;
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -31,7 +31,26 @@
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/javaThread.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
|
||||
class PlaceholderKey {
|
||||
Symbol* _name;
|
||||
ClassLoaderData* _loader_data;
|
||||
public:
|
||||
PlaceholderKey(Symbol* name, ClassLoaderData* l) : _name(name), _loader_data(l) {}
|
||||
|
||||
static bool equals(PlaceholderKey const& k1, PlaceholderKey const& k2) {
|
||||
return (k1._name == k2._name && k1._loader_data == k2._loader_data);
|
||||
}
|
||||
static unsigned hash(PlaceholderKey const& k) {
|
||||
return (unsigned) k._name->identity_hash() ^ (int)((intptr_t)k._loader_data >> 3);
|
||||
}
|
||||
void print_on(outputStream* st) const;
|
||||
};
|
||||
|
||||
const int _placeholder_table_size = 503; // Does this really have to be prime?
|
||||
ResourceHashtable<PlaceholderKey, PlaceholderEntry, _placeholder_table_size, ResourceObj::C_HEAP, mtClass,
|
||||
PlaceholderKey::hash, PlaceholderKey::equals> _placeholders;
|
||||
|
||||
// SeenThread objects represent list of threads that are
|
||||
// currently performing a load action on a class.
|
||||
@ -173,90 +192,41 @@ bool PlaceholderEntry::remove_seen_thread(JavaThread* thread, PlaceholderTable::
|
||||
|
||||
// Placeholder methods
|
||||
|
||||
PlaceholderEntry* PlaceholderTable::new_entry(int hash, Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Symbol* supername) {
|
||||
PlaceholderEntry* entry = (PlaceholderEntry*)Hashtable<Symbol*, mtClass>::new_entry(hash, name);
|
||||
// Hashtable with Symbol* literal must increment and decrement refcount.
|
||||
name->increment_refcount();
|
||||
entry->set_loader_data(loader_data);
|
||||
entry->set_supername(supername);
|
||||
entry->set_superThreadQ(NULL);
|
||||
entry->set_loadInstanceThreadQ(NULL);
|
||||
entry->set_defineThreadQ(NULL);
|
||||
entry->set_definer(NULL);
|
||||
entry->set_instance_klass(NULL);
|
||||
return entry;
|
||||
}
|
||||
|
||||
void PlaceholderTable::free_entry(PlaceholderEntry* entry) {
|
||||
// decrement Symbol refcount here because Hashtable doesn't.
|
||||
entry->literal()->decrement_refcount();
|
||||
if (entry->supername() != NULL) entry->supername()->decrement_refcount();
|
||||
BasicHashtable<mtClass>::free_entry(entry);
|
||||
}
|
||||
|
||||
|
||||
// Placeholder objects represent classes currently being loaded.
|
||||
// All threads examining the placeholder table must hold the
|
||||
// SystemDictionary_lock, so we don't need special precautions
|
||||
// on store ordering here.
|
||||
PlaceholderEntry* PlaceholderTable::add_entry(unsigned int hash,
|
||||
Symbol* class_name, ClassLoaderData* loader_data,
|
||||
Symbol* supername){
|
||||
PlaceholderEntry* add_entry(Symbol* class_name, ClassLoaderData* loader_data,
|
||||
Symbol* supername){
|
||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||
assert(class_name != NULL, "adding NULL obj");
|
||||
|
||||
// Both readers and writers are locked so it's safe to just
|
||||
// create the placeholder and insert it in the list without a membar.
|
||||
PlaceholderEntry* entry = new_entry(hash, class_name, loader_data, supername);
|
||||
int index = hash_to_index(hash);
|
||||
Hashtable<Symbol*, mtClass>::add_entry(index, entry);
|
||||
return entry;
|
||||
PlaceholderEntry entry;
|
||||
entry.set_supername(supername);
|
||||
PlaceholderKey key(class_name, loader_data);
|
||||
// Since we're storing this key in the hashtable, we need to increment the refcount.
|
||||
class_name->increment_refcount();
|
||||
bool created;
|
||||
PlaceholderEntry* table_copy = _placeholders.put_if_absent(key, entry, &created);
|
||||
assert(created, "better be absent");
|
||||
return table_copy;
|
||||
}
|
||||
|
||||
|
||||
// Remove a placeholder object.
|
||||
void PlaceholderTable::remove_entry(unsigned int hash,
|
||||
Symbol* class_name,
|
||||
ClassLoaderData* loader_data) {
|
||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||
int index = hash_to_index(hash);
|
||||
PlaceholderEntry** p = bucket_addr(index);
|
||||
while (*p != NULL) {
|
||||
PlaceholderEntry *probe = *p;
|
||||
if (probe->hash() == hash && probe->equals(class_name, loader_data)) {
|
||||
// Delete entry
|
||||
*p = probe->next();
|
||||
free_entry(probe);
|
||||
return;
|
||||
}
|
||||
p = probe->next_addr();
|
||||
}
|
||||
}
|
||||
|
||||
PlaceholderEntry* PlaceholderTable::get_entry(unsigned int hash,
|
||||
Symbol* class_name,
|
||||
ClassLoaderData* loader_data) {
|
||||
void remove_entry(Symbol* class_name, ClassLoaderData* loader_data) {
|
||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||
|
||||
int index = hash_to_index(hash);
|
||||
for (PlaceholderEntry *place_probe = bucket(index);
|
||||
place_probe != NULL;
|
||||
place_probe = place_probe->next()) {
|
||||
if (place_probe->hash() == hash &&
|
||||
place_probe->equals(class_name, loader_data)) {
|
||||
return place_probe;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
PlaceholderKey key(class_name, loader_data);
|
||||
_placeholders.remove(key);
|
||||
// Decrement the refcount in key, since it's no longer in the table.
|
||||
class_name->decrement_refcount();
|
||||
}
|
||||
|
||||
Symbol* PlaceholderTable::find_entry(unsigned int hash,
|
||||
Symbol* class_name,
|
||||
ClassLoaderData* loader_data) {
|
||||
PlaceholderEntry* probe = get_entry(hash, class_name, loader_data);
|
||||
return (probe != NULL ? probe->klassname() : NULL);
|
||||
|
||||
PlaceholderEntry* PlaceholderTable::get_entry(Symbol* class_name, ClassLoaderData* loader_data) {
|
||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||
PlaceholderKey key(class_name, loader_data);
|
||||
return _placeholders.get(key);
|
||||
}
|
||||
|
||||
static const char* action_to_string(PlaceholderTable::classloadAction action) {
|
||||
@ -274,7 +244,7 @@ inline void log(PlaceholderEntry* entry, const char* function, PlaceholderTable:
|
||||
ResourceMark rm;
|
||||
LogStream ls(lt);
|
||||
ls.print("%s %s ", function, action_to_string(action));
|
||||
entry->print_entry(&ls);
|
||||
entry->print_on(&ls);
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,17 +253,16 @@ inline void log(PlaceholderEntry* entry, const char* function, PlaceholderTable:
|
||||
// If entry exists, reuse entry
|
||||
// For both, push SeenThread for classloadAction
|
||||
// If LOAD_SUPER, this is used for circularity detection for instanceklass loading.
|
||||
PlaceholderEntry* PlaceholderTable::find_and_add(unsigned int hash,
|
||||
Symbol* name,
|
||||
PlaceholderEntry* PlaceholderTable::find_and_add(Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
classloadAction action,
|
||||
Symbol* supername,
|
||||
JavaThread* thread) {
|
||||
assert(action != LOAD_SUPER || supername != NULL, "must have a super class name");
|
||||
PlaceholderEntry* probe = get_entry(hash, name, loader_data);
|
||||
PlaceholderEntry* probe = get_entry(name, loader_data);
|
||||
if (probe == NULL) {
|
||||
// Nothing found, add place holder
|
||||
probe = add_entry(hash, name, loader_data, supername);
|
||||
probe = add_entry(name, loader_data, supername);
|
||||
} else {
|
||||
if (action == LOAD_SUPER) {
|
||||
probe->set_supername(supername);
|
||||
@ -318,50 +287,30 @@ PlaceholderEntry* PlaceholderTable::find_and_add(unsigned int hash,
|
||||
// Note: you can be in both placeholders and systemDictionary
|
||||
// Therefore - must always check SD first
|
||||
// Ignores the case where entry is not found
|
||||
void PlaceholderTable::find_and_remove(unsigned int hash,
|
||||
Symbol* name, ClassLoaderData* loader_data,
|
||||
void PlaceholderTable::find_and_remove(Symbol* name, ClassLoaderData* loader_data,
|
||||
classloadAction action,
|
||||
JavaThread* thread) {
|
||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||
PlaceholderEntry *probe = get_entry(hash, name, loader_data);
|
||||
if (probe != NULL) {
|
||||
log(probe, "find_and_remove", action);
|
||||
probe->remove_seen_thread(thread, action);
|
||||
// If no other threads using this entry, and this thread is not using this entry for other states
|
||||
if ((probe->superThreadQ() == NULL) && (probe->loadInstanceThreadQ() == NULL)
|
||||
&& (probe->defineThreadQ() == NULL) && (probe->definer() == NULL)) {
|
||||
remove_entry(hash, name, loader_data);
|
||||
}
|
||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||
PlaceholderEntry* probe = get_entry(name, loader_data);
|
||||
if (probe != NULL) {
|
||||
log(probe, "find_and_remove", action);
|
||||
probe->remove_seen_thread(thread, action);
|
||||
// If no other threads using this entry, and this thread is not using this entry for other states
|
||||
if ((probe->superThreadQ() == NULL) && (probe->loadInstanceThreadQ() == NULL)
|
||||
&& (probe->defineThreadQ() == NULL) && (probe->definer() == NULL)) {
|
||||
probe->clear_supername();
|
||||
remove_entry(name, loader_data);
|
||||
}
|
||||
}
|
||||
|
||||
PlaceholderTable::PlaceholderTable(int table_size)
|
||||
: Hashtable<Symbol*, mtClass>(table_size, sizeof(PlaceholderEntry)) {
|
||||
}
|
||||
|
||||
void PlaceholderEntry::verify() const {
|
||||
guarantee(loader_data() != NULL, "Must have been setup.");
|
||||
guarantee(loader_data()->class_loader() == NULL || loader_data()->class_loader()->is_instance(),
|
||||
"checking type of _loader");
|
||||
guarantee(instance_klass() == NULL
|
||||
|| instance_klass()->is_instance_klass(),
|
||||
"checking type of instance_klass result");
|
||||
void PlaceholderKey::print_on(outputStream* st) const {
|
||||
_name->print_value_on(st);
|
||||
st->print(", loader ");
|
||||
_loader_data->print_value_on(st);
|
||||
}
|
||||
|
||||
void PlaceholderTable::verify() {
|
||||
verify_table<PlaceholderEntry>("Placeholder Table");
|
||||
}
|
||||
|
||||
|
||||
// Note, doesn't append a cr
|
||||
// Can't call this print_on because HashtableEntry doesn't initialize its vptr
|
||||
// and print_on is a virtual function so the vptr call crashes.
|
||||
void PlaceholderEntry::print_entry(outputStream* st) const {
|
||||
klassname()->print_value_on(st);
|
||||
if (loader_data() != NULL) {
|
||||
st->print(", loader ");
|
||||
loader_data()->print_value_on(st);
|
||||
}
|
||||
void PlaceholderEntry::print_on(outputStream* st) const {
|
||||
if (supername() != NULL) {
|
||||
st->print(", supername ");
|
||||
supername()->print_value_on(st);
|
||||
@ -386,17 +335,16 @@ void PlaceholderEntry::print_entry(outputStream* st) const {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void PlaceholderTable::print_on(outputStream* st) const {
|
||||
void PlaceholderTable::print_on(outputStream* st) {
|
||||
auto printer = [&] (PlaceholderKey& key, PlaceholderEntry& entry) {
|
||||
st->print("placeholder ");
|
||||
key.print_on(st);
|
||||
entry.print_on(st);
|
||||
return true;
|
||||
};
|
||||
st->print_cr("Placeholder table (table_size=%d, placeholders=%d)",
|
||||
table_size(), number_of_entries());
|
||||
for (int pindex = 0; pindex < table_size(); pindex++) {
|
||||
for (PlaceholderEntry* probe = bucket(pindex);
|
||||
probe != NULL;
|
||||
probe = probe->next()) {
|
||||
st->print("%4d: placeholder ", pindex);
|
||||
probe->print_entry(st);
|
||||
}
|
||||
}
|
||||
_placeholders.table_size(), _placeholders.number_of_entries());
|
||||
_placeholders.iterate(printer);
|
||||
}
|
||||
|
||||
void PlaceholderTable::print() const { return print_on(tty); }
|
||||
void PlaceholderTable::print() { return print_on(tty); }
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -25,8 +25,6 @@
|
||||
#ifndef SHARE_CLASSFILE_PLACEHOLDERS_HPP
|
||||
#define SHARE_CLASSFILE_PLACEHOLDERS_HPP
|
||||
|
||||
#include "utilities/hashtable.hpp"
|
||||
|
||||
class PlaceholderEntry;
|
||||
class Thread;
|
||||
class ClassLoaderData;
|
||||
@ -36,69 +34,40 @@ class Symbol;
|
||||
// being loaded, as well as arrays of primitives.
|
||||
//
|
||||
|
||||
class PlaceholderTable : public Hashtable<Symbol*, mtClass> {
|
||||
|
||||
public:
|
||||
PlaceholderTable(int table_size);
|
||||
|
||||
PlaceholderEntry* new_entry(int hash, Symbol* name, ClassLoaderData* loader_data, Symbol* supername);
|
||||
void free_entry(PlaceholderEntry* entry);
|
||||
|
||||
PlaceholderEntry* bucket(int i) const {
|
||||
return (PlaceholderEntry*)Hashtable<Symbol*, mtClass>::bucket(i);
|
||||
}
|
||||
|
||||
PlaceholderEntry** bucket_addr(int i) {
|
||||
return (PlaceholderEntry**)Hashtable<Symbol*, mtClass>::bucket_addr(i);
|
||||
}
|
||||
|
||||
PlaceholderEntry* add_entry(unsigned int hash, Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Symbol* supername);
|
||||
|
||||
// This returns a Symbol* to match type for SystemDictionary
|
||||
Symbol* find_entry(unsigned int hash,
|
||||
Symbol* name, ClassLoaderData* loader_data);
|
||||
|
||||
PlaceholderEntry* get_entry(unsigned int hash,
|
||||
Symbol* name, ClassLoaderData* loader_data);
|
||||
|
||||
// caller to create a placeholder entry must enumerate an action
|
||||
// caller claims ownership of that action
|
||||
// For parallel classloading:
|
||||
// multiple LOAD_INSTANCE threads can proceed in parallel
|
||||
// multiple LOAD_SUPER threads can proceed in parallel
|
||||
// LOAD_SUPER needed to check for class circularity
|
||||
// DEFINE_CLASS: ultimately define class must be single threaded
|
||||
// on a class/classloader basis
|
||||
// so the head of that queue owns the token
|
||||
// and the rest of the threads return the result the first thread gets
|
||||
enum classloadAction {
|
||||
class PlaceholderTable : public AllStatic {
|
||||
public:
|
||||
// caller to create a placeholder entry must enumerate an action
|
||||
// caller claims ownership of that action
|
||||
// For parallel classloading:
|
||||
// multiple LOAD_INSTANCE threads can proceed in parallel
|
||||
// multiple LOAD_SUPER threads can proceed in parallel
|
||||
// LOAD_SUPER needed to check for class circularity
|
||||
// DEFINE_CLASS: ultimately define class must be single threaded
|
||||
// on a class/classloader basis
|
||||
// so the head of that queue owns the token
|
||||
// and the rest of the threads return the result the first thread gets
|
||||
enum classloadAction {
|
||||
LOAD_INSTANCE = 1, // calling load_instance_class
|
||||
LOAD_SUPER = 2, // loading superclass for this class
|
||||
DEFINE_CLASS = 3 // find_or_define class
|
||||
};
|
||||
};
|
||||
|
||||
static PlaceholderEntry* get_entry(Symbol* name, ClassLoaderData* loader_data);
|
||||
|
||||
// find_and_add returns probe pointer - old or new
|
||||
// If no entry exists, add a placeholder entry and push SeenThread for classloadAction
|
||||
// If entry exists, reuse entry and push SeenThread for classloadAction
|
||||
PlaceholderEntry* find_and_add(unsigned int hash,
|
||||
Symbol* name, ClassLoaderData* loader_data,
|
||||
classloadAction action, Symbol* supername,
|
||||
JavaThread* thread);
|
||||
|
||||
void remove_entry(unsigned int hash,
|
||||
Symbol* name, ClassLoaderData* loader_data);
|
||||
static PlaceholderEntry* find_and_add(Symbol* name, ClassLoaderData* loader_data,
|
||||
classloadAction action, Symbol* supername,
|
||||
JavaThread* thread);
|
||||
|
||||
// find_and_remove first removes SeenThread for classloadAction
|
||||
// If all queues are empty and definer is null, remove the PlacheholderEntry completely
|
||||
void find_and_remove(unsigned int hash,
|
||||
Symbol* name, ClassLoaderData* loader_data,
|
||||
static void find_and_remove(Symbol* name, ClassLoaderData* loader_data,
|
||||
classloadAction action, JavaThread* thread);
|
||||
|
||||
void print_on(outputStream* st) const;
|
||||
void print() const;
|
||||
void verify();
|
||||
static void print_on(outputStream* st);
|
||||
static void print();
|
||||
};
|
||||
|
||||
class SeenThread;
|
||||
@ -108,13 +77,9 @@ class SeenThread;
|
||||
// SystemDictionary_lock, so we don't need special precautions
|
||||
// on store ordering here.
|
||||
// The system dictionary is the only user of this class.
|
||||
|
||||
class PlaceholderEntry : public HashtableEntry<Symbol*, mtClass> {
|
||||
|
||||
class PlaceholderEntry {
|
||||
friend class PlaceholderTable;
|
||||
|
||||
private:
|
||||
ClassLoaderData* _loader_data; // initiating loader
|
||||
Symbol* _supername;
|
||||
JavaThread* _definer; // owner of define token
|
||||
InstanceKlass* _instanceKlass; // InstanceKlass from successful define
|
||||
@ -134,16 +99,19 @@ class PlaceholderEntry : public HashtableEntry<Symbol*, mtClass> {
|
||||
bool remove_seen_thread(JavaThread* thread, PlaceholderTable::classloadAction action);
|
||||
|
||||
public:
|
||||
// Simple accessors, used only by SystemDictionary
|
||||
Symbol* klassname() const { return literal(); }
|
||||
|
||||
ClassLoaderData* loader_data() const { return _loader_data; }
|
||||
void set_loader_data(ClassLoaderData* loader_data) { _loader_data = loader_data; }
|
||||
PlaceholderEntry() :
|
||||
_supername(nullptr), _definer(nullptr), _instanceKlass(nullptr),
|
||||
_superThreadQ(nullptr), _loadInstanceThreadQ(nullptr), _defineThreadQ(nullptr) { }
|
||||
|
||||
Symbol* supername() const { return _supername; }
|
||||
void set_supername(Symbol* supername) {
|
||||
Symbol::maybe_decrement_refcount(_supername);
|
||||
_supername = supername;
|
||||
if (_supername != NULL) _supername->increment_refcount();
|
||||
Symbol::maybe_increment_refcount(_supername);
|
||||
}
|
||||
void clear_supername() {
|
||||
Symbol::maybe_decrement_refcount(_supername);
|
||||
_supername = nullptr;
|
||||
}
|
||||
|
||||
JavaThread* definer() const {return _definer; }
|
||||
@ -161,20 +129,6 @@ class PlaceholderEntry : public HashtableEntry<Symbol*, mtClass> {
|
||||
SeenThread* defineThreadQ() const { return _defineThreadQ; }
|
||||
void set_defineThreadQ(SeenThread* SeenThread) { _defineThreadQ = SeenThread; }
|
||||
|
||||
PlaceholderEntry* next() const {
|
||||
return (PlaceholderEntry*)HashtableEntry<Symbol*, mtClass>::next();
|
||||
}
|
||||
|
||||
PlaceholderEntry** next_addr() {
|
||||
return (PlaceholderEntry**)HashtableEntry<Symbol*, mtClass>::next_addr();
|
||||
}
|
||||
|
||||
// Test for equality
|
||||
// Entries are unique for class/classloader name pair
|
||||
bool equals(Symbol* class_name, ClassLoaderData* loader) const {
|
||||
return (klassname() == class_name && loader_data() == loader);
|
||||
}
|
||||
|
||||
bool super_load_in_progress() {
|
||||
return (_superThreadQ != NULL);
|
||||
}
|
||||
@ -190,9 +144,7 @@ class PlaceholderEntry : public HashtableEntry<Symbol*, mtClass> {
|
||||
// Used for ClassCircularityError checking
|
||||
bool check_seen_thread(JavaThread* thread, PlaceholderTable::classloadAction action);
|
||||
|
||||
// Print method doesn't append a cr
|
||||
void print_entry(outputStream* st) const;
|
||||
void verify() const;
|
||||
void print_on(outputStream* st) const;
|
||||
};
|
||||
|
||||
#endif // SHARE_CLASSFILE_PLACEHOLDERS_HPP
|
||||
|
@ -126,11 +126,6 @@ const int defaultProtectionDomainCacheSize = 1009;
|
||||
const int _resolution_error_size = 107; // number of entries in resolution error table
|
||||
const int _invoke_method_size = 139; // number of entries in invoke method table
|
||||
|
||||
// Hashtable holding placeholders for classes being loaded.
|
||||
const int _placeholder_table_size = 1009;
|
||||
static PlaceholderTable* _placeholders = NULL;
|
||||
static PlaceholderTable* placeholders() { return _placeholders; }
|
||||
|
||||
// Constraints on class loaders
|
||||
const int _loader_constraint_size = 107; // number of entries in constraint table
|
||||
static LoaderConstraintTable* _loader_constraints;
|
||||
@ -389,7 +384,7 @@ static inline void log_circularity_error(Thread* thread, PlaceholderEntry* probe
|
||||
ResourceMark rm(thread);
|
||||
LogStream ls(lt);
|
||||
ls.print("ClassCircularityError detected for placeholder ");
|
||||
probe->print_entry(&ls);
|
||||
probe->print_on(&ls);
|
||||
ls.cr();
|
||||
}
|
||||
}
|
||||
@ -442,7 +437,6 @@ 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);
|
||||
assert(placeholders()->compute_hash(class_name) == name_hash, "they're the same hashcode");
|
||||
|
||||
// can't throw error holding a lock
|
||||
bool throw_circularity_error = false;
|
||||
@ -460,7 +454,7 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name,
|
||||
return quicksuperk;
|
||||
} else {
|
||||
// Must check ClassCircularity before checking if superclass is already loaded.
|
||||
PlaceholderEntry* probe = placeholders()->get_entry(name_hash, class_name, loader_data);
|
||||
PlaceholderEntry* probe = PlaceholderTable::get_entry(class_name, loader_data);
|
||||
if (probe && probe->check_seen_thread(THREAD, PlaceholderTable::LOAD_SUPER)) {
|
||||
log_circularity_error(THREAD, probe);
|
||||
throw_circularity_error = true;
|
||||
@ -469,11 +463,10 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name,
|
||||
|
||||
if (!throw_circularity_error) {
|
||||
// Be careful not to exit resolve_super without removing this placeholder.
|
||||
PlaceholderEntry* newprobe = placeholders()->find_and_add(name_hash,
|
||||
class_name,
|
||||
loader_data,
|
||||
PlaceholderTable::LOAD_SUPER,
|
||||
super_name, THREAD);
|
||||
PlaceholderEntry* newprobe = PlaceholderTable::find_and_add(class_name,
|
||||
loader_data,
|
||||
PlaceholderTable::LOAD_SUPER,
|
||||
super_name, THREAD);
|
||||
}
|
||||
}
|
||||
|
||||
@ -492,7 +485,7 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name,
|
||||
// Clean up placeholder entry.
|
||||
{
|
||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
||||
placeholders()->find_and_remove(name_hash, class_name, loader_data, PlaceholderTable::LOAD_SUPER, THREAD);
|
||||
PlaceholderTable::find_and_remove(class_name, loader_data, PlaceholderTable::LOAD_SUPER, THREAD);
|
||||
SystemDictionary_lock->notify_all();
|
||||
}
|
||||
|
||||
@ -579,7 +572,7 @@ InstanceKlass* SystemDictionary::handle_parallel_loading(JavaThread* current,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle lockObject,
|
||||
bool* throw_circularity_error) {
|
||||
PlaceholderEntry* oldprobe = placeholders()->get_entry(name_hash, name, loader_data);
|
||||
PlaceholderEntry* oldprobe = PlaceholderTable::get_entry(name, loader_data);
|
||||
if (oldprobe != NULL) {
|
||||
// only need check_seen_thread once, not on each loop
|
||||
// 6341374 java/lang/Instrument with -Xcomp
|
||||
@ -620,7 +613,7 @@ InstanceKlass* SystemDictionary::handle_parallel_loading(JavaThread* current,
|
||||
return check;
|
||||
}
|
||||
// check if other thread failed to load and cleaned up
|
||||
oldprobe = placeholders()->get_entry(name_hash, name, loader_data);
|
||||
oldprobe = PlaceholderTable::get_entry(name, loader_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -689,8 +682,6 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
|
||||
name->as_C_string(),
|
||||
class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string());
|
||||
|
||||
assert(placeholders()->compute_hash(name) == name_hash, "they're the same hashcode");
|
||||
|
||||
// Check again (after locking) if the class already exists in SystemDictionary
|
||||
{
|
||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
||||
@ -699,7 +690,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
|
||||
// InstanceKlass is already loaded, but we still need to check protection domain below.
|
||||
loaded_class = check;
|
||||
} else {
|
||||
PlaceholderEntry* placeholder = placeholders()->get_entry(name_hash, name, loader_data);
|
||||
PlaceholderEntry* placeholder = PlaceholderTable::get_entry(name, loader_data);
|
||||
if (placeholder != NULL && placeholder->super_load_in_progress()) {
|
||||
super_load_in_progress = true;
|
||||
superclassname = placeholder->supername();
|
||||
@ -757,10 +748,10 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
|
||||
loaded_class = check;
|
||||
} else if (should_wait_for_loading(class_loader)) {
|
||||
// Add the LOAD_INSTANCE token. Threads will wait on loading to complete for this thread.
|
||||
PlaceholderEntry* newprobe = placeholders()->find_and_add(name_hash, name, loader_data,
|
||||
PlaceholderTable::LOAD_INSTANCE,
|
||||
NULL,
|
||||
THREAD);
|
||||
PlaceholderEntry* newprobe = PlaceholderTable::find_and_add(name, loader_data,
|
||||
PlaceholderTable::LOAD_INSTANCE,
|
||||
NULL,
|
||||
THREAD);
|
||||
load_placeholder_added = true;
|
||||
}
|
||||
}
|
||||
@ -774,7 +765,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
|
||||
}
|
||||
|
||||
// Be careful when modifying this code: once you have run
|
||||
// placeholders()->find_and_add(PlaceholderTable::LOAD_INSTANCE),
|
||||
// PlaceholderTable::find_and_add(PlaceholderTable::LOAD_INSTANCE),
|
||||
// you need to find_and_remove it before returning.
|
||||
// So be careful to not exit with a CHECK_ macro between these calls.
|
||||
|
||||
@ -788,7 +779,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
|
||||
// This brackets the SystemDictionary updates for both defining
|
||||
// and initiating loaders
|
||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
||||
placeholders()->find_and_remove(name_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, THREAD);
|
||||
PlaceholderTable::find_and_remove(name, loader_data, PlaceholderTable::LOAD_INSTANCE, THREAD);
|
||||
SystemDictionary_lock->notify_all();
|
||||
}
|
||||
}
|
||||
@ -1538,7 +1529,7 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, Handle class_load
|
||||
// potentially waste time reading and parsing the bytestream.
|
||||
// Note: VM callers should ensure consistency of k/class_name,class_loader
|
||||
// Be careful when modifying this code: once you have run
|
||||
// placeholders()->find_and_add(PlaceholderTable::DEFINE_CLASS),
|
||||
// PlaceholderTable::find_and_add(PlaceholderTable::DEFINE_CLASS),
|
||||
// you need to find_and_remove it before returning.
|
||||
// So be careful to not exit with a CHECK_ macro between these calls.
|
||||
InstanceKlass* SystemDictionary::find_or_define_helper(Symbol* class_name, Handle class_loader,
|
||||
@ -1562,9 +1553,8 @@ InstanceKlass* SystemDictionary::find_or_define_helper(Symbol* class_name, Handl
|
||||
}
|
||||
|
||||
// Acquire define token for this class/classloader
|
||||
assert(placeholders()->compute_hash(name_h) == name_hash, "they're the same hashcode");
|
||||
PlaceholderEntry* probe = placeholders()->find_and_add(name_hash, name_h, loader_data,
|
||||
PlaceholderTable::DEFINE_CLASS, NULL, THREAD);
|
||||
PlaceholderEntry* probe = PlaceholderTable::find_and_add(name_h, loader_data,
|
||||
PlaceholderTable::DEFINE_CLASS, NULL, THREAD);
|
||||
// Wait if another thread defining in parallel
|
||||
// All threads wait - even those that will throw duplicate class: otherwise
|
||||
// caller is surprised by LinkageError: duplicate, but findLoadedClass fails
|
||||
@ -1577,7 +1567,7 @@ InstanceKlass* SystemDictionary::find_or_define_helper(Symbol* class_name, Handl
|
||||
// caught by finding an entry in the SystemDictionary
|
||||
if (is_parallelDefine(class_loader) && (probe->instance_klass() != NULL)) {
|
||||
InstanceKlass* ik = probe->instance_klass();
|
||||
placeholders()->find_and_remove(name_hash, name_h, loader_data, PlaceholderTable::DEFINE_CLASS, THREAD);
|
||||
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);
|
||||
@ -1595,13 +1585,13 @@ InstanceKlass* SystemDictionary::find_or_define_helper(Symbol* class_name, Handl
|
||||
// definer must notify any waiting threads
|
||||
{
|
||||
MutexLocker mu(THREAD, SystemDictionary_lock);
|
||||
PlaceholderEntry* probe = placeholders()->get_entry(name_hash, name_h, loader_data);
|
||||
PlaceholderEntry* probe = PlaceholderTable::get_entry(name_h, loader_data);
|
||||
assert(probe != NULL, "DEFINE_CLASS placeholder lost?");
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
probe->set_instance_klass(k);
|
||||
}
|
||||
probe->set_definer(NULL);
|
||||
placeholders()->find_and_remove(name_hash, name_h, loader_data, PlaceholderTable::DEFINE_CLASS, THREAD);
|
||||
PlaceholderTable::find_and_remove(name_h, loader_data, PlaceholderTable::DEFINE_CLASS, THREAD);
|
||||
SystemDictionary_lock->notify_all();
|
||||
}
|
||||
|
||||
@ -1724,7 +1714,6 @@ void SystemDictionary::methods_do(void f(Method*)) {
|
||||
|
||||
void SystemDictionary::initialize(TRAPS) {
|
||||
// Allocate arrays
|
||||
_placeholders = new PlaceholderTable(_placeholder_table_size);
|
||||
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
|
||||
_pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize);
|
||||
|
||||
@ -2489,7 +2478,7 @@ void SystemDictionary::print_on(outputStream *st) {
|
||||
ClassLoaderDataGraph::print_dictionary(st);
|
||||
|
||||
// Placeholders
|
||||
placeholders()->print_on(st);
|
||||
PlaceholderTable::print_on(st);
|
||||
st->cr();
|
||||
|
||||
// loader constraints - print under SD_lock
|
||||
@ -2505,19 +2494,15 @@ void SystemDictionary::print() { print_on(tty); }
|
||||
void SystemDictionary::verify() {
|
||||
guarantee(constraints() != NULL,
|
||||
"Verify of loader constraints failed");
|
||||
guarantee(placeholders()->number_of_entries() >= 0,
|
||||
"Verify of placeholders failed");
|
||||
|
||||
GCMutexLocker mu(SystemDictionary_lock);
|
||||
|
||||
// Verify dictionary
|
||||
ClassLoaderDataGraph::verify_dictionary();
|
||||
|
||||
placeholders()->verify();
|
||||
|
||||
// Verify constraint table
|
||||
guarantee(constraints() != NULL, "Verify of loader constraints failed");
|
||||
constraints()->verify(placeholders());
|
||||
constraints()->verify();
|
||||
|
||||
_pd_cache_table->verify();
|
||||
}
|
||||
@ -2529,7 +2514,6 @@ void SystemDictionary::dump(outputStream *st, bool verbose) {
|
||||
} else {
|
||||
CDS_ONLY(SystemDictionaryShared::print_table_statistics(st));
|
||||
ClassLoaderDataGraph::print_table_statistics(st);
|
||||
placeholders()->print_table_statistics(st, "Placeholder Table");
|
||||
constraints()->print_table_statistics(st, "LoaderConstraints Table");
|
||||
pd_cache_table()->print_table_statistics(st, "ProtectionDomainCache Table");
|
||||
}
|
||||
|
@ -284,4 +284,3 @@ template class BasicHashtable<mtLogging>;
|
||||
|
||||
template void BasicHashtable<mtClass>::verify_table<DictionaryEntry>(char const*);
|
||||
template void BasicHashtable<mtClass>::verify_table<ProtectionDomainCacheEntry>(char const*);
|
||||
template void BasicHashtable<mtClass>::verify_table<PlaceholderEntry>(char const*);
|
||||
|
Loading…
Reference in New Issue
Block a user