--- old/src/share/vm/runtime/sharedRuntime.cpp 2015-10-30 00:19:42.000000000 +0300 +++ new/src/share/vm/runtime/sharedRuntime.cpp 2015-10-30 00:19:42.000000000 +0300 @@ -1076,6 +1076,85 @@ return find_callee_info_helper(thread, vfst, bc, callinfo, THREAD); } +methodHandle SharedRuntime::extract_attached_call_info(JavaThread* thread) { + ResourceMark rm(thread); + RegisterMap cbl_map(thread, false); + frame caller_frame = thread->last_frame().sender(&cbl_map); + CodeBlob* caller_cb = caller_frame.cb(); + guarantee(caller_cb != NULL && caller_cb->is_nmethod(), "must be called from nmethod"); + nmethod* caller_nm = caller_cb->as_nmethod_or_null(); + + //assert(caller_nm is locked)); + + NativeCall* call = nativeCall_before(caller_frame.pc()); + RelocIterator iter(caller_nm, call->instruction_address()); + while (iter.next()) { + if (iter.addr() == call->instruction_address()) { + switch(iter.type()) { + case relocInfo::static_call_type: return iter.static_call_reloc()->method_value(); + case relocInfo::opt_virtual_call_type: return iter.opt_virtual_call_reloc()->method_value(); + case relocInfo::virtual_call_type: return iter.virtual_call_reloc()->method_value(); + default: + fatal("unexpected reloc type: %d", iter.type()); + } + } + } + return NULL; +} + +static Bytecodes::Code compute_bc(vmIntrinsics::ID id) { + switch(id) { + case vmIntrinsics::_linkToVirtual: return Bytecodes::_invokevirtual; + case vmIntrinsics::_linkToInterface: return Bytecodes::_invokeinterface; + case vmIntrinsics::_linkToStatic: return Bytecodes::_invokestatic; + case vmIntrinsics::_linkToSpecial: return Bytecodes::_invokespecial; + case vmIntrinsics::_invokeBasic: return Bytecodes::_invokestatic; + default: + fatal("unexpected id: (%d) %s", (uint)id, vmIntrinsics::name_at(id)); + return Bytecodes::_illegal; + } +} + +static Handle extract_receiver(JavaThread* thread, TRAPS) { + // 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); + frame stubFrame = thread->last_frame(); + // Caller-frame is a compiled frame + frame callerFrame = stubFrame.sender(®_map2); + // Retrieve from a compiled argument list + Handle receiver = Handle(THREAD, callerFrame.retrieve_receiver(®_map2)); + if (receiver.is_null()) { + THROW_(vmSymbols::java_lang_NullPointerException(), Handle()); + } + return receiver; +} + +void SharedRuntime::resolve_attached_call_info(JavaThread* thread, methodHandle info, Bytecodes::Code bc, + Handle& receiver, CallInfo& callinfo, TRAPS) { + KlassHandle defc = info->method_holder(); + Symbol* name = info->name(); + Symbol* type = info->signature(); + LinkInfo link_info(defc, name, type, KlassHandle(), /*check_access=*/false); + switch(bc) { + case Bytecodes::_invokevirtual: + LinkResolver::resolve_virtual_call(callinfo, receiver, receiver->klass(), + link_info, /*check_null_and_abstract=*/true, THREAD); + break; + case Bytecodes::_invokeinterface: + LinkResolver::resolve_interface_call(callinfo, receiver, receiver->klass(), + link_info, /*check_null_and_abstract=*/true, THREAD); + break; + case Bytecodes::_invokestatic: + LinkResolver::resolve_static_call(callinfo, link_info, /*initialize_class=*/false, THREAD); + break; + case Bytecodes::_invokespecial: + LinkResolver::resolve_special_call(callinfo, link_info, THREAD); + break; + default: + fatal("bad call"); + } +} // Finds receiver, CallInfo (i.e. receiver method), and calling bytecode // for a call current in progress, i.e., arguments has been pushed on stack @@ -1126,6 +1205,21 @@ assert(receiver.is_null() || receiver->is_oop(), "wrong receiver"); LinkResolver::resolve_invoke(callinfo, receiver, constants, bytecode_index, bc, CHECK_(nullHandle)); + // When VM replaces MH.invokeBasic/linkTo* call with a direct/virtual call, + // it attaches statically resolved method to the call site. + methodHandle call_info; + vmIntrinsics::ID id = callinfo.resolved_method()->intrinsic_id(); + if (MethodHandles::is_signature_polymorphic(id) && id != vmIntrinsics::_invokeGeneric) { + call_info = extract_attached_call_info(thread); + if (!call_info.is_null()) { + bc = compute_bc(id); + // Find receiver for non-static call + if (bc != Bytecodes::_invokestatic) { + receiver = extract_receiver(thread, CHECK_(nullHandle)); + } + resolve_attached_call_info(thread, call_info, bc, receiver, callinfo, 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 && bc != Bytecodes::_invokehandle) { @@ -1133,14 +1227,13 @@ KlassHandle receiver_klass(THREAD, receiver->klass()); Klass* rk = constants->klass_ref_at(bytecode_index, CHECK_(nullHandle)); // klass is already loaded + if (!call_info.is_null()) { + // In case there's resolved method attached, use it's holder during the check. + rk = call_info->method_holder(); + } 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(), + assert(receiver_klass->is_subtype_of(static_receiver_klass()), "actual receiver must be subclass of static receiver klass"); if (receiver_klass->oop_is_instance()) { if (InstanceKlass::cast(receiver_klass())->is_not_initialized()) {