6911204: generated adapters with large signatures can fill up the code cache
Reviewed-by: kvn, jrose
This commit is contained in:
parent
ae60c05fee
commit
bac125984c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2010 Sun Microsystems, Inc. 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
|
||||
@ -1189,7 +1189,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
// VMReg max_arg,
|
||||
int comp_args_on_stack, // VMRegStackSlots
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint) {
|
||||
address i2c_entry = __ pc();
|
||||
|
||||
AdapterGenerator agen(masm);
|
||||
@ -1258,7 +1259,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
||||
|
||||
__ flush();
|
||||
return new AdapterHandlerEntry(i2c_entry, c2i_entry, c2i_unverified_entry);
|
||||
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2010 Sun Microsystems, Inc. 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
|
||||
@ -907,7 +907,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint) {
|
||||
address i2c_entry = __ pc();
|
||||
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
@ -954,7 +955,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
||||
|
||||
__ flush();
|
||||
return new AdapterHandlerEntry(i2c_entry, c2i_entry, c2i_unverified_entry);
|
||||
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
||||
}
|
||||
|
||||
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2010 Sun Microsystems, Inc. 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
|
||||
@ -778,7 +778,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint) {
|
||||
address i2c_entry = __ pc();
|
||||
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
@ -824,7 +825,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
||||
|
||||
__ flush();
|
||||
return new AdapterHandlerEntry(i2c_entry, c2i_entry, c2i_unverified_entry);
|
||||
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
||||
}
|
||||
|
||||
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||
|
@ -921,6 +921,7 @@ classFileStream.hpp top.hpp
|
||||
|
||||
classLoader.cpp allocation.inline.hpp
|
||||
classLoader.cpp arguments.hpp
|
||||
classLoader.cpp bytecodeStream.hpp
|
||||
classLoader.cpp classFileParser.hpp
|
||||
classLoader.cpp classFileStream.hpp
|
||||
classLoader.cpp classLoader.hpp
|
||||
@ -948,6 +949,7 @@ classLoader.cpp jvm_misc.hpp
|
||||
classLoader.cpp management.hpp
|
||||
classLoader.cpp oop.inline.hpp
|
||||
classLoader.cpp oopFactory.hpp
|
||||
classLoader.cpp oopMapCache.hpp
|
||||
classLoader.cpp os_<os_family>.inline.hpp
|
||||
classLoader.cpp symbolOop.hpp
|
||||
classLoader.cpp systemDictionary.hpp
|
||||
@ -3724,6 +3726,7 @@ sharedRuntime.cpp events.hpp
|
||||
sharedRuntime.cpp forte.hpp
|
||||
sharedRuntime.cpp gcLocker.inline.hpp
|
||||
sharedRuntime.cpp handles.inline.hpp
|
||||
sharedRuntime.cpp hashtable.inline.hpp
|
||||
sharedRuntime.cpp init.hpp
|
||||
sharedRuntime.cpp interfaceSupport.hpp
|
||||
sharedRuntime.cpp interpreterRuntime.hpp
|
||||
@ -3751,6 +3754,7 @@ sharedRuntime.cpp xmlstream.hpp
|
||||
sharedRuntime.hpp allocation.hpp
|
||||
sharedRuntime.hpp bytecodeHistogram.hpp
|
||||
sharedRuntime.hpp bytecodeTracer.hpp
|
||||
sharedRuntime.hpp hashtable.hpp
|
||||
sharedRuntime.hpp linkResolver.hpp
|
||||
sharedRuntime.hpp resourceArea.hpp
|
||||
sharedRuntime.hpp threadLocalStorage.hpp
|
||||
|
@ -688,7 +688,7 @@ address methodOopDesc::make_adapters(methodHandle mh, TRAPS) {
|
||||
// so making them eagerly shouldn't be too expensive.
|
||||
AdapterHandlerEntry* adapter = AdapterHandlerLibrary::get_adapter(mh);
|
||||
if (adapter == NULL ) {
|
||||
THROW_0(vmSymbols::java_lang_OutOfMemoryError());
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_VirtualMachineError(), "out of space in CodeCache for adapters");
|
||||
}
|
||||
|
||||
mh->set_adapter_entry(adapter);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2010 Sun Microsystems, Inc. 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
|
||||
@ -1680,6 +1680,8 @@ void SharedRuntime::print_statistics() {
|
||||
if( _find_handler_ctr ) tty->print_cr("%5d find exception handler", _find_handler_ctr );
|
||||
if( _rethrow_ctr ) tty->print_cr("%5d rethrow handler", _rethrow_ctr );
|
||||
|
||||
AdapterHandlerLibrary::print_statistics();
|
||||
|
||||
if (xtty != NULL) xtty->tail("statistics");
|
||||
}
|
||||
|
||||
@ -1780,11 +1782,258 @@ void SharedRuntime::print_call_statistics(int comp_total) {
|
||||
#endif
|
||||
|
||||
|
||||
// A simple wrapper class around the calling convention information
|
||||
// that allows sharing of adapters for the same calling convention.
|
||||
class AdapterFingerPrint : public CHeapObj {
|
||||
private:
|
||||
union {
|
||||
signed char _compact[12];
|
||||
int _compact_int[3];
|
||||
intptr_t* _fingerprint;
|
||||
} _value;
|
||||
int _length; // A negative length indicates that _value._fingerprint is the array.
|
||||
// Otherwise it's in the compact form.
|
||||
|
||||
public:
|
||||
AdapterFingerPrint(int total_args_passed, VMRegPair* regs) {
|
||||
assert(sizeof(_value._compact) == sizeof(_value._compact_int), "must match");
|
||||
_length = total_args_passed * 2;
|
||||
if (_length < (int)sizeof(_value._compact)) {
|
||||
_value._compact_int[0] = _value._compact_int[1] = _value._compact_int[2] = 0;
|
||||
// Storing the signature encoded as signed chars hits about 98%
|
||||
// of the time.
|
||||
signed char* ptr = _value._compact;
|
||||
int o = 0;
|
||||
for (int i = 0; i < total_args_passed; i++) {
|
||||
VMRegPair pair = regs[i];
|
||||
intptr_t v1 = pair.first()->value();
|
||||
intptr_t v2 = pair.second()->value();
|
||||
if (v1 == (signed char) v1 &&
|
||||
v2 == (signed char) v2) {
|
||||
_value._compact[o++] = v1;
|
||||
_value._compact[o++] = v2;
|
||||
} else {
|
||||
goto big;
|
||||
}
|
||||
}
|
||||
_length = -_length;
|
||||
return;
|
||||
}
|
||||
big:
|
||||
_value._fingerprint = NEW_C_HEAP_ARRAY(intptr_t, _length);
|
||||
int o = 0;
|
||||
for (int i = 0; i < total_args_passed; i++) {
|
||||
VMRegPair pair = regs[i];
|
||||
intptr_t v1 = pair.first()->value();
|
||||
intptr_t v2 = pair.second()->value();
|
||||
_value._fingerprint[o++] = v1;
|
||||
_value._fingerprint[o++] = v2;
|
||||
}
|
||||
}
|
||||
|
||||
AdapterFingerPrint(AdapterFingerPrint* orig) {
|
||||
_length = orig->_length;
|
||||
_value = orig->_value;
|
||||
// take ownership of any storage by destroying the length
|
||||
orig->_length = 0;
|
||||
}
|
||||
|
||||
~AdapterFingerPrint() {
|
||||
if (_length > 0) {
|
||||
FREE_C_HEAP_ARRAY(int, _value._fingerprint);
|
||||
}
|
||||
}
|
||||
|
||||
AdapterFingerPrint* allocate() {
|
||||
return new AdapterFingerPrint(this);
|
||||
}
|
||||
|
||||
intptr_t value(int index) {
|
||||
if (_length < 0) {
|
||||
return _value._compact[index];
|
||||
}
|
||||
return _value._fingerprint[index];
|
||||
}
|
||||
int length() {
|
||||
if (_length < 0) return -_length;
|
||||
return _length;
|
||||
}
|
||||
|
||||
bool is_compact() {
|
||||
return _length <= 0;
|
||||
}
|
||||
|
||||
unsigned int compute_hash() {
|
||||
intptr_t hash = 0;
|
||||
for (int i = 0; i < length(); i++) {
|
||||
intptr_t v = value(i);
|
||||
hash = (hash << 8) ^ v ^ (hash >> 5);
|
||||
}
|
||||
return (unsigned int)hash;
|
||||
}
|
||||
|
||||
const char* as_string() {
|
||||
stringStream st;
|
||||
for (int i = 0; i < length(); i++) {
|
||||
st.print(PTR_FORMAT, value(i));
|
||||
}
|
||||
return st.as_string();
|
||||
}
|
||||
|
||||
bool equals(AdapterFingerPrint* other) {
|
||||
if (other->_length != _length) {
|
||||
return false;
|
||||
}
|
||||
if (_length < 0) {
|
||||
return _value._compact_int[0] == other->_value._compact_int[0] &&
|
||||
_value._compact_int[1] == other->_value._compact_int[1] &&
|
||||
_value._compact_int[2] == other->_value._compact_int[2];
|
||||
} else {
|
||||
for (int i = 0; i < _length; i++) {
|
||||
if (_value._fingerprint[i] != other->_value._fingerprint[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A hashtable mapping from AdapterFingerPrints to AdapterHandlerEntries
|
||||
class AdapterHandlerTable : public BasicHashtable {
|
||||
friend class AdapterHandlerTableIterator;
|
||||
|
||||
private:
|
||||
|
||||
#ifdef ASSERT
|
||||
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
|
||||
#endif
|
||||
|
||||
AdapterHandlerEntry* bucket(int i) {
|
||||
return (AdapterHandlerEntry*)BasicHashtable::bucket(i);
|
||||
}
|
||||
|
||||
public:
|
||||
AdapterHandlerTable()
|
||||
: BasicHashtable(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) {
|
||||
AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable::new_entry(fingerprint->compute_hash());
|
||||
entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Insert an entry into the table
|
||||
void add(AdapterHandlerEntry* entry) {
|
||||
int index = hash_to_index(entry->hash());
|
||||
add_entry(index, entry);
|
||||
}
|
||||
|
||||
// Find a entry with the same fingerprint if it exists
|
||||
AdapterHandlerEntry* lookup(int total_args_passed, VMRegPair* regs) {
|
||||
debug_only(_lookups++);
|
||||
AdapterFingerPrint fp(total_args_passed, regs);
|
||||
unsigned int hash = fp.compute_hash();
|
||||
int index = hash_to_index(hash);
|
||||
for (AdapterHandlerEntry* e = bucket(index); e != NULL; e = e->next()) {
|
||||
debug_only(_buckets++);
|
||||
if (e->hash() == hash) {
|
||||
debug_only(_equals++);
|
||||
if (fp.equals(e->fingerprint())) {
|
||||
#ifdef ASSERT
|
||||
if (fp.is_compact()) _compact++;
|
||||
_hits++;
|
||||
#endif
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
#ifdef ASSERT
|
||||
tty->print_cr("AdapterHandlerTable: lookups %d buckets %d equals %d hits %d compact %d",
|
||||
_lookups, _buckets, _equals, _hits, _compact);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#ifdef ASSERT
|
||||
|
||||
int AdapterHandlerTable::_lookups;
|
||||
int AdapterHandlerTable::_buckets;
|
||||
int AdapterHandlerTable::_equals;
|
||||
int AdapterHandlerTable::_hits;
|
||||
int AdapterHandlerTable::_compact;
|
||||
|
||||
class AdapterHandlerTableIterator : public StackObj {
|
||||
private:
|
||||
AdapterHandlerTable* _table;
|
||||
int _index;
|
||||
AdapterHandlerEntry* _current;
|
||||
|
||||
void scan() {
|
||||
while (_index < _table->table_size()) {
|
||||
AdapterHandlerEntry* a = _table->bucket(_index);
|
||||
if (a != NULL) {
|
||||
_current = a;
|
||||
return;
|
||||
}
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Implementation of AdapterHandlerLibrary
|
||||
const char* AdapterHandlerEntry::name = "I2C/C2I adapters";
|
||||
GrowableArray<uint64_t>* AdapterHandlerLibrary::_fingerprints = NULL;
|
||||
GrowableArray<AdapterHandlerEntry* >* AdapterHandlerLibrary::_handlers = NULL;
|
||||
AdapterHandlerTable* AdapterHandlerLibrary::_adapters = NULL;
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = NULL;
|
||||
const int AdapterHandlerLibrary_size = 16*K;
|
||||
BufferBlob* AdapterHandlerLibrary::_buffer = NULL;
|
||||
|
||||
@ -1796,28 +2045,31 @@ BufferBlob* AdapterHandlerLibrary::buffer_blob() {
|
||||
}
|
||||
|
||||
void AdapterHandlerLibrary::initialize() {
|
||||
if (_fingerprints != NULL) return;
|
||||
_fingerprints = new(ResourceObj::C_HEAP)GrowableArray<uint64_t>(32, true);
|
||||
_handlers = new(ResourceObj::C_HEAP)GrowableArray<AdapterHandlerEntry*>(32, true);
|
||||
// Index 0 reserved for the slow path handler
|
||||
_fingerprints->append(0/*the never-allowed 0 fingerprint*/);
|
||||
_handlers->append(NULL);
|
||||
if (_adapters != NULL) return;
|
||||
_adapters = new AdapterHandlerTable();
|
||||
|
||||
// Create a special handler for abstract methods. Abstract methods
|
||||
// are never compiled so an i2c entry is somewhat meaningless, but
|
||||
// fill it in with something appropriate just in case. Pass handle
|
||||
// wrong method for the c2i transitions.
|
||||
address wrong_method = SharedRuntime::get_handle_wrong_method_stub();
|
||||
_fingerprints->append(0/*the never-allowed 0 fingerprint*/);
|
||||
assert(_handlers->length() == AbstractMethodHandler, "in wrong slot");
|
||||
_handlers->append(new AdapterHandlerEntry(StubRoutines::throw_AbstractMethodError_entry(),
|
||||
wrong_method, wrong_method));
|
||||
_abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, NULL),
|
||||
StubRoutines::throw_AbstractMethodError_entry(),
|
||||
wrong_method, wrong_method);
|
||||
}
|
||||
|
||||
int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) {
|
||||
// Use customized signature handler. Need to lock around updates to the
|
||||
// _fingerprints array (it is not safe for concurrent readers and a single
|
||||
// writer: this can be fixed if it becomes a problem).
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint,
|
||||
address i2c_entry,
|
||||
address c2i_entry,
|
||||
address c2i_unverified_entry) {
|
||||
return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
||||
}
|
||||
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) {
|
||||
// Use customized signature handler. Need to lock around updates to
|
||||
// the AdapterHandlerTable (it is not safe for concurrent readers
|
||||
// and a single writer: this could be fixed if it becomes a
|
||||
// problem).
|
||||
|
||||
// Get the address of the ic_miss handlers before we grab the
|
||||
// AdapterHandlerLibrary_lock. This fixes bug 6236259 which
|
||||
@ -1828,47 +2080,49 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) {
|
||||
address ic_miss = SharedRuntime::get_ic_miss_stub();
|
||||
assert(ic_miss != NULL, "must have handler");
|
||||
|
||||
int result;
|
||||
ResourceMark rm;
|
||||
|
||||
NOT_PRODUCT(int code_size);
|
||||
BufferBlob *B = NULL;
|
||||
AdapterHandlerEntry* entry = NULL;
|
||||
uint64_t fingerprint;
|
||||
AdapterFingerPrint* fingerprint = NULL;
|
||||
{
|
||||
MutexLocker mu(AdapterHandlerLibrary_lock);
|
||||
// make sure data structure is initialized
|
||||
initialize();
|
||||
|
||||
if (method->is_abstract()) {
|
||||
return AbstractMethodHandler;
|
||||
return _abstract_method_handler;
|
||||
}
|
||||
|
||||
// Fill in the signature array, for the calling-convention call.
|
||||
int total_args_passed = method->size_of_parameters(); // All args on stack
|
||||
|
||||
BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed);
|
||||
VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
|
||||
int i = 0;
|
||||
if (!method->is_static()) // Pass in receiver first
|
||||
sig_bt[i++] = T_OBJECT;
|
||||
for (SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) {
|
||||
sig_bt[i++] = ss.type(); // Collect remaining bits of signature
|
||||
if (ss.type() == T_LONG || ss.type() == T_DOUBLE)
|
||||
sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots
|
||||
}
|
||||
assert(i == total_args_passed, "");
|
||||
|
||||
// Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
|
||||
int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
|
||||
|
||||
// Lookup method signature's fingerprint
|
||||
fingerprint = Fingerprinter(method).fingerprint();
|
||||
assert( fingerprint != CONST64( 0), "no zero fingerprints allowed" );
|
||||
// Fingerprints are small fixed-size condensed representations of
|
||||
// signatures. If the signature is too large, it won't fit in a
|
||||
// fingerprint. Signatures which cannot support a fingerprint get a new i2c
|
||||
// adapter gen'd each time, instead of searching the cache for one. This -1
|
||||
// game can be avoided if I compared signatures instead of using
|
||||
// fingerprints. However, -1 fingerprints are very rare.
|
||||
if( fingerprint != UCONST64(-1) ) { // If this is a cache-able fingerprint
|
||||
// Turns out i2c adapters do not care what the return value is. Mask it
|
||||
// out so signatures that only differ in return type will share the same
|
||||
// adapter.
|
||||
fingerprint &= ~(SignatureIterator::result_feature_mask << SignatureIterator::static_feature_size);
|
||||
// Search for a prior existing i2c/c2i adapter
|
||||
int index = _fingerprints->find(fingerprint);
|
||||
if( index >= 0 ) return index; // Found existing handlers?
|
||||
} else {
|
||||
// Annoyingly, I end up adding -1 fingerprints to the array of handlers,
|
||||
// because I need a unique handler index. It cannot be scanned for
|
||||
// because all -1's look alike. Instead, the matching index is passed out
|
||||
// and immediately used to collect the 2 return values (the c2i and i2c
|
||||
// adapters).
|
||||
entry = _adapters->lookup(total_args_passed, regs);
|
||||
if (entry != NULL) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Make a C heap allocated version of the fingerprint to store in the adapter
|
||||
fingerprint = new AdapterFingerPrint(total_args_passed, regs);
|
||||
|
||||
// Create I2C & C2I handlers
|
||||
ResourceMark rm;
|
||||
|
||||
BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache
|
||||
if (buf != NULL) {
|
||||
@ -1878,32 +2132,12 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) {
|
||||
sizeof(buffer_locs)/sizeof(relocInfo));
|
||||
MacroAssembler _masm(&buffer);
|
||||
|
||||
// Fill in the signature array, for the calling-convention call.
|
||||
int total_args_passed = method->size_of_parameters(); // All args on stack
|
||||
|
||||
BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType,total_args_passed);
|
||||
VMRegPair * regs = NEW_RESOURCE_ARRAY(VMRegPair ,total_args_passed);
|
||||
int i=0;
|
||||
if( !method->is_static() ) // Pass in receiver first
|
||||
sig_bt[i++] = T_OBJECT;
|
||||
for( SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) {
|
||||
sig_bt[i++] = ss.type(); // Collect remaining bits of signature
|
||||
if( ss.type() == T_LONG || ss.type() == T_DOUBLE )
|
||||
sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots
|
||||
}
|
||||
assert( i==total_args_passed, "" );
|
||||
|
||||
// Now get the re-packed compiled-Java layout.
|
||||
int comp_args_on_stack;
|
||||
|
||||
// Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
|
||||
comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
|
||||
|
||||
entry = SharedRuntime::generate_i2c2i_adapters(&_masm,
|
||||
total_args_passed,
|
||||
comp_args_on_stack,
|
||||
sig_bt,
|
||||
regs);
|
||||
regs,
|
||||
fingerprint);
|
||||
|
||||
B = BufferBlob::create(AdapterHandlerEntry::name, &buffer);
|
||||
NOT_PRODUCT(code_size = buffer.code_size());
|
||||
@ -1925,36 +2159,31 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) {
|
||||
UseCompiler = false;
|
||||
AlwaysCompileLoopMethods = false;
|
||||
}
|
||||
return 0; // Out of CodeCache space (_handlers[0] == NULL)
|
||||
return NULL; // Out of CodeCache space
|
||||
}
|
||||
entry->relocate(B->instructions_begin());
|
||||
#ifndef PRODUCT
|
||||
// debugging suppport
|
||||
if (PrintAdapterHandlers) {
|
||||
tty->cr();
|
||||
tty->print_cr("i2c argument handler #%d for: %s %s (fingerprint = 0x%llx, %d bytes generated)",
|
||||
_handlers->length(), (method->is_static() ? "static" : "receiver"),
|
||||
method->signature()->as_C_string(), fingerprint, code_size );
|
||||
tty->print_cr("i2c argument handler #%d for: %s %s (fingerprint = %s, %d bytes generated)",
|
||||
_adapters->number_of_entries(), (method->is_static() ? "static" : "receiver"),
|
||||
method->signature()->as_C_string(), fingerprint->as_string(), code_size );
|
||||
tty->print_cr("c2i argument handler starts at %p",entry->get_c2i_entry());
|
||||
Disassembler::decode(entry->get_i2c_entry(), entry->get_i2c_entry() + code_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
// add handlers to library
|
||||
_fingerprints->append(fingerprint);
|
||||
_handlers->append(entry);
|
||||
// set handler index
|
||||
assert(_fingerprints->length() == _handlers->length(), "sanity check");
|
||||
result = _fingerprints->length() - 1;
|
||||
_adapters->add(entry);
|
||||
}
|
||||
// Outside of the lock
|
||||
if (B != NULL) {
|
||||
char blob_id[256];
|
||||
jio_snprintf(blob_id,
|
||||
sizeof(blob_id),
|
||||
"%s(" PTR64_FORMAT ")@" PTR_FORMAT,
|
||||
"%s(%s)@" PTR_FORMAT,
|
||||
AdapterHandlerEntry::name,
|
||||
fingerprint,
|
||||
fingerprint->as_string(),
|
||||
B->instructions_begin());
|
||||
VTune::register_stub(blob_id, B->instructions_begin(), B->instructions_end());
|
||||
Forte::register_stub(blob_id, B->instructions_begin(), B->instructions_end());
|
||||
@ -1965,7 +2194,7 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) {
|
||||
B->instructions_end());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return entry;
|
||||
}
|
||||
|
||||
void AdapterHandlerEntry::relocate(address new_base) {
|
||||
@ -2308,30 +2537,31 @@ JRT_END
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool AdapterHandlerLibrary::contains(CodeBlob* b) {
|
||||
|
||||
if (_handlers == NULL) return false;
|
||||
|
||||
for (int i = 0 ; i < _handlers->length() ; i++) {
|
||||
AdapterHandlerEntry* a = get_entry(i);
|
||||
if ( a != NULL && b == CodeCache::find_blob(a->get_i2c_entry()) ) return true;
|
||||
AdapterHandlerTableIterator iter(_adapters);
|
||||
while (iter.has_next()) {
|
||||
AdapterHandlerEntry* a = iter.next();
|
||||
if ( b == CodeCache::find_blob(a->get_i2c_entry()) ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AdapterHandlerLibrary::print_handler(CodeBlob* b) {
|
||||
|
||||
for (int i = 0 ; i < _handlers->length() ; i++) {
|
||||
AdapterHandlerEntry* a = get_entry(i);
|
||||
if ( a != NULL && b == CodeCache::find_blob(a->get_i2c_entry()) ) {
|
||||
AdapterHandlerTableIterator iter(_adapters);
|
||||
while (iter.has_next()) {
|
||||
AdapterHandlerEntry* a = iter.next();
|
||||
if ( b == CodeCache::find_blob(a->get_i2c_entry()) ) {
|
||||
tty->print("Adapter for signature: ");
|
||||
// Fingerprinter::print(_fingerprints->at(i));
|
||||
tty->print("0x%" FORMAT64_MODIFIER "x", _fingerprints->at(i));
|
||||
tty->print_cr(" i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT,
|
||||
tty->print_cr("%s i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT,
|
||||
a->fingerprint()->as_string(),
|
||||
a->get_i2c_entry(), a->get_c2i_entry(), a->get_c2i_unverified_entry());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(false, "Should have found handler");
|
||||
}
|
||||
|
||||
void AdapterHandlerLibrary::print_statistics() {
|
||||
_adapters->print_statistics();
|
||||
}
|
||||
|
||||
#endif /* PRODUCT */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2010 Sun Microsystems, Inc. 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
|
||||
@ -23,6 +23,8 @@
|
||||
*/
|
||||
|
||||
class AdapterHandlerEntry;
|
||||
class AdapterHandlerTable;
|
||||
class AdapterFingerPrint;
|
||||
class vframeStream;
|
||||
|
||||
// Runtime is the base class for various runtime interfaces
|
||||
@ -337,7 +339,8 @@ class SharedRuntime: AllStatic {
|
||||
int total_args_passed,
|
||||
int max_arg,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs);
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint);
|
||||
|
||||
// OSR support
|
||||
|
||||
@ -528,28 +531,41 @@ 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 CHeapObj {
|
||||
class AdapterHandlerEntry : public BasicHashtableEntry {
|
||||
friend class AdapterHandlerTable;
|
||||
|
||||
private:
|
||||
AdapterFingerPrint* _fingerprint;
|
||||
address _i2c_entry;
|
||||
address _c2i_entry;
|
||||
address _c2i_unverified_entry;
|
||||
|
||||
public:
|
||||
void init(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry) {
|
||||
_fingerprint = fingerprint;
|
||||
_i2c_entry = i2c_entry;
|
||||
_c2i_entry = c2i_entry;
|
||||
_c2i_unverified_entry = c2i_unverified_entry;
|
||||
}
|
||||
|
||||
// should never be used
|
||||
AdapterHandlerEntry();
|
||||
|
||||
public:
|
||||
// The name we give all buffer blobs
|
||||
static const char* name;
|
||||
|
||||
AdapterHandlerEntry(address i2c_entry, address c2i_entry, address c2i_unverified_entry):
|
||||
_i2c_entry(i2c_entry),
|
||||
_c2i_entry(c2i_entry),
|
||||
_c2i_unverified_entry(c2i_unverified_entry) {
|
||||
}
|
||||
|
||||
address get_i2c_entry() { return _i2c_entry; }
|
||||
address get_c2i_entry() { return _c2i_entry; }
|
||||
address get_c2i_unverified_entry() { return _c2i_unverified_entry; }
|
||||
|
||||
void relocate(address new_base);
|
||||
|
||||
AdapterFingerPrint* fingerprint() { return _fingerprint; }
|
||||
|
||||
AdapterHandlerEntry* next() {
|
||||
return (AdapterHandlerEntry*)BasicHashtableEntry::next();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void print();
|
||||
#endif /* PRODUCT */
|
||||
@ -558,30 +574,18 @@ class AdapterHandlerEntry : public CHeapObj {
|
||||
class AdapterHandlerLibrary: public AllStatic {
|
||||
private:
|
||||
static BufferBlob* _buffer; // the temporary code buffer in CodeCache
|
||||
static GrowableArray<uint64_t>* _fingerprints; // the fingerprint collection
|
||||
static GrowableArray<AdapterHandlerEntry*> * _handlers; // the corresponding handlers
|
||||
enum {
|
||||
AbstractMethodHandler = 1 // special handler for abstract methods
|
||||
};
|
||||
static AdapterHandlerTable* _adapters;
|
||||
static AdapterHandlerEntry* _abstract_method_handler;
|
||||
static BufferBlob* buffer_blob();
|
||||
static void initialize();
|
||||
static int get_create_adapter_index(methodHandle method);
|
||||
static address get_i2c_entry( int index ) {
|
||||
return get_entry(index)->get_i2c_entry();
|
||||
}
|
||||
static address get_c2i_entry( int index ) {
|
||||
return get_entry(index)->get_c2i_entry();
|
||||
}
|
||||
static address get_c2i_unverified_entry( int index ) {
|
||||
return get_entry(index)->get_c2i_unverified_entry();
|
||||
}
|
||||
|
||||
public:
|
||||
static AdapterHandlerEntry* get_entry( int index ) { return _handlers->at(index); }
|
||||
|
||||
static AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint,
|
||||
address i2c_entry, address c2i_entry, address c2i_unverified_entry);
|
||||
static nmethod* create_native_wrapper(methodHandle method);
|
||||
static AdapterHandlerEntry* get_adapter(methodHandle method) {
|
||||
return get_entry(get_create_adapter_index(method));
|
||||
}
|
||||
static AdapterHandlerEntry* get_adapter(methodHandle method);
|
||||
|
||||
#ifdef HAVE_DTRACE_H
|
||||
static nmethod* create_dtrace_nmethod (methodHandle method);
|
||||
#endif // HAVE_DTRACE_H
|
||||
@ -589,6 +593,7 @@ class AdapterHandlerLibrary: public AllStatic {
|
||||
#ifndef PRODUCT
|
||||
static void print_handler(CodeBlob* b);
|
||||
static bool contains(CodeBlob* b);
|
||||
static void print_statistics();
|
||||
#endif /* PRODUCT */
|
||||
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user