mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
7023639: JSR 292 method handle invocation needs a fast path for compiled code
6984705: JSR 292 method handle creation should not go through JNI Remove assembly code for JDK 7 chained method handles Co-authored-by: John Rose <john.r.rose@oracle.com> Co-authored-by: Michael Haupt <michael.haupt@oracle.com> Reviewed-by: jrose, twisti, kvn, mhaupt
This commit is contained in:
parent
893817c28d
commit
12901d0e5b
181 changed files with 5760 additions and 14402 deletions
|
@ -88,8 +88,6 @@ RuntimeStub* SharedRuntime::_resolve_virtual_call_blob;
|
|||
RuntimeStub* SharedRuntime::_resolve_static_call_blob;
|
||||
|
||||
DeoptimizationBlob* SharedRuntime::_deopt_blob;
|
||||
RicochetBlob* SharedRuntime::_ricochet_blob;
|
||||
|
||||
SafepointBlob* SharedRuntime::_polling_page_safepoint_handler_blob;
|
||||
SafepointBlob* SharedRuntime::_polling_page_return_handler_blob;
|
||||
|
||||
|
@ -109,7 +107,6 @@ void SharedRuntime::generate_stubs() {
|
|||
_polling_page_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), false);
|
||||
_polling_page_return_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), true);
|
||||
|
||||
generate_ricochet_blob();
|
||||
generate_deopt_blob();
|
||||
|
||||
#ifdef COMPILER2
|
||||
|
@ -117,33 +114,6 @@ void SharedRuntime::generate_stubs() {
|
|||
#endif // COMPILER2
|
||||
}
|
||||
|
||||
//----------------------------generate_ricochet_blob---------------------------
|
||||
void SharedRuntime::generate_ricochet_blob() {
|
||||
if (!EnableInvokeDynamic) return; // leave it as a null
|
||||
|
||||
// allocate space for the code
|
||||
ResourceMark rm;
|
||||
// setup code generation tools
|
||||
CodeBuffer buffer("ricochet_blob", 256 LP64_ONLY(+ 256), 256); // XXX x86 LP64L: 512, 512
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
|
||||
int bounce_offset = -1, exception_offset = -1, frame_size_in_words = -1;
|
||||
MethodHandles::RicochetFrame::generate_ricochet_blob(masm, &bounce_offset, &exception_offset, &frame_size_in_words);
|
||||
|
||||
// -------------
|
||||
// make sure all code is generated
|
||||
masm->flush();
|
||||
|
||||
// failed to generate?
|
||||
if (bounce_offset < 0 || exception_offset < 0 || frame_size_in_words < 0) {
|
||||
assert(false, "bad ricochet blob");
|
||||
return;
|
||||
}
|
||||
|
||||
_ricochet_blob = RicochetBlob::create(&buffer, bounce_offset, exception_offset, frame_size_in_words);
|
||||
}
|
||||
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifndef USDT2
|
||||
|
@ -527,10 +497,6 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thre
|
|||
if (Interpreter::contains(return_address)) {
|
||||
return Interpreter::rethrow_exception_entry();
|
||||
}
|
||||
// Ricochet frame unwind code
|
||||
if (SharedRuntime::ricochet_blob() != NULL && SharedRuntime::ricochet_blob()->returns_to_bounce_addr(return_address)) {
|
||||
return SharedRuntime::ricochet_blob()->exception_addr();
|
||||
}
|
||||
|
||||
guarantee(blob == NULL || !blob->is_runtime_stub(), "caller should have skipped stub");
|
||||
guarantee(!VtableStubs::contains(return_address), "NULL exceptions in vtables should have been handled already!");
|
||||
|
@ -768,13 +734,6 @@ JRT_ENTRY(void, SharedRuntime::throw_StackOverflowError(JavaThread* thread))
|
|||
throw_and_post_jvmti_exception(thread, exception);
|
||||
JRT_END
|
||||
|
||||
JRT_ENTRY(void, SharedRuntime::throw_WrongMethodTypeException(JavaThread* thread, oopDesc* required, oopDesc* actual))
|
||||
assert(thread == JavaThread::current() && required->is_oop() && actual->is_oop(), "bad args");
|
||||
ResourceMark rm;
|
||||
char* message = SharedRuntime::generate_wrong_method_type_message(thread, required, actual);
|
||||
throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_invoke_WrongMethodTypeException(), message);
|
||||
JRT_END
|
||||
|
||||
address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
|
||||
address pc,
|
||||
SharedRuntime::ImplicitExceptionKind exception_kind)
|
||||
|
@ -857,6 +816,12 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
|
|||
return StubRoutines::throw_NullPointerException_at_call_entry();
|
||||
}
|
||||
|
||||
if (nm->method()->is_method_handle_intrinsic()) {
|
||||
// exception happened inside MH dispatch code, similar to a vtable stub
|
||||
Events::log_exception(thread, "NullPointerException in MH adapter " INTPTR_FORMAT, pc);
|
||||
return StubRoutines::throw_NullPointerException_at_call_entry();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
_implicit_null_throws++;
|
||||
#endif
|
||||
|
@ -1045,16 +1010,17 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread,
|
|||
assert(!vfst.at_end(), "Java frame must exist");
|
||||
|
||||
// Find caller and bci from vframe
|
||||
methodHandle caller (THREAD, vfst.method());
|
||||
int bci = vfst.bci();
|
||||
methodHandle caller(THREAD, vfst.method());
|
||||
int bci = vfst.bci();
|
||||
|
||||
// Find bytecode
|
||||
Bytecode_invoke bytecode(caller, bci);
|
||||
bc = bytecode.java_code();
|
||||
bc = bytecode.invoke_code();
|
||||
int bytecode_index = bytecode.index();
|
||||
|
||||
// Find receiver for non-static call
|
||||
if (bc != Bytecodes::_invokestatic) {
|
||||
if (bc != Bytecodes::_invokestatic &&
|
||||
bc != Bytecodes::_invokedynamic) {
|
||||
// This register map must be update since we need to find the receiver for
|
||||
// compiled frames. The receiver might be in a register.
|
||||
RegisterMap reg_map2(thread);
|
||||
|
@ -1075,25 +1041,32 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread,
|
|||
}
|
||||
|
||||
// Resolve method. This is parameterized by bytecode.
|
||||
constantPoolHandle constants (THREAD, caller->constants());
|
||||
assert (receiver.is_null() || receiver->is_oop(), "wrong receiver");
|
||||
constantPoolHandle constants(THREAD, caller->constants());
|
||||
assert(receiver.is_null() || receiver->is_oop(), "wrong receiver");
|
||||
LinkResolver::resolve_invoke(callinfo, receiver, constants, bytecode_index, bc, CHECK_(nullHandle));
|
||||
|
||||
#ifdef ASSERT
|
||||
// Check that the receiver klass is of the right subtype and that it is initialized for virtual calls
|
||||
if (bc != Bytecodes::_invokestatic && bc != Bytecodes::_invokedynamic) {
|
||||
assert(receiver.not_null(), "should have thrown exception");
|
||||
KlassHandle receiver_klass (THREAD, receiver->klass());
|
||||
KlassHandle receiver_klass(THREAD, receiver->klass());
|
||||
klassOop rk = constants->klass_ref_at(bytecode_index, CHECK_(nullHandle));
|
||||
// klass is already loaded
|
||||
KlassHandle static_receiver_klass (THREAD, rk);
|
||||
assert(receiver_klass->is_subtype_of(static_receiver_klass()), "actual receiver must be subclass of static receiver klass");
|
||||
KlassHandle static_receiver_klass(THREAD, rk);
|
||||
// Method handle invokes might have been optimized to a direct call
|
||||
// so don't check for the receiver class.
|
||||
// FIXME this weakens the assert too much
|
||||
methodHandle callee = callinfo.selected_method();
|
||||
assert(receiver_klass->is_subtype_of(static_receiver_klass()) ||
|
||||
callee->is_method_handle_intrinsic() ||
|
||||
callee->is_compiled_lambda_form(),
|
||||
"actual receiver must be subclass of static receiver klass");
|
||||
if (receiver_klass->oop_is_instance()) {
|
||||
if (instanceKlass::cast(receiver_klass())->is_not_initialized()) {
|
||||
tty->print_cr("ERROR: Klass not yet initialized!!");
|
||||
receiver_klass.print();
|
||||
}
|
||||
assert (!instanceKlass::cast(receiver_klass())->is_not_initialized(), "receiver_klass must be initialized");
|
||||
assert(!instanceKlass::cast(receiver_klass())->is_not_initialized(), "receiver_klass must be initialized");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1186,8 +1159,10 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread,
|
|||
call_info, CHECK_(methodHandle()));
|
||||
methodHandle callee_method = call_info.selected_method();
|
||||
|
||||
assert((!is_virtual && invoke_code == Bytecodes::_invokestatic) ||
|
||||
( is_virtual && invoke_code != Bytecodes::_invokestatic), "inconsistent bytecode");
|
||||
assert((!is_virtual && invoke_code == Bytecodes::_invokestatic ) ||
|
||||
(!is_virtual && invoke_code == Bytecodes::_invokehandle ) ||
|
||||
(!is_virtual && invoke_code == Bytecodes::_invokedynamic) ||
|
||||
( is_virtual && invoke_code != Bytecodes::_invokestatic ), "inconsistent bytecode");
|
||||
|
||||
#ifndef PRODUCT
|
||||
// tracing/debugging/statistics
|
||||
|
@ -1202,16 +1177,17 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread,
|
|||
(is_optimized) ? "optimized " : "", (is_virtual) ? "virtual" : "static",
|
||||
Bytecodes::name(invoke_code));
|
||||
callee_method->print_short_name(tty);
|
||||
tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code());
|
||||
tty->print_cr(" at pc: " INTPTR_FORMAT " to code: " INTPTR_FORMAT, caller_frame.pc(), callee_method->code());
|
||||
}
|
||||
#endif
|
||||
|
||||
// JSR 292
|
||||
// JSR 292 key invariant:
|
||||
// If the resolved method is a MethodHandle invoke target the call
|
||||
// site must be a MethodHandle call site.
|
||||
if (callee_method->is_method_handle_invoke()) {
|
||||
assert(caller_nm->is_method_handle_return(caller_frame.pc()), "must be MH call site");
|
||||
}
|
||||
// site must be a MethodHandle call site, because the lambda form might tail-call
|
||||
// leaving the stack in a state unknown to either caller or callee
|
||||
// TODO detune for now but we might need it again
|
||||
// assert(!callee_method->is_compiled_lambda_form() ||
|
||||
// caller_nm->is_method_handle_return(caller_frame.pc()), "must be MH call site");
|
||||
|
||||
// Compute entry points. This might require generation of C2I converter
|
||||
// frames, so we cannot be holding any locks here. Furthermore, the
|
||||
|
@ -1284,7 +1260,6 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method_ic_miss(JavaThread*
|
|||
assert(stub_frame.is_runtime_frame(), "sanity check");
|
||||
frame caller_frame = stub_frame.sender(®_map);
|
||||
assert(!caller_frame.is_interpreted_frame() && !caller_frame.is_entry_frame(), "unexpected frame");
|
||||
assert(!caller_frame.is_ricochet_frame(), "unexpected frame");
|
||||
#endif /* ASSERT */
|
||||
|
||||
methodHandle callee_method;
|
||||
|
@ -1320,21 +1295,9 @@ 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() ||
|
||||
caller_frame.is_ricochet_frame() ||
|
||||
is_mh_invoke_via_adapter) {
|
||||
caller_frame.is_entry_frame()) {
|
||||
methodOop callee = thread->callee_target();
|
||||
guarantee(callee != NULL && callee->is_method(), "bad handshake");
|
||||
thread->set_vm_result(callee);
|
||||
|
@ -1677,12 +1640,6 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, addr
|
|||
// Get the return PC for the passed caller PC.
|
||||
address return_pc = caller_pc + frame::pc_return_offset;
|
||||
|
||||
// Don't fixup method handle call sites as the executed method
|
||||
// handle adapters are doing the required MethodHandle chain work.
|
||||
if (nm->is_method_handle_return(return_pc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// There is a benign race here. We could be attempting to patch to a compiled
|
||||
// entry point at the same time the callee is being deoptimized. If that is
|
||||
// the case then entry_point may in fact point to a c2i and we'd patch the
|
||||
|
@ -1788,97 +1745,6 @@ char* SharedRuntime::generate_class_cast_message(
|
|||
return generate_class_cast_message(objName, targetKlass->external_name());
|
||||
}
|
||||
|
||||
char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread,
|
||||
oopDesc* required,
|
||||
oopDesc* actual) {
|
||||
if (TraceMethodHandles) {
|
||||
tty->print_cr("WrongMethodType thread="PTR_FORMAT" req="PTR_FORMAT" act="PTR_FORMAT"",
|
||||
thread, required, actual);
|
||||
}
|
||||
assert(EnableInvokeDynamic, "");
|
||||
oop singleKlass = wrong_method_type_is_for_single_argument(thread, required);
|
||||
char* message = NULL;
|
||||
if (singleKlass != NULL) {
|
||||
const char* objName = "argument or return value";
|
||||
if (actual != NULL) {
|
||||
// be flexible about the junk passed in:
|
||||
klassOop ak = (actual->is_klass()
|
||||
? (klassOop)actual
|
||||
: actual->klass());
|
||||
objName = Klass::cast(ak)->external_name();
|
||||
}
|
||||
Klass* targetKlass = Klass::cast(required->is_klass()
|
||||
? (klassOop)required
|
||||
: java_lang_Class::as_klassOop(required));
|
||||
message = generate_class_cast_message(objName, targetKlass->external_name());
|
||||
} else {
|
||||
// %%% need to get the MethodType string, without messing around too much
|
||||
const char* desc = NULL;
|
||||
// Get a signature from the invoke instruction
|
||||
const char* mhName = "method handle";
|
||||
const char* targetType = "the required signature";
|
||||
int targetArity = -1, mhArity = -1;
|
||||
vframeStream vfst(thread, true);
|
||||
if (!vfst.at_end()) {
|
||||
Bytecode_invoke call(vfst.method(), vfst.bci());
|
||||
methodHandle target;
|
||||
{
|
||||
EXCEPTION_MARK;
|
||||
target = call.static_target(THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; }
|
||||
}
|
||||
if (target.not_null()
|
||||
&& target->is_method_handle_invoke()
|
||||
&& required == target->method_handle_type()) {
|
||||
targetType = target->signature()->as_C_string();
|
||||
targetArity = ArgumentCount(target->signature()).size();
|
||||
}
|
||||
}
|
||||
KlassHandle kignore; int dmf_flags = 0;
|
||||
methodHandle actual_method = MethodHandles::decode_method(actual, kignore, dmf_flags);
|
||||
if ((dmf_flags & ~(MethodHandles::_dmf_has_receiver |
|
||||
MethodHandles::_dmf_does_dispatch |
|
||||
MethodHandles::_dmf_from_interface)) != 0)
|
||||
actual_method = methodHandle(); // MH does extra binds, drops, etc.
|
||||
bool has_receiver = ((dmf_flags & MethodHandles::_dmf_has_receiver) != 0);
|
||||
if (actual_method.not_null()) {
|
||||
mhName = actual_method->signature()->as_C_string();
|
||||
mhArity = ArgumentCount(actual_method->signature()).size();
|
||||
if (!actual_method->is_static()) mhArity += 1;
|
||||
} else if (java_lang_invoke_MethodHandle::is_instance(actual)) {
|
||||
oopDesc* mhType = java_lang_invoke_MethodHandle::type(actual);
|
||||
mhArity = java_lang_invoke_MethodType::ptype_count(mhType);
|
||||
stringStream st;
|
||||
java_lang_invoke_MethodType::print_signature(mhType, &st);
|
||||
mhName = st.as_string();
|
||||
}
|
||||
if (targetArity != -1 && targetArity != mhArity) {
|
||||
if (has_receiver && targetArity == mhArity-1)
|
||||
desc = " cannot be called without a receiver argument as ";
|
||||
else
|
||||
desc = " cannot be called with a different arity as ";
|
||||
}
|
||||
message = generate_class_cast_message(mhName, targetType,
|
||||
desc != NULL ? desc :
|
||||
" cannot be called as ");
|
||||
}
|
||||
if (TraceMethodHandles) {
|
||||
tty->print_cr("WrongMethodType => message=%s", message);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
oop SharedRuntime::wrong_method_type_is_for_single_argument(JavaThread* thr,
|
||||
oopDesc* required) {
|
||||
if (required == NULL) return NULL;
|
||||
if (required->klass() == SystemDictionary::Class_klass())
|
||||
return required;
|
||||
if (required->is_klass())
|
||||
return Klass::cast(klassOop(required))->java_mirror();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char* SharedRuntime::generate_class_cast_message(
|
||||
const char* objName, const char* targetKlassName, const char* desc) {
|
||||
size_t msglen = strlen(objName) + strlen(desc) + strlen(targetKlassName) + 1;
|
||||
|
@ -2119,8 +1985,17 @@ void SharedRuntime::print_call_statistics(int comp_total) {
|
|||
// that allows sharing of adapters for the same calling convention.
|
||||
class AdapterFingerPrint : public CHeapObj<mtCode> {
|
||||
private:
|
||||
enum {
|
||||
_basic_type_bits = 4,
|
||||
_basic_type_mask = right_n_bits(_basic_type_bits),
|
||||
_basic_types_per_int = BitsPerInt / _basic_type_bits,
|
||||
_compact_int_count = 3
|
||||
};
|
||||
// TO DO: Consider integrating this with a more global scheme for compressing signatures.
|
||||
// For now, 4 bits per components (plus T_VOID gaps after double/long) is not excessive.
|
||||
|
||||
union {
|
||||
int _compact[3];
|
||||
int _compact[_compact_int_count];
|
||||
int* _fingerprint;
|
||||
} _value;
|
||||
int _length; // A negative length indicates the fingerprint is in the compact form,
|
||||
|
@ -2129,8 +2004,7 @@ class AdapterFingerPrint : public CHeapObj<mtCode> {
|
|||
// 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");
|
||||
static int adapter_encoding(BasicType in) {
|
||||
switch(in) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE:
|
||||
|
@ -2141,6 +2015,8 @@ class AdapterFingerPrint : public CHeapObj<mtCode> {
|
|||
|
||||
case T_OBJECT:
|
||||
case T_ARRAY:
|
||||
// In other words, we assume that any register good enough for
|
||||
// an int or long is good enough for a managed pointer.
|
||||
#ifdef _LP64
|
||||
return T_LONG;
|
||||
#else
|
||||
|
@ -2165,8 +2041,9 @@ class AdapterFingerPrint : public CHeapObj<mtCode> {
|
|||
// The fingerprint is based on the BasicType signature encoded
|
||||
// into an array of ints with eight entries per int.
|
||||
int* ptr;
|
||||
int len = (total_args_passed + 7) >> 3;
|
||||
if (len <= (int)(sizeof(_value._compact) / sizeof(int))) {
|
||||
int len = (total_args_passed + (_basic_types_per_int-1)) / _basic_types_per_int;
|
||||
if (len <= _compact_int_count) {
|
||||
assert(_compact_int_count == 3, "else change next line");
|
||||
_value._compact[0] = _value._compact[1] = _value._compact[2] = 0;
|
||||
// Storing the signature encoded as signed chars hits about 98%
|
||||
// of the time.
|
||||
|
@ -2182,10 +2059,12 @@ class AdapterFingerPrint : public CHeapObj<mtCode> {
|
|||
int sig_index = 0;
|
||||
for (int index = 0; index < len; index++) {
|
||||
int value = 0;
|
||||
for (int byte = 0; byte < 8; byte++) {
|
||||
if (sig_index < total_args_passed) {
|
||||
value = (value << 4) | adapter_encoding(sig_bt[sig_index++]);
|
||||
}
|
||||
for (int byte = 0; byte < _basic_types_per_int; byte++) {
|
||||
int bt = ((sig_index < total_args_passed)
|
||||
? adapter_encoding(sig_bt[sig_index++])
|
||||
: 0);
|
||||
assert((bt & _basic_type_mask) == bt, "must fit in 4 bits");
|
||||
value = (value << _basic_type_bits) | bt;
|
||||
}
|
||||
ptr[index] = value;
|
||||
}
|
||||
|
@ -2235,6 +2114,7 @@ class AdapterFingerPrint : public CHeapObj<mtCode> {
|
|||
return false;
|
||||
}
|
||||
if (_length < 0) {
|
||||
assert(_compact_int_count == 3, "else change next line");
|
||||
return _value._compact[0] == other->_value._compact[0] &&
|
||||
_value._compact[1] == other->_value._compact[1] &&
|
||||
_value._compact[2] == other->_value._compact[2];
|
||||
|
@ -2531,13 +2411,17 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) {
|
|||
entry->relocate(B->content_begin());
|
||||
#ifndef PRODUCT
|
||||
// debugging suppport
|
||||
if (PrintAdapterHandlers) {
|
||||
tty->cr();
|
||||
tty->print_cr("i2c argument handler #%d for: %s %s (fingerprint = %s, %d bytes generated)",
|
||||
if (PrintAdapterHandlers || PrintStubCode) {
|
||||
entry->print_adapter_on(tty);
|
||||
tty->print_cr("i2c argument handler #%d for: %s %s (%d bytes generated)",
|
||||
_adapters->number_of_entries(), (method->is_static() ? "static" : "receiver"),
|
||||
method->signature()->as_C_string(), fingerprint->as_string(), insts_size );
|
||||
method->signature()->as_C_string(), insts_size);
|
||||
tty->print_cr("c2i argument handler starts at %p",entry->get_c2i_entry());
|
||||
Disassembler::decode(entry->get_i2c_entry(), entry->get_i2c_entry() + insts_size);
|
||||
if (Verbose || PrintStubCode) {
|
||||
address first_pc = entry->base_address();
|
||||
if (first_pc != NULL)
|
||||
Disassembler::decode(first_pc, first_pc + insts_size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2561,11 +2445,25 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) {
|
|||
return entry;
|
||||
}
|
||||
|
||||
address AdapterHandlerEntry::base_address() {
|
||||
address base = _i2c_entry;
|
||||
if (base == NULL) base = _c2i_entry;
|
||||
assert(base <= _c2i_entry || _c2i_entry == NULL, "");
|
||||
assert(base <= _c2i_unverified_entry || _c2i_unverified_entry == NULL, "");
|
||||
return base;
|
||||
}
|
||||
|
||||
void AdapterHandlerEntry::relocate(address new_base) {
|
||||
ptrdiff_t delta = new_base - _i2c_entry;
|
||||
address old_base = base_address();
|
||||
assert(old_base != NULL, "");
|
||||
ptrdiff_t delta = new_base - old_base;
|
||||
if (_i2c_entry != NULL)
|
||||
_i2c_entry += delta;
|
||||
if (_c2i_entry != NULL)
|
||||
_c2i_entry += delta;
|
||||
if (_c2i_unverified_entry != NULL)
|
||||
_c2i_unverified_entry += delta;
|
||||
assert(base_address() == new_base, "");
|
||||
}
|
||||
|
||||
|
||||
|
@ -2614,7 +2512,9 @@ nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method, int c
|
|||
ResourceMark rm;
|
||||
nmethod* nm = NULL;
|
||||
|
||||
assert(method->has_native_function(), "must have something valid to call!");
|
||||
assert(method->is_native(), "must be native");
|
||||
assert(method->is_method_handle_intrinsic() ||
|
||||
method->has_native_function(), "must have something valid to call!");
|
||||
|
||||
{
|
||||
// perform the work while holding the lock, but perform any printing outside the lock
|
||||
|
@ -2651,9 +2551,11 @@ nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method, int c
|
|||
assert( i==total_args_passed, "" );
|
||||
BasicType ret_type = ss.type();
|
||||
|
||||
// Now get the compiled-Java layout as input arguments
|
||||
int comp_args_on_stack;
|
||||
comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
|
||||
// Now get the compiled-Java layout as input (or output) arguments.
|
||||
// NOTE: Stubs for compiled entry points of method handle intrinsics
|
||||
// are just trampolines so the argument registers must be outgoing ones.
|
||||
const bool is_outgoing = method->is_method_handle_intrinsic();
|
||||
int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, is_outgoing);
|
||||
|
||||
// Generate the compiled-to-native wrapper code
|
||||
nm = SharedRuntime::generate_native_wrapper(&_masm,
|
||||
|
@ -2939,18 +2841,22 @@ void AdapterHandlerLibrary::print_handler_on(outputStream* st, CodeBlob* b) {
|
|||
AdapterHandlerTableIterator iter(_adapters);
|
||||
while (iter.has_next()) {
|
||||
AdapterHandlerEntry* a = iter.next();
|
||||
if ( b == CodeCache::find_blob(a->get_i2c_entry()) ) {
|
||||
if (b == CodeCache::find_blob(a->get_i2c_entry())) {
|
||||
st->print("Adapter for signature: ");
|
||||
st->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());
|
||||
|
||||
a->print_adapter_on(tty);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(false, "Should have found handler");
|
||||
}
|
||||
|
||||
void AdapterHandlerEntry::print_adapter_on(outputStream* st) const {
|
||||
st->print_cr("AHE@" INTPTR_FORMAT ": %s i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT,
|
||||
(intptr_t) this, fingerprint()->as_string(),
|
||||
get_i2c_entry(), get_c2i_entry(), get_c2i_unverified_entry());
|
||||
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
void AdapterHandlerLibrary::print_statistics() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue