8292384: Convert AdapterHandlerTable to ResourceHashtable
Reviewed-by: hseigel, rehn
This commit is contained in:
parent
0c67fba11f
commit
f45b8408a0
@ -72,7 +72,7 @@
|
||||
#include "utilities/copy.hpp"
|
||||
#include "utilities/dtrace.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/xmlstream.hpp"
|
||||
#ifdef COMPILER1
|
||||
@ -2390,6 +2390,12 @@ void SharedRuntime::print_call_statistics(uint64_t comp_total) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
static int _lookups; // number of calls to lookup
|
||||
static int _equals; // number of buckets checked with matching hash
|
||||
static int _hits; // number of successful lookups
|
||||
static int _compact; // number of equals calls with compact signature
|
||||
#endif
|
||||
|
||||
// A simple wrapper class around the calling convention information
|
||||
// that allows sharing of adapters for the same calling convention.
|
||||
@ -2576,147 +2582,55 @@ class AdapterFingerPrint : public CHeapObj<mtCode> {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static bool equals(AdapterFingerPrint* const& fp1, AdapterFingerPrint* const& fp2) {
|
||||
NOT_PRODUCT(_equals++);
|
||||
return fp1->equals(fp2);
|
||||
}
|
||||
|
||||
static unsigned int compute_hash(AdapterFingerPrint* const& fp) {
|
||||
return fp->compute_hash();
|
||||
}
|
||||
};
|
||||
|
||||
// A hashtable mapping from AdapterFingerPrints to AdapterHandlerEntries
|
||||
class AdapterHandlerTable : public BasicHashtable<mtCode> {
|
||||
friend class AdapterHandlerTableIterator;
|
||||
ResourceHashtable<AdapterFingerPrint*, AdapterHandlerEntry*, 293,
|
||||
ResourceObj::C_HEAP, mtCode,
|
||||
AdapterFingerPrint::compute_hash,
|
||||
AdapterFingerPrint::equals> _adapter_handler_table;
|
||||
|
||||
private:
|
||||
// Find a entry with the same fingerprint if it exists
|
||||
static AdapterHandlerEntry* lookup(int total_args_passed, BasicType* sig_bt) {
|
||||
NOT_PRODUCT(_lookups++);
|
||||
assert_lock_strong(AdapterHandlerLibrary_lock);
|
||||
AdapterFingerPrint fp(total_args_passed, sig_bt);
|
||||
AdapterHandlerEntry** entry = _adapter_handler_table.get(&fp);
|
||||
if (entry != nullptr) {
|
||||
#ifndef PRODUCT
|
||||
if (fp.is_compact()) _compact++;
|
||||
_hits++;
|
||||
#endif
|
||||
return *entry;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
static int _lookups; // number of calls to lookup
|
||||
static int _buckets; // number of buckets checked
|
||||
static int _equals; // number of buckets checked with matching hash
|
||||
static int _hits; // number of successful lookups
|
||||
static int _compact; // number of equals calls with compact signature
|
||||
static void print_table_statistics() {
|
||||
auto size = [&] (AdapterFingerPrint* key, AdapterHandlerEntry* a) {
|
||||
return sizeof(*key) + sizeof(*a);
|
||||
};
|
||||
TableStatistics ts = _adapter_handler_table.statistics_calculate(size);
|
||||
ts.print(tty, "AdapterHandlerTable");
|
||||
tty->print_cr("AdapterHandlerTable (table_size=%d, entries=%d)",
|
||||
_adapter_handler_table.table_size(), _adapter_handler_table.number_of_entries());
|
||||
tty->print_cr("AdapterHandlerTable: lookups %d equals %d hits %d compact %d",
|
||||
_lookups, _equals, _hits, _compact);
|
||||
}
|
||||
#endif
|
||||
|
||||
AdapterHandlerEntry* bucket(int i) {
|
||||
return (AdapterHandlerEntry*)BasicHashtable<mtCode>::bucket(i);
|
||||
}
|
||||
|
||||
public:
|
||||
AdapterHandlerTable()
|
||||
: BasicHashtable<mtCode>(293, (sizeof(AdapterHandlerEntry))) { }
|
||||
|
||||
// Create a new entry suitable for insertion in the table
|
||||
AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry, address c2i_no_clinit_check_entry) {
|
||||
AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable<mtCode>::new_entry(fingerprint->compute_hash());
|
||||
entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Insert an entry into the table
|
||||
void add(AdapterHandlerEntry* entry) {
|
||||
int index = hash_to_index(entry->hash());
|
||||
add_entry(index, entry);
|
||||
}
|
||||
|
||||
void free_entry(AdapterHandlerEntry* entry) {
|
||||
entry->deallocate();
|
||||
BasicHashtable<mtCode>::free_entry(entry);
|
||||
}
|
||||
|
||||
// Find a entry with the same fingerprint if it exists
|
||||
AdapterHandlerEntry* lookup(int total_args_passed, BasicType* sig_bt) {
|
||||
NOT_PRODUCT(_lookups++);
|
||||
AdapterFingerPrint fp(total_args_passed, sig_bt);
|
||||
unsigned int hash = fp.compute_hash();
|
||||
int index = hash_to_index(hash);
|
||||
for (AdapterHandlerEntry* e = bucket(index); e != NULL; e = e->next()) {
|
||||
NOT_PRODUCT(_buckets++);
|
||||
if (e->hash() == hash) {
|
||||
NOT_PRODUCT(_equals++);
|
||||
if (fp.equals(e->fingerprint())) {
|
||||
#ifndef PRODUCT
|
||||
if (fp.is_compact()) _compact++;
|
||||
_hits++;
|
||||
#endif
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void print_statistics() {
|
||||
ResourceMark rm;
|
||||
int longest = 0;
|
||||
int empty = 0;
|
||||
int total = 0;
|
||||
int nonempty = 0;
|
||||
for (int index = 0; index < table_size(); index++) {
|
||||
int count = 0;
|
||||
for (AdapterHandlerEntry* e = bucket(index); e != NULL; e = e->next()) {
|
||||
count++;
|
||||
}
|
||||
if (count != 0) nonempty++;
|
||||
if (count == 0) empty++;
|
||||
if (count > longest) longest = count;
|
||||
total += count;
|
||||
}
|
||||
tty->print_cr("AdapterHandlerTable: empty %d longest %d total %d average %f",
|
||||
empty, longest, total, total / (double)nonempty);
|
||||
tty->print_cr("AdapterHandlerTable: lookups %d buckets %d equals %d hits %d compact %d",
|
||||
_lookups, _buckets, _equals, _hits, _compact);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
int AdapterHandlerTable::_lookups;
|
||||
int AdapterHandlerTable::_buckets;
|
||||
int AdapterHandlerTable::_equals;
|
||||
int AdapterHandlerTable::_hits;
|
||||
int AdapterHandlerTable::_compact;
|
||||
|
||||
#endif
|
||||
|
||||
class AdapterHandlerTableIterator : public StackObj {
|
||||
private:
|
||||
AdapterHandlerTable* _table;
|
||||
int _index;
|
||||
AdapterHandlerEntry* _current;
|
||||
|
||||
void scan() {
|
||||
while (_index < _table->table_size()) {
|
||||
AdapterHandlerEntry* a = _table->bucket(_index);
|
||||
_index++;
|
||||
if (a != NULL) {
|
||||
_current = a;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
AdapterHandlerTableIterator(AdapterHandlerTable* table): _table(table), _index(0), _current(NULL) {
|
||||
scan();
|
||||
}
|
||||
bool has_next() {
|
||||
return _current != NULL;
|
||||
}
|
||||
AdapterHandlerEntry* next() {
|
||||
if (_current != NULL) {
|
||||
AdapterHandlerEntry* result = _current;
|
||||
_current = _current->next();
|
||||
if (_current == NULL) scan();
|
||||
return result;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Implementation of AdapterHandlerLibrary
|
||||
AdapterHandlerTable* AdapterHandlerLibrary::_adapters = NULL;
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = NULL;
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::_no_arg_handler = NULL;
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::_int_arg_handler = NULL;
|
||||
@ -2734,7 +2648,8 @@ extern "C" void unexpected_adapter_call() {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
static void post_adapter_creation(const AdapterBlob* new_adapter, const AdapterHandlerEntry* entry) {
|
||||
static void post_adapter_creation(const AdapterBlob* new_adapter,
|
||||
const AdapterHandlerEntry* entry) {
|
||||
if (Forte::is_enabled() || JvmtiExport::should_post_dynamic_code_generated()) {
|
||||
char blob_id[256];
|
||||
jio_snprintf(blob_id,
|
||||
@ -2761,9 +2676,6 @@ void AdapterHandlerLibrary::initialize() {
|
||||
AdapterBlob* obj_obj_arg_blob = NULL;
|
||||
{
|
||||
MutexLocker mu(AdapterHandlerLibrary_lock);
|
||||
assert(_adapters == NULL, "Initializing more than once");
|
||||
|
||||
_adapters = new AdapterHandlerTable();
|
||||
|
||||
// Create a special handler for abstract methods. Abstract methods
|
||||
// are never compiled so an i2c entry is somewhat meaningless, but
|
||||
@ -2776,7 +2688,6 @@ void AdapterHandlerLibrary::initialize() {
|
||||
wrong_method_abstract, wrong_method_abstract);
|
||||
|
||||
_buffer = BufferBlob::create("adapters", AdapterHandlerLibrary_size);
|
||||
|
||||
_no_arg_handler = create_adapter(no_arg_blob, 0, NULL, true);
|
||||
|
||||
BasicType obj_args[] = { T_OBJECT };
|
||||
@ -2811,7 +2722,9 @@ AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* finger
|
||||
address c2i_entry,
|
||||
address c2i_unverified_entry,
|
||||
address c2i_no_clinit_check_entry) {
|
||||
return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
// Insert an entry into the table
|
||||
return new AdapterHandlerEntry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry,
|
||||
c2i_no_clinit_check_entry);
|
||||
}
|
||||
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::get_simple_adapter(const methodHandle& method) {
|
||||
@ -2897,10 +2810,9 @@ class AdapterSignatureIterator : public SignatureIterator {
|
||||
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) {
|
||||
// Use customized signature handler. Need to lock around updates to
|
||||
// the AdapterHandlerTable (it is not safe for concurrent readers
|
||||
// the _adapter_handler_table (it is not safe for concurrent readers
|
||||
// and a single writer: this could be fixed if it becomes a
|
||||
// problem).
|
||||
assert(_adapters != NULL, "Uninitialized");
|
||||
|
||||
// Fast-path for trivial adapters
|
||||
AdapterHandlerEntry* entry = get_simple_adapter(method);
|
||||
@ -2922,7 +2834,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& meth
|
||||
MutexLocker mu(AdapterHandlerLibrary_lock);
|
||||
|
||||
// Lookup method signature's fingerprint
|
||||
entry = _adapters->lookup(total_args_passed, sig_bt);
|
||||
entry = lookup(total_args_passed, sig_bt);
|
||||
|
||||
if (entry != NULL) {
|
||||
#ifdef ASSERT
|
||||
@ -2932,7 +2844,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& meth
|
||||
assert(comparison_blob == NULL, "no blob should be created when creating an adapter for comparison");
|
||||
assert(comparison_entry->compare_code(entry), "code must match");
|
||||
// Release the one just created and return the original
|
||||
_adapters->free_entry(comparison_entry);
|
||||
delete comparison_entry;
|
||||
}
|
||||
#endif
|
||||
return entry;
|
||||
@ -3004,7 +2916,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::create_adapter(AdapterBlob*& new_ada
|
||||
ttyLocker ttyl;
|
||||
entry->print_adapter_on(tty);
|
||||
tty->print_cr("i2c argument handler #%d for: %s %s (%d bytes generated)",
|
||||
_adapters->number_of_entries(), fingerprint->as_basic_args_string(),
|
||||
_adapter_handler_table.number_of_entries(), fingerprint->as_basic_args_string(),
|
||||
fingerprint->as_string(), insts_size);
|
||||
tty->print_cr("c2i argument handler starts at " INTPTR_FORMAT, p2i(entry->get_c2i_entry()));
|
||||
if (Verbose || PrintStubCode) {
|
||||
@ -3021,7 +2933,8 @@ AdapterHandlerEntry* AdapterHandlerLibrary::create_adapter(AdapterBlob*& new_ada
|
||||
// Add the entry only if the entry contains all required checks (see sharedRuntime_xxx.cpp)
|
||||
// The checks are inserted only if -XX:+VerifyAdapterCalls is specified.
|
||||
if (contains_all_checks || !VerifyAdapterCalls) {
|
||||
_adapters->add(entry);
|
||||
assert_lock_strong(AdapterHandlerLibrary_lock);
|
||||
_adapter_handler_table.put(fingerprint, entry);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
@ -3051,7 +2964,7 @@ void AdapterHandlerEntry::relocate(address new_base) {
|
||||
}
|
||||
|
||||
|
||||
void AdapterHandlerEntry::deallocate() {
|
||||
AdapterHandlerEntry::~AdapterHandlerEntry() {
|
||||
delete _fingerprint;
|
||||
#ifdef ASSERT
|
||||
FREE_C_HEAP_ARRAY(unsigned char, _saved_code);
|
||||
@ -3340,25 +3253,30 @@ JRT_LEAF(void, SharedRuntime::OSR_migration_end( intptr_t* buf) )
|
||||
JRT_END
|
||||
|
||||
bool AdapterHandlerLibrary::contains(const CodeBlob* b) {
|
||||
AdapterHandlerTableIterator iter(_adapters);
|
||||
while (iter.has_next()) {
|
||||
AdapterHandlerEntry* a = iter.next();
|
||||
if (b == CodeCache::find_blob(a->get_i2c_entry())) return true;
|
||||
}
|
||||
return false;
|
||||
bool found = false;
|
||||
auto findblob = [&] (AdapterFingerPrint* key, AdapterHandlerEntry* a) {
|
||||
return (found = (b == CodeCache::find_blob(a->get_i2c_entry())));
|
||||
};
|
||||
assert_locked_or_safepoint(AdapterHandlerLibrary_lock);
|
||||
_adapter_handler_table.iterate(findblob);
|
||||
return found;
|
||||
}
|
||||
|
||||
void AdapterHandlerLibrary::print_handler_on(outputStream* st, const CodeBlob* b) {
|
||||
AdapterHandlerTableIterator iter(_adapters);
|
||||
while (iter.has_next()) {
|
||||
AdapterHandlerEntry* a = iter.next();
|
||||
bool found = false;
|
||||
auto findblob = [&] (AdapterFingerPrint* key, AdapterHandlerEntry* a) {
|
||||
if (b == CodeCache::find_blob(a->get_i2c_entry())) {
|
||||
found = true;
|
||||
st->print("Adapter for signature: ");
|
||||
a->print_adapter_on(tty);
|
||||
return;
|
||||
a->print_adapter_on(st);
|
||||
return true;
|
||||
} else {
|
||||
return false; // keep looking
|
||||
}
|
||||
}
|
||||
assert(false, "Should have found handler");
|
||||
};
|
||||
assert_locked_or_safepoint(AdapterHandlerLibrary_lock);
|
||||
_adapter_handler_table.iterate(findblob);
|
||||
assert(found, "Should have found handler");
|
||||
}
|
||||
|
||||
void AdapterHandlerEntry::print_adapter_on(outputStream* st) const {
|
||||
@ -3381,7 +3299,7 @@ void AdapterHandlerEntry::print_adapter_on(outputStream* st) const {
|
||||
#ifndef PRODUCT
|
||||
|
||||
void AdapterHandlerLibrary::print_statistics() {
|
||||
_adapters->print_statistics();
|
||||
print_table_statistics();
|
||||
}
|
||||
|
||||
#endif /* PRODUCT */
|
||||
|
@ -31,11 +31,9 @@
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "memory/allStatic.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "utilities/hashtable.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
class AdapterHandlerEntry;
|
||||
class AdapterHandlerTable;
|
||||
class AdapterFingerPrint;
|
||||
class vframeStream;
|
||||
|
||||
@ -611,8 +609,7 @@ class SharedRuntime: AllStatic {
|
||||
// used by the adapters. The code generation happens here because it's very
|
||||
// similar to what the adapters have to do.
|
||||
|
||||
class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> {
|
||||
friend class AdapterHandlerTable;
|
||||
class AdapterHandlerEntry : public CHeapObj<mtCode> {
|
||||
friend class AdapterHandlerLibrary;
|
||||
|
||||
private:
|
||||
@ -629,21 +626,20 @@ class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> {
|
||||
int _saved_code_length;
|
||||
#endif
|
||||
|
||||
void init(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry, address c2i_no_clinit_check_entry) {
|
||||
_fingerprint = fingerprint;
|
||||
_i2c_entry = i2c_entry;
|
||||
_c2i_entry = c2i_entry;
|
||||
_c2i_unverified_entry = c2i_unverified_entry;
|
||||
_c2i_no_clinit_check_entry = c2i_no_clinit_check_entry;
|
||||
AdapterHandlerEntry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry,
|
||||
address c2i_unverified_entry,
|
||||
address c2i_no_clinit_check_entry) :
|
||||
_fingerprint(fingerprint),
|
||||
_i2c_entry(i2c_entry),
|
||||
_c2i_entry(c2i_entry),
|
||||
_c2i_unverified_entry(c2i_unverified_entry),
|
||||
_c2i_no_clinit_check_entry(c2i_no_clinit_check_entry)
|
||||
#ifdef ASSERT
|
||||
_saved_code_length = 0;
|
||||
, _saved_code_length(0)
|
||||
#endif
|
||||
}
|
||||
{ }
|
||||
|
||||
void deallocate();
|
||||
|
||||
// should never be used
|
||||
AdapterHandlerEntry();
|
||||
~AdapterHandlerEntry();
|
||||
|
||||
public:
|
||||
address get_i2c_entry() const { return _i2c_entry; }
|
||||
@ -656,10 +652,6 @@ class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> {
|
||||
|
||||
AdapterFingerPrint* fingerprint() const { return _fingerprint; }
|
||||
|
||||
AdapterHandlerEntry* next() {
|
||||
return (AdapterHandlerEntry*)BasicHashtableEntry<mtCode>::next();
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
// Used to verify that code generated for shared adapters is equivalent
|
||||
void save_code (unsigned char* code, int length);
|
||||
@ -674,7 +666,6 @@ class AdapterHandlerLibrary: public AllStatic {
|
||||
friend class SharedRuntime;
|
||||
private:
|
||||
static BufferBlob* _buffer; // the temporary code buffer in CodeCache
|
||||
static AdapterHandlerTable* _adapters;
|
||||
static AdapterHandlerEntry* _abstract_method_handler;
|
||||
static AdapterHandlerEntry* _no_arg_handler;
|
||||
static AdapterHandlerEntry* _int_arg_handler;
|
||||
|
@ -271,10 +271,8 @@ template class Hashtable<Symbol*, mtClass>;
|
||||
template class HashtableEntry<Symbol*, mtClass>;
|
||||
template class HashtableBucket<mtClass>;
|
||||
template class BasicHashtableEntry<mtSymbol>;
|
||||
template class BasicHashtableEntry<mtCode>;
|
||||
template class BasicHashtable<mtClass>;
|
||||
template class BasicHashtable<mtClassShared>;
|
||||
template class BasicHashtable<mtCode>;
|
||||
template class BasicHashtable<mtInternal>;
|
||||
template class BasicHashtable<mtModule>;
|
||||
template class BasicHashtable<mtCompiler>;
|
||||
|
Loading…
x
Reference in New Issue
Block a user