mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 06:14:49 +02:00
Merge
This commit is contained in:
commit
134e70e53b
56 changed files with 1472 additions and 437 deletions
|
@ -1033,10 +1033,20 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method(JavaThread* thread))
|
|||
address sender_pc = caller_frame.pc();
|
||||
CodeBlob* sender_cb = caller_frame.cb();
|
||||
nmethod* sender_nm = sender_cb->as_nmethod_or_null();
|
||||
bool is_mh_invoke_via_adapter = false; // Direct c2c call or via adapter?
|
||||
if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) {
|
||||
// If the callee_target is set, then we have come here via an i2c
|
||||
// adapter.
|
||||
methodOop callee = thread->callee_target();
|
||||
if (callee != NULL) {
|
||||
assert(callee->is_method(), "sanity");
|
||||
is_mh_invoke_via_adapter = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (caller_frame.is_interpreted_frame() ||
|
||||
caller_frame.is_entry_frame() ||
|
||||
(sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc))) {
|
||||
caller_frame.is_entry_frame() ||
|
||||
is_mh_invoke_via_adapter) {
|
||||
methodOop callee = thread->callee_target();
|
||||
guarantee(callee != NULL && callee->is_method(), "bad handshake");
|
||||
thread->set_vm_result(callee);
|
||||
|
@ -1351,7 +1361,7 @@ methodHandle SharedRuntime::reresolve_call_site(JavaThread *thread, TRAPS) {
|
|||
// We are calling the interpreter via a c2i. Normally this would mean that
|
||||
// we were called by a compiled method. However we could have lost a race
|
||||
// where we went int -> i2c -> c2i and so the caller could in fact be
|
||||
// interpreted. If the caller is compiled we attampt to patch the caller
|
||||
// interpreted. If the caller is compiled we attempt to patch the caller
|
||||
// so he no longer calls into the interpreter.
|
||||
IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, address caller_pc))
|
||||
methodOop moop(method);
|
||||
|
@ -1367,10 +1377,19 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, addr
|
|||
// we did we'd leap into space because the callsite needs to use
|
||||
// "to interpreter" stub in order to load up the methodOop. Don't
|
||||
// ask me how I know this...
|
||||
//
|
||||
|
||||
CodeBlob* cb = CodeCache::find_blob(caller_pc);
|
||||
if ( !cb->is_nmethod() || entry_point == moop->get_c2i_entry()) {
|
||||
if (!cb->is_nmethod() || entry_point == moop->get_c2i_entry()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The check above makes sure this is a nmethod.
|
||||
nmethod* nm = cb->as_nmethod_or_null();
|
||||
assert(nm, "must be");
|
||||
|
||||
// Don't fixup MethodHandle call sites as c2i/i2c adapters are used
|
||||
// to implement MethodHandle actions.
|
||||
if (nm->is_method_handle_return(caller_pc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1385,7 +1404,7 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, addr
|
|||
|
||||
if (moop->code() == NULL) return;
|
||||
|
||||
if (((nmethod*)cb)->is_in_use()) {
|
||||
if (nm->is_in_use()) {
|
||||
|
||||
// Expect to find a native call there (unless it was no-inline cache vtable dispatch)
|
||||
MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
@ -1417,7 +1436,7 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, addr
|
|||
if (callee == cb || callee->is_adapter_blob()) {
|
||||
// static call or optimized virtual
|
||||
if (TraceCallFixup) {
|
||||
tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
|
||||
tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
|
||||
moop->print_short_name(tty);
|
||||
tty->print_cr(" to " INTPTR_FORMAT, entry_point);
|
||||
}
|
||||
|
@ -1433,7 +1452,7 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, addr
|
|||
}
|
||||
} else {
|
||||
if (TraceCallFixup) {
|
||||
tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
|
||||
tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
|
||||
moop->print_short_name(tty);
|
||||
tty->print_cr(" to " INTPTR_FORMAT, entry_point);
|
||||
}
|
||||
|
@ -1787,55 +1806,78 @@ void SharedRuntime::print_call_statistics(int comp_total) {
|
|||
class AdapterFingerPrint : public CHeapObj {
|
||||
private:
|
||||
union {
|
||||
signed char _compact[12];
|
||||
int _compact_int[3];
|
||||
intptr_t* _fingerprint;
|
||||
int _compact[3];
|
||||
int* _fingerprint;
|
||||
} _value;
|
||||
int _length; // A negative length indicates that _value._fingerprint is the array.
|
||||
// Otherwise it's in the compact form.
|
||||
int _length; // A negative length indicates the fingerprint is in the compact form,
|
||||
// Otherwise _value._fingerprint is the array.
|
||||
|
||||
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;
|
||||
// Remap BasicTypes that are handled equivalently by the adapters.
|
||||
// These are correct for the current system but someday it might be
|
||||
// necessary to make this mapping platform dependent.
|
||||
static BasicType adapter_encoding(BasicType in) {
|
||||
assert((~0xf & in) == 0, "must fit in 4 bits");
|
||||
switch(in) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE:
|
||||
case T_SHORT:
|
||||
case T_CHAR:
|
||||
// There are all promoted to T_INT in the calling convention
|
||||
return T_INT;
|
||||
|
||||
case T_OBJECT:
|
||||
case T_ARRAY:
|
||||
if (!TaggedStackInterpreter) {
|
||||
#ifdef _LP64
|
||||
return T_LONG;
|
||||
#else
|
||||
return T_INT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
_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;
|
||||
return T_OBJECT;
|
||||
|
||||
case T_INT:
|
||||
case T_LONG:
|
||||
case T_FLOAT:
|
||||
case T_DOUBLE:
|
||||
case T_VOID:
|
||||
return in;
|
||||
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return T_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
AdapterFingerPrint(AdapterFingerPrint* orig) {
|
||||
_length = orig->_length;
|
||||
_value = orig->_value;
|
||||
// take ownership of any storage by destroying the length
|
||||
orig->_length = 0;
|
||||
public:
|
||||
AdapterFingerPrint(int total_args_passed, BasicType* sig_bt) {
|
||||
// The fingerprint is based on the BasicType signature encoded
|
||||
// into an array of ints with four entries per int.
|
||||
int* ptr;
|
||||
int len = (total_args_passed + 3) >> 2;
|
||||
if (len <= (int)(sizeof(_value._compact) / sizeof(int))) {
|
||||
_value._compact[0] = _value._compact[1] = _value._compact[2] = 0;
|
||||
// Storing the signature encoded as signed chars hits about 98%
|
||||
// of the time.
|
||||
_length = -len;
|
||||
ptr = _value._compact;
|
||||
} else {
|
||||
_length = len;
|
||||
_value._fingerprint = NEW_C_HEAP_ARRAY(int, _length);
|
||||
ptr = _value._fingerprint;
|
||||
}
|
||||
|
||||
// Now pack the BasicTypes with 4 per int
|
||||
int sig_index = 0;
|
||||
for (int index = 0; index < len; index++) {
|
||||
int value = 0;
|
||||
for (int byte = 0; byte < 4; byte++) {
|
||||
if (sig_index < total_args_passed) {
|
||||
value = (value << 4) | adapter_encoding(sig_bt[sig_index++]);
|
||||
}
|
||||
}
|
||||
ptr[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
~AdapterFingerPrint() {
|
||||
|
@ -1844,11 +1886,7 @@ class AdapterFingerPrint : public CHeapObj {
|
|||
}
|
||||
}
|
||||
|
||||
AdapterFingerPrint* allocate() {
|
||||
return new AdapterFingerPrint(this);
|
||||
}
|
||||
|
||||
intptr_t value(int index) {
|
||||
int value(int index) {
|
||||
if (_length < 0) {
|
||||
return _value._compact[index];
|
||||
}
|
||||
|
@ -1864,9 +1902,9 @@ class AdapterFingerPrint : public CHeapObj {
|
|||
}
|
||||
|
||||
unsigned int compute_hash() {
|
||||
intptr_t hash = 0;
|
||||
int hash = 0;
|
||||
for (int i = 0; i < length(); i++) {
|
||||
intptr_t v = value(i);
|
||||
int v = value(i);
|
||||
hash = (hash << 8) ^ v ^ (hash >> 5);
|
||||
}
|
||||
return (unsigned int)hash;
|
||||
|
@ -1885,9 +1923,9 @@ class AdapterFingerPrint : public CHeapObj {
|
|||
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];
|
||||
return _value._compact[0] == other->_value._compact[0] &&
|
||||
_value._compact[1] == other->_value._compact[1] &&
|
||||
_value._compact[2] == other->_value._compact[2];
|
||||
} else {
|
||||
for (int i = 0; i < _length; i++) {
|
||||
if (_value._fingerprint[i] != other->_value._fingerprint[i]) {
|
||||
|
@ -1935,10 +1973,15 @@ class AdapterHandlerTable : public BasicHashtable {
|
|||
add_entry(index, entry);
|
||||
}
|
||||
|
||||
void free_entry(AdapterHandlerEntry* entry) {
|
||||
entry->deallocate();
|
||||
BasicHashtable::free_entry(entry);
|
||||
}
|
||||
|
||||
// Find a entry with the same fingerprint if it exists
|
||||
AdapterHandlerEntry* lookup(int total_args_passed, VMRegPair* regs) {
|
||||
AdapterHandlerEntry* lookup(int total_args_passed, BasicType* sig_bt) {
|
||||
debug_only(_lookups++);
|
||||
AdapterFingerPrint fp(total_args_passed, regs);
|
||||
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()) {
|
||||
|
@ -2110,17 +2153,26 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) {
|
|||
}
|
||||
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
|
||||
entry = _adapters->lookup(total_args_passed, regs);
|
||||
entry = _adapters->lookup(total_args_passed, sig_bt);
|
||||
|
||||
#ifdef ASSERT
|
||||
AdapterHandlerEntry* shared_entry = NULL;
|
||||
if (VerifyAdapterSharing && entry != NULL) {
|
||||
shared_entry = entry;
|
||||
entry = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (entry != NULL) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// Make a C heap allocated version of the fingerprint to store in the adapter
|
||||
fingerprint = new AdapterFingerPrint(total_args_passed, regs);
|
||||
fingerprint = new AdapterFingerPrint(total_args_passed, sig_bt);
|
||||
|
||||
// Create I2C & C2I handlers
|
||||
|
||||
|
@ -2139,6 +2191,20 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) {
|
|||
regs,
|
||||
fingerprint);
|
||||
|
||||
#ifdef ASSERT
|
||||
if (VerifyAdapterSharing) {
|
||||
if (shared_entry != NULL) {
|
||||
assert(shared_entry->compare_code(buf->instructions_begin(), buffer.code_size(), total_args_passed, sig_bt),
|
||||
"code must match");
|
||||
// Release the one just created and return the original
|
||||
_adapters->free_entry(entry);
|
||||
return shared_entry;
|
||||
} else {
|
||||
entry->save_code(buf->instructions_begin(), buffer.code_size(), total_args_passed, sig_bt);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
B = BufferBlob::create(AdapterHandlerEntry::name, &buffer);
|
||||
NOT_PRODUCT(code_size = buffer.code_size());
|
||||
}
|
||||
|
@ -2146,19 +2212,8 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) {
|
|||
// CodeCache is full, disable compilation
|
||||
// Ought to log this but compile log is only per compile thread
|
||||
// and we're some non descript Java thread.
|
||||
UseInterpreter = true;
|
||||
if (UseCompiler || AlwaysCompileLoopMethods ) {
|
||||
#ifndef PRODUCT
|
||||
warning("CodeCache is full. Compiler has been disabled");
|
||||
if (CompileTheWorld || ExitOnFullCodeCache) {
|
||||
before_exit(JavaThread::current());
|
||||
exit_globals(); // will delete tty
|
||||
vm_direct_exit(CompileTheWorld ? 0 : 1);
|
||||
}
|
||||
#endif
|
||||
UseCompiler = false;
|
||||
AlwaysCompileLoopMethods = false;
|
||||
}
|
||||
MutexUnlocker mu(AdapterHandlerLibrary_lock);
|
||||
CompileBroker::handle_full_code_cache();
|
||||
return NULL; // Out of CodeCache space
|
||||
}
|
||||
entry->relocate(B->instructions_begin());
|
||||
|
@ -2204,6 +2259,44 @@ void AdapterHandlerEntry::relocate(address new_base) {
|
|||
_c2i_unverified_entry += delta;
|
||||
}
|
||||
|
||||
|
||||
void AdapterHandlerEntry::deallocate() {
|
||||
delete _fingerprint;
|
||||
#ifdef ASSERT
|
||||
if (_saved_code) FREE_C_HEAP_ARRAY(unsigned char, _saved_code);
|
||||
if (_saved_sig) FREE_C_HEAP_ARRAY(Basictype, _saved_sig);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef ASSERT
|
||||
// Capture the code before relocation so that it can be compared
|
||||
// against other versions. If the code is captured after relocation
|
||||
// then relative instructions won't be equivalent.
|
||||
void AdapterHandlerEntry::save_code(unsigned char* buffer, int length, int total_args_passed, BasicType* sig_bt) {
|
||||
_saved_code = NEW_C_HEAP_ARRAY(unsigned char, length);
|
||||
_code_length = length;
|
||||
memcpy(_saved_code, buffer, length);
|
||||
_total_args_passed = total_args_passed;
|
||||
_saved_sig = NEW_C_HEAP_ARRAY(BasicType, _total_args_passed);
|
||||
memcpy(_saved_sig, sig_bt, _total_args_passed * sizeof(BasicType));
|
||||
}
|
||||
|
||||
|
||||
bool AdapterHandlerEntry::compare_code(unsigned char* buffer, int length, int total_args_passed, BasicType* sig_bt) {
|
||||
if (length != _code_length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (buffer[i] != _saved_code[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Create a native wrapper for this native method. The wrapper converts the
|
||||
// java compiled calling convention to the native convention, handlizes
|
||||
// arguments, and transitions to native. On return from the native we transition
|
||||
|
@ -2282,19 +2375,8 @@ nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method) {
|
|||
// CodeCache is full, disable compilation
|
||||
// Ought to log this but compile log is only per compile thread
|
||||
// and we're some non descript Java thread.
|
||||
UseInterpreter = true;
|
||||
if (UseCompiler || AlwaysCompileLoopMethods ) {
|
||||
#ifndef PRODUCT
|
||||
warning("CodeCache is full. Compiler has been disabled");
|
||||
if (CompileTheWorld || ExitOnFullCodeCache) {
|
||||
before_exit(JavaThread::current());
|
||||
exit_globals(); // will delete tty
|
||||
vm_direct_exit(CompileTheWorld ? 0 : 1);
|
||||
}
|
||||
#endif
|
||||
UseCompiler = false;
|
||||
AlwaysCompileLoopMethods = false;
|
||||
}
|
||||
MutexUnlocker mu(AdapterHandlerLibrary_lock);
|
||||
CompileBroker::handle_full_code_cache();
|
||||
}
|
||||
return nm;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue