// Code generation address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm, vmIntrinsics::ID iid) { const bool not_for_compiler_entry = false; // this is the interpreter entry assert(is_signature_polymorphic(iid), "expected invoke iid"); if (iid == vmIntrinsics::_invokeGeneric || iid == vmIntrinsics::_compiledLambdaForm) { // Perhaps surprisingly, the symbolic references visible to Java are not directly used. // They are linked to Java-generated adapters via MethodHandleNatives.linkMethod. // They all allow an appendix argument. __ stop("Should not reach here"); // empty stubs make SG sick return NULL; } Register argbase = CC_INTERP_ONLY(R17_tos) NOT_CC_INTERP(R15_esp); // parameter (preserved) Register argslot = R3; Register temp1 = R6; Register param_size = R7; // here's where control starts out: __ align(CodeEntryAlignment); address entry_point = __ pc(); if (VerifyMethodHandles) { Label L; BLOCK_COMMENT("verify_intrinsic_id {"); __ load_sized_value(temp1, Method::intrinsic_id_offset_in_bytes(), R19_method, sizeof(u1), /*is_signed*/ false); // assert(sizeof(u1) == sizeof(Method::_intrinsic_id), ""); __ cmpwi(CCR1, temp1, (int) iid); __ beq(CCR1, L); if (iid == vmIntrinsics::_linkToVirtual || iid == vmIntrinsics::_linkToSpecial) { // could do this for all kinds, but would explode assembly code size trace_method_handle(_masm, "bad Method*:intrinsic_id"); } __ stop("bad Method*::intrinsic_id"); __ BIND(L); BLOCK_COMMENT("} verify_intrinsic_id"); } // First task: Find out how big the argument list is. int ref_kind = signature_polymorphic_intrinsic_ref_kind(iid); assert(ref_kind != 0 || iid == vmIntrinsics::_invokeBasic, "must be _invokeBasic or a linkTo intrinsic"); if (ref_kind == 0 || MethodHandles::ref_kind_has_receiver(ref_kind)) { __ ld(param_size, in_bytes(Method::const_offset()), R19_method); __ load_sized_value(param_size, in_bytes(ConstMethod::size_of_parameters_offset()), param_size, sizeof(u2), /*is_signed*/ false); // assert(sizeof(u2) == sizeof(ConstMethod::_size_of_parameters), ""); } else { DEBUG_ONLY(param_size = noreg); } Register tmp_mh = noreg; if (!is_signature_polymorphic_static(iid)) { __ ld(tmp_mh = temp1, __ argument_offset(param_size, param_size, 0), argbase); DEBUG_ONLY(param_size = noreg); } if (TraceMethodHandles) { if (tmp_mh != noreg) { __ mr(R23_method_handle, tmp_mh); // make stub happy } trace_method_handle_interpreter_entry(_masm, iid); } if (iid == vmIntrinsics::_invokeBasic) { generate_method_handle_dispatch(_masm, iid, tmp_mh, noreg, not_for_compiler_entry); } else { // Adjust argument list by popping the trailing MemberName argument. Register tmp_recv = noreg; if (MethodHandles::ref_kind_has_receiver(ref_kind)) { // Load the receiver (not the MH; the actual MemberName's receiver) up from the interpreter stack. __ ld(tmp_recv = temp1, __ argument_offset(param_size, param_size, 0), argbase); DEBUG_ONLY(param_size = noreg); } Register R19_member = R19_method; // MemberName ptr; incoming method ptr is dead now __ ld(R19_member, RegisterOrConstant((intptr_t)8), argbase); __ add(argbase, Interpreter::stackElementSize, argbase); generate_method_handle_dispatch(_masm, iid, tmp_recv, R19_member, not_for_compiler_entry); } return entry_point; }
// Code generation address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm, vmIntrinsics::ID iid) { const bool not_for_compiler_entry = false; // this is the interpreter entry assert(is_signature_polymorphic(iid), "expected invoke iid"); if (iid == vmIntrinsics::_invokeGeneric || iid == vmIntrinsics::_compiledLambdaForm) { // Perhaps surprisingly, the symbolic references visible to Java are not directly used. // They are linked to Java-generated adapters via MethodHandleNatives.linkMethod. // They all allow an appendix argument. __ hlt(0); // empty stubs make SG sick return NULL; } // r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) // rmethod: Method* // r3: argument locator (parameter slot count, added to rsp) // r1: used as temp to hold mh or receiver // r0, r11: garbage temps, blown away Register argp = r3; // argument list ptr, live on error paths Register temp = r0; Register mh = r1; // MH receiver; dies quickly and is recycled // here's where control starts out: __ align(CodeEntryAlignment); address entry_point = __ pc(); if (VerifyMethodHandles) { assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2"); Label L; BLOCK_COMMENT("verify_intrinsic_id {"); __ ldrh(rscratch1, Address(rmethod, Method::intrinsic_id_offset_in_bytes())); __ cmp(rscratch1, (int) iid); __ br(Assembler::EQ, L); if (iid == vmIntrinsics::_linkToVirtual || iid == vmIntrinsics::_linkToSpecial) { // could do this for all kinds, but would explode assembly code size trace_method_handle(_masm, "bad Method*::intrinsic_id"); } __ hlt(0); __ bind(L); BLOCK_COMMENT("} verify_intrinsic_id"); } // First task: Find out how big the argument list is. Address r3_first_arg_addr; int ref_kind = signature_polymorphic_intrinsic_ref_kind(iid); assert(ref_kind != 0 || iid == vmIntrinsics::_invokeBasic, "must be _invokeBasic or a linkTo intrinsic"); if (ref_kind == 0 || MethodHandles::ref_kind_has_receiver(ref_kind)) { __ ldr(argp, Address(rmethod, Method::const_offset())); __ load_sized_value(argp, Address(argp, ConstMethod::size_of_parameters_offset()), sizeof(u2), /*is_signed*/ false); // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), ""); r3_first_arg_addr = __ argument_address(argp, -1); } else { DEBUG_ONLY(argp = noreg); } if (!is_signature_polymorphic_static(iid)) { __ ldr(mh, r3_first_arg_addr); DEBUG_ONLY(argp = noreg); } // r3_first_arg_addr is live! trace_method_handle_interpreter_entry(_masm, iid); if (iid == vmIntrinsics::_invokeBasic) { generate_method_handle_dispatch(_masm, iid, mh, noreg, not_for_compiler_entry); } else { // Adjust argument list by popping the trailing MemberName argument. Register recv = noreg; if (MethodHandles::ref_kind_has_receiver(ref_kind)) { // Load the receiver (not the MH; the actual MemberName's receiver) up from the interpreter stack. __ ldr(recv = r2, r3_first_arg_addr); } DEBUG_ONLY(argp = noreg); Register rmember = rmethod; // MemberName ptr; incoming method ptr is dead now __ pop(rmember); // extract last argument generate_method_handle_dispatch(_masm, iid, recv, rmember, not_for_compiler_entry); } return entry_point; }