mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
Reviewed-by: never
This commit is contained in:
parent
7be7d19ba5
commit
52e3d262a1
17 changed files with 227 additions and 57 deletions
|
@ -27,6 +27,14 @@
|
|||
|
||||
#define __ _masm->
|
||||
|
||||
#ifdef PRODUCT
|
||||
#define BLOCK_COMMENT(str) /* nothing */
|
||||
#else
|
||||
#define BLOCK_COMMENT(str) __ block_comment(str)
|
||||
#endif
|
||||
|
||||
#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
|
||||
|
||||
address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm,
|
||||
address interpreted_entry) {
|
||||
// Just before the actual machine code entry point, allocate space
|
||||
|
@ -64,6 +72,7 @@ static void verify_argslot(MacroAssembler* _masm, Register argslot_reg,
|
|||
const char* error_message) {
|
||||
// Verify that argslot lies within (rsp, rbp].
|
||||
Label L_ok, L_bad;
|
||||
BLOCK_COMMENT("{ verify_argslot");
|
||||
__ cmpptr(argslot_reg, rbp);
|
||||
__ jccb(Assembler::above, L_bad);
|
||||
__ cmpptr(rsp, argslot_reg);
|
||||
|
@ -71,6 +80,7 @@ static void verify_argslot(MacroAssembler* _masm, Register argslot_reg,
|
|||
__ bind(L_bad);
|
||||
__ stop(error_message);
|
||||
__ bind(L_ok);
|
||||
BLOCK_COMMENT("} verify_argslot");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -80,16 +90,21 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
|
|||
// rbx: methodOop
|
||||
// rcx: receiver method handle (must load from sp[MethodTypeForm.vmslots])
|
||||
// rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted)
|
||||
// rdx: garbage temp, blown away
|
||||
// rdx, rdi: garbage temp, blown away
|
||||
|
||||
Register rbx_method = rbx;
|
||||
Register rcx_recv = rcx;
|
||||
Register rax_mtype = rax;
|
||||
Register rdx_temp = rdx;
|
||||
Register rdi_temp = rdi;
|
||||
|
||||
// emit WrongMethodType path first, to enable jccb back-branch from main path
|
||||
Label wrong_method_type;
|
||||
__ bind(wrong_method_type);
|
||||
Label invoke_generic_slow_path;
|
||||
assert(methodOopDesc::intrinsic_id_size_in_bytes() == sizeof(u1), "");;
|
||||
__ cmpb(Address(rbx_method, methodOopDesc::intrinsic_id_offset_in_bytes()), (int) vmIntrinsics::_invokeExact);
|
||||
__ jcc(Assembler::notEqual, invoke_generic_slow_path);
|
||||
__ push(rax_mtype); // required mtype
|
||||
__ push(rcx_recv); // bad mh (1st stacked argument)
|
||||
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
|
||||
|
@ -106,17 +121,68 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
|
|||
tem = rax_mtype; // in case there is another indirection
|
||||
}
|
||||
}
|
||||
Register rbx_temp = rbx_method; // done with incoming methodOop
|
||||
|
||||
// given the MethodType, find out where the MH argument is buried
|
||||
__ movptr(rdx_temp, Address(rax_mtype,
|
||||
__ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rbx_temp)));
|
||||
__ movl(rdx_temp, Address(rdx_temp,
|
||||
__ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, rbx_temp)));
|
||||
__ movptr(rcx_recv, __ argument_address(rdx_temp));
|
||||
__ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rdi_temp)));
|
||||
Register rdx_vmslots = rdx_temp;
|
||||
__ movl(rdx_vmslots, Address(rdx_temp,
|
||||
__ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, rdi_temp)));
|
||||
__ movptr(rcx_recv, __ argument_address(rdx_vmslots));
|
||||
|
||||
__ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
|
||||
__ jump_to_method_handle_entry(rcx_recv, rdx_temp);
|
||||
trace_method_handle(_masm, "invokeExact");
|
||||
|
||||
__ check_method_handle_type(rax_mtype, rcx_recv, rdi_temp, wrong_method_type);
|
||||
__ jump_to_method_handle_entry(rcx_recv, rdi_temp);
|
||||
|
||||
// for invokeGeneric (only), apply argument and result conversions on the fly
|
||||
__ bind(invoke_generic_slow_path);
|
||||
#ifdef ASSERT
|
||||
{ Label L;
|
||||
__ cmpb(Address(rbx_method, methodOopDesc::intrinsic_id_offset_in_bytes()), (int) vmIntrinsics::_invokeGeneric);
|
||||
__ jcc(Assembler::equal, L);
|
||||
__ stop("bad methodOop::intrinsic_id");
|
||||
__ bind(L);
|
||||
}
|
||||
#endif //ASSERT
|
||||
Register rbx_temp = rbx_method; // don't need it now
|
||||
|
||||
// make room on the stack for another pointer:
|
||||
Register rcx_argslot = rcx_recv;
|
||||
__ lea(rcx_argslot, __ argument_address(rdx_vmslots, 1));
|
||||
insert_arg_slots(_masm, 2 * stack_move_unit(), _INSERT_REF_MASK,
|
||||
rcx_argslot, rbx_temp, rdx_temp);
|
||||
|
||||
// load up an adapter from the calling type (Java weaves this)
|
||||
__ movptr(rdx_temp, Address(rax_mtype,
|
||||
__ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rdi_temp)));
|
||||
Register rdx_adapter = rdx_temp;
|
||||
// movptr(rdx_adapter, Address(rdx_temp, java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes()));
|
||||
// deal with old JDK versions:
|
||||
__ lea(rdi_temp, Address(rdx_temp,
|
||||
__ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, rdi_temp)));
|
||||
__ cmpptr(rdi_temp, rdx_temp);
|
||||
Label sorry_no_invoke_generic;
|
||||
__ jccb(Assembler::below, sorry_no_invoke_generic);
|
||||
|
||||
__ movptr(rdx_adapter, Address(rdi_temp, 0));
|
||||
__ testptr(rdx_adapter, rdx_adapter);
|
||||
__ jccb(Assembler::zero, sorry_no_invoke_generic);
|
||||
__ movptr(Address(rcx_argslot, 1 * Interpreter::stackElementSize), rdx_adapter);
|
||||
// As a trusted first argument, pass the type being called, so the adapter knows
|
||||
// the actual types of the arguments and return values.
|
||||
// (Generic invokers are shared among form-families of method-type.)
|
||||
__ movptr(Address(rcx_argslot, 0 * Interpreter::stackElementSize), rax_mtype);
|
||||
// FIXME: assert that rdx_adapter is of the right method-type.
|
||||
__ mov(rcx, rdx_adapter);
|
||||
trace_method_handle(_masm, "invokeGeneric");
|
||||
__ jump_to_method_handle_entry(rcx, rdi_temp);
|
||||
|
||||
__ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available!
|
||||
__ movptr(rcx_recv, Address(rcx_argslot, -1 * Interpreter::stackElementSize)); // recover original MH
|
||||
__ push(rax_mtype); // required mtype
|
||||
__ push(rcx_recv); // bad mh (1st stacked argument)
|
||||
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
|
||||
|
||||
return entry_point;
|
||||
}
|
||||
|
@ -164,11 +230,12 @@ void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
|
|||
// for (rdx = rsp + size; rdx < argslot; rdx++)
|
||||
// rdx[-size] = rdx[0]
|
||||
// argslot -= size;
|
||||
BLOCK_COMMENT("insert_arg_slots {");
|
||||
__ mov(rdx_temp, rsp); // source pointer for copy
|
||||
__ lea(rsp, Address(rsp, arg_slots, Address::times_ptr));
|
||||
{
|
||||
Label loop;
|
||||
__ bind(loop);
|
||||
__ BIND(loop);
|
||||
// pull one word down each time through the loop
|
||||
__ movptr(rbx_temp, Address(rdx_temp, 0));
|
||||
__ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp);
|
||||
|
@ -179,6 +246,7 @@ void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
|
|||
|
||||
// Now move the argslot down, to point to the opened-up space.
|
||||
__ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr));
|
||||
BLOCK_COMMENT("} insert_arg_slots");
|
||||
}
|
||||
|
||||
// Helper to remove argument slots from the stack.
|
||||
|
@ -218,6 +286,7 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
|
|||
}
|
||||
#endif
|
||||
|
||||
BLOCK_COMMENT("remove_arg_slots {");
|
||||
// Pull up everything shallower than rax_argslot.
|
||||
// Then remove the excess space on the stack.
|
||||
// The stacked return address gets pulled up with everything else.
|
||||
|
@ -229,7 +298,7 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
|
|||
__ lea(rdx_temp, Address(rax_argslot, -wordSize)); // source pointer for copy
|
||||
{
|
||||
Label loop;
|
||||
__ bind(loop);
|
||||
__ BIND(loop);
|
||||
// pull one word up each time through the loop
|
||||
__ movptr(rbx_temp, Address(rdx_temp, 0));
|
||||
__ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp);
|
||||
|
@ -242,12 +311,14 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
|
|||
__ lea(rsp, Address(rsp, arg_slots, Address::times_ptr));
|
||||
// And adjust the argslot address to point at the deletion point.
|
||||
__ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr));
|
||||
BLOCK_COMMENT("} remove_arg_slots");
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
extern "C" void print_method_handle(oop mh);
|
||||
void trace_method_handle_stub(const char* adaptername,
|
||||
oop mh,
|
||||
intptr_t* saved_regs,
|
||||
intptr_t* entry_sp,
|
||||
intptr_t* saved_sp,
|
||||
intptr_t* saved_bp) {
|
||||
|
@ -256,9 +327,47 @@ void trace_method_handle_stub(const char* adaptername,
|
|||
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)
|
||||
if (last_sp != saved_sp && last_sp != NULL)
|
||||
printf("*** last_sp="INTPTR_FORMAT"\n", (intptr_t)last_sp);
|
||||
if (Verbose) print_method_handle(mh);
|
||||
if (Verbose) {
|
||||
printf(" reg dump: ");
|
||||
int saved_regs_count = (entry_sp-1) - saved_regs;
|
||||
// 32 bit: rdi rsi rbp rsp; rbx rdx rcx (*) rax
|
||||
int i;
|
||||
for (i = 0; i <= saved_regs_count; i++) {
|
||||
if (i > 0 && i % 4 == 0 && i != saved_regs_count)
|
||||
printf("\n + dump: ");
|
||||
printf(" %d: "INTPTR_FORMAT, i, saved_regs[i]);
|
||||
}
|
||||
printf("\n");
|
||||
int stack_dump_count = 16;
|
||||
if (stack_dump_count < (int)(saved_bp + 2 - saved_sp))
|
||||
stack_dump_count = (int)(saved_bp + 2 - saved_sp);
|
||||
if (stack_dump_count > 64) stack_dump_count = 48;
|
||||
for (i = 0; i < stack_dump_count; i += 4) {
|
||||
printf(" dump at SP[%d] "INTPTR_FORMAT": "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT"\n",
|
||||
i, &entry_sp[i+0], entry_sp[i+0], entry_sp[i+1], entry_sp[i+2], entry_sp[i+3]);
|
||||
}
|
||||
print_method_handle(mh);
|
||||
}
|
||||
}
|
||||
void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
|
||||
if (!TraceMethodHandles) return;
|
||||
BLOCK_COMMENT("trace_method_handle {");
|
||||
__ push(rax);
|
||||
__ lea(rax, Address(rsp, wordSize*6)); // entry_sp
|
||||
__ pusha();
|
||||
// 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) adaptername);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 5);
|
||||
__ popa();
|
||||
__ pop(rax);
|
||||
BLOCK_COMMENT("} trace_method_handle");
|
||||
}
|
||||
#endif //PRODUCT
|
||||
|
||||
|
@ -324,21 +433,9 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
|||
address interp_entry = __ pc();
|
||||
if (UseCompressedOops) __ unimplemented("UseCompressedOops");
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceMethodHandles) {
|
||||
__ 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), 5);
|
||||
__ pop(rdi); __ pop(rsi); __ pop(rdx); __ pop(rcx); __ pop(rbx); __ pop(rax);
|
||||
}
|
||||
#endif //PRODUCT
|
||||
trace_method_handle(_masm, entry_name(ek));
|
||||
|
||||
BLOCK_COMMENT(entry_name(ek));
|
||||
|
||||
switch ((int) ek) {
|
||||
case _raise_exception:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue