mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 03:24:38 +02:00
6815692: method handle code needs some cleanup (post-6655638)
Correctly raise exceptions, support safe bitwise "raw" conversions, fix bugs revealed by VerifyMethodHandles, remove dead code, improve debugging support Reviewed-by: never, twisti
This commit is contained in:
parent
9c6f603b85
commit
2134a92922
12 changed files with 274 additions and 120 deletions
|
@ -271,9 +271,15 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
|
|||
void trace_method_handle_stub(const char* adaptername,
|
||||
oopDesc* mh,
|
||||
intptr_t* entry_sp,
|
||||
intptr_t* saved_sp) {
|
||||
intptr_t* saved_sp,
|
||||
intptr_t* saved_bp) {
|
||||
// called as a leaf from native code: do not block the JVM!
|
||||
printf("MH %s "PTR_FORMAT" "PTR_FORMAT" "INTX_FORMAT"\n", adaptername, (void*)mh, entry_sp, entry_sp - saved_sp);
|
||||
intptr_t* last_sp = (intptr_t*) saved_bp[frame::interpreter_frame_last_sp_offset];
|
||||
intptr_t* base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset];
|
||||
printf("MH %s mh="INTPTR_FORMAT" sp=("INTPTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="INTPTR_FORMAT"\n",
|
||||
adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp);
|
||||
if (last_sp != saved_sp)
|
||||
printf("*** last_sp="INTPTR_FORMAT"\n", (intptr_t)last_sp);
|
||||
}
|
||||
#endif //PRODUCT
|
||||
|
||||
|
@ -293,6 +299,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
Register rbx_temp = rbx;
|
||||
Register rdx_temp = rdx;
|
||||
|
||||
// This guy is set up by prepare_to_jump_from_interpreted (from interpreted calls)
|
||||
// and gen_c2i_adapter (from compiled calls):
|
||||
Register saved_last_sp = LP64_ONLY(r13) NOT_LP64(rsi);
|
||||
|
||||
guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
|
||||
|
||||
// some handy addresses
|
||||
|
@ -315,6 +325,8 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
assert(tag_offset = wordSize, "stack grows as expected");
|
||||
}
|
||||
|
||||
const int java_mirror_offset = klassOopDesc::klass_part_offset_in_bytes() + Klass::java_mirror_offset_in_bytes();
|
||||
|
||||
if (have_entry(ek)) {
|
||||
__ nop(); // empty stubs make SG sick
|
||||
return;
|
||||
|
@ -328,45 +340,65 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
__ push(rax); __ push(rbx); __ push(rcx); __ push(rdx); __ push(rsi); __ push(rdi);
|
||||
__ lea(rax, Address(rsp, wordSize*6)); // entry_sp
|
||||
// arguments:
|
||||
__ push(rbp); // interpreter frame pointer
|
||||
__ push(rsi); // saved_sp
|
||||
__ push(rax); // entry_sp
|
||||
__ push(rcx); // mh
|
||||
__ push(rcx);
|
||||
__ movptr(Address(rsp, 0), (intptr_t)entry_name(ek));
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 4);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 5);
|
||||
__ pop(rdi); __ pop(rsi); __ pop(rdx); __ pop(rcx); __ pop(rbx); __ pop(rax);
|
||||
}
|
||||
#endif //PRODUCT
|
||||
|
||||
switch ((int) ek) {
|
||||
case _check_mtype:
|
||||
case _raise_exception:
|
||||
{
|
||||
// this stub is special, because it requires a live mtype argument
|
||||
Register rax_mtype = rax;
|
||||
// Not a real MH entry, but rather shared code for raising an exception.
|
||||
// Extra local arguments are pushed on stack, as required type at TOS+8,
|
||||
// failing object (or NULL) at TOS+4, failing bytecode type at TOS.
|
||||
// Beyond those local arguments are the PC, of course.
|
||||
Register rdx_code = rdx_temp;
|
||||
Register rcx_fail = rcx_recv;
|
||||
Register rax_want = rax_argslot;
|
||||
Register rdi_pc = rdi;
|
||||
__ pop(rdx_code); // TOS+0
|
||||
__ pop(rcx_fail); // TOS+4
|
||||
__ pop(rax_want); // TOS+8
|
||||
__ pop(rdi_pc); // caller PC
|
||||
|
||||
// emit WrongMethodType path first, to enable jccb back-branch
|
||||
Label wrong_method_type;
|
||||
__ bind(wrong_method_type);
|
||||
__ movptr(rdx_temp, ExternalAddress((address) &_entries[_wrong_method_type]));
|
||||
__ jmp(Address(rdx_temp, MethodHandleEntry::from_interpreted_entry_offset_in_bytes()));
|
||||
__ hlt();
|
||||
__ mov(rsp, rsi); // cut the stack back to where the caller started
|
||||
|
||||
interp_entry = __ pc();
|
||||
__ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
|
||||
// now rax_mtype is dead; subsequent stubs will use it as a temp
|
||||
// Repush the arguments as if coming from the interpreter.
|
||||
if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_INT));
|
||||
__ push(rdx_code);
|
||||
if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_OBJECT));
|
||||
__ push(rcx_fail);
|
||||
if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_OBJECT));
|
||||
__ push(rax_want);
|
||||
|
||||
__ jump_to_method_handle_entry(rcx_recv, rdx_temp);
|
||||
}
|
||||
break;
|
||||
Register rbx_method = rbx_temp;
|
||||
Label no_method;
|
||||
// FIXME: fill in _raise_exception_method with a suitable sun.dyn method
|
||||
__ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method));
|
||||
__ testptr(rbx_method, rbx_method);
|
||||
__ jcc(Assembler::zero, no_method);
|
||||
int jobject_oop_offset = 0;
|
||||
__ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject
|
||||
__ testptr(rbx_method, rbx_method);
|
||||
__ jcc(Assembler::zero, no_method);
|
||||
__ verify_oop(rbx_method);
|
||||
__ push(rdi_pc); // and restore caller PC
|
||||
__ jmp(rbx_method_fie);
|
||||
|
||||
case _wrong_method_type:
|
||||
{
|
||||
// this stub is special, because it requires a live mtype argument
|
||||
Register rax_mtype = rax;
|
||||
|
||||
interp_entry = __ pc();
|
||||
__ push(rax_mtype); // required mtype
|
||||
__ push(rcx_recv); // random mh (1st stacked argument)
|
||||
// If we get here, the Java runtime did not do its job of creating the exception.
|
||||
// Do something that is at least causes a valid throw from the interpreter.
|
||||
__ bind(no_method);
|
||||
__ pop(rax_want);
|
||||
if (TaggedStackInterpreter) __ pop(rcx_fail);
|
||||
__ pop(rcx_fail);
|
||||
__ push(rax_want);
|
||||
__ push(rcx_fail);
|
||||
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
|
||||
}
|
||||
break;
|
||||
|
@ -442,7 +474,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
__ load_klass(rax_klass, rcx_recv);
|
||||
__ verify_oop(rax_klass);
|
||||
|
||||
Register rcx_temp = rcx_recv;
|
||||
Register rdi_temp = rdi;
|
||||
Register rbx_method = rbx_index;
|
||||
|
||||
// get interface klass
|
||||
|
@ -451,7 +483,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
__ lookup_interface_method(rax_klass, rdx_intf,
|
||||
// note: next two args must be the same:
|
||||
rbx_index, rbx_method,
|
||||
rcx_temp,
|
||||
rdi_temp,
|
||||
no_such_interface);
|
||||
|
||||
__ verify_oop(rbx_method);
|
||||
|
@ -461,7 +493,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
__ bind(no_such_interface);
|
||||
// Throw an exception.
|
||||
// For historical reasons, it will be IncompatibleClassChangeError.
|
||||
__ should_not_reach_here(); // %%% FIXME NYI
|
||||
__ pushptr(Address(rdx_intf, java_mirror_offset)); // required interface
|
||||
__ push(rcx_recv); // bad receiver
|
||||
__ push((int)Bytecodes::_invokeinterface); // who is complaining?
|
||||
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -524,6 +559,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
break;
|
||||
|
||||
case _adapter_retype_only:
|
||||
case _adapter_retype_raw:
|
||||
// immediately jump to the next MH layer:
|
||||
__ movptr(rcx_recv, rcx_mh_vmtarget);
|
||||
__ verify_oop(rcx_recv);
|
||||
|
@ -545,10 +581,6 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
__ movptr(rbx_klass, rcx_amh_argument); // this is a Class object!
|
||||
__ movptr(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes()));
|
||||
|
||||
// get the new MH:
|
||||
__ movptr(rcx_recv, rcx_mh_vmtarget);
|
||||
// (now we are done with the old MH)
|
||||
|
||||
Label done;
|
||||
__ movptr(rdx_temp, vmarg);
|
||||
__ testl(rdx_temp, rdx_temp);
|
||||
|
@ -558,17 +590,23 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
// live at this point:
|
||||
// - rbx_klass: klass required by the target method
|
||||
// - rdx_temp: argument klass to test
|
||||
// - rcx_recv: method handle to invoke (after cast succeeds)
|
||||
// - rcx_recv: adapter method handle
|
||||
__ check_klass_subtype(rdx_temp, rbx_klass, rax_argslot, done);
|
||||
|
||||
// If we get here, the type check failed!
|
||||
// Call the wrong_method_type stub, passing the failing argument type in rax.
|
||||
Register rax_mtype = rax_argslot;
|
||||
__ push(rbx_klass); // missed klass (required type)
|
||||
__ push(rdx_temp); // bad actual type (1st stacked argument)
|
||||
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
|
||||
__ movl(rax_argslot, rcx_amh_vmargslot); // reload argslot field
|
||||
__ movptr(rdx_temp, vmarg);
|
||||
|
||||
__ pushptr(rcx_amh_argument); // required class
|
||||
__ push(rdx_temp); // bad object
|
||||
__ push((int)Bytecodes::_checkcast); // who is complaining?
|
||||
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
|
||||
|
||||
__ bind(done);
|
||||
// get the new MH:
|
||||
__ movptr(rcx_recv, rcx_mh_vmtarget);
|
||||
__ jump_to_method_handle_entry(rcx_recv, rdx_temp);
|
||||
}
|
||||
break;
|
||||
|
@ -1107,11 +1145,17 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
|
||||
__ bind(bad_array_klass);
|
||||
UNPUSH_RSI_RDI;
|
||||
__ stop("bad array klass NYI");
|
||||
__ pushptr(Address(rdx_array_klass, java_mirror_offset)); // required type
|
||||
__ pushptr(vmarg); // bad array
|
||||
__ push((int)Bytecodes::_aaload); // who is complaining?
|
||||
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
|
||||
|
||||
__ bind(bad_array_length);
|
||||
UNPUSH_RSI_RDI;
|
||||
__ stop("bad array length NYI");
|
||||
__ push(rcx_recv); // AMH requiring a certain length
|
||||
__ pushptr(vmarg); // bad array
|
||||
__ push((int)Bytecodes::_arraylength); // who is complaining?
|
||||
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
|
||||
|
||||
#undef UNPUSH_RSI_RDI
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue