void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, bool for_compiler_entry) { assert(method == rmethod, "interpreter calling convention"); Label L_no_such_method; __ cbz(rmethod, L_no_such_method); __ verify_method_ptr(method); if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { Label run_compiled_code; // JVMTI events, such as single-stepping, are implemented partly by avoiding running // compiled code in threads for which the event is enabled. Check here for // interp_only_mode if these events CAN be enabled. __ ldrb(rscratch1, Address(rthread, JavaThread::interp_only_mode_offset())); __ cbnz(rscratch1, run_compiled_code); __ ldr(rscratch1, Address(method, Method::interpreter_entry_offset())); __ br(rscratch1); __ BIND(run_compiled_code); } const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : Method::from_interpreted_offset(); __ ldr(rscratch1,Address(method, entry_offset)); __ br(rscratch1); __ bind(L_no_such_method); __ far_jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); }
void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); if (_compute_lock) { // lock_reg was destroyed by fast unlocking attempt => recompute it ce->monitor_address(_monitor_ix, _lock_reg); } ce->store_parameter(_lock_reg->as_register(), 0); // note: non-blocking leaf routine => no call info needed Runtime1::StubID exit_id; if (ce->compilation()->has_fpu_code()) { exit_id = Runtime1::monitorexit_id; } else { exit_id = Runtime1::monitorexit_nofpu_id; } __ adr(lr, _continuation); __ far_jump(RuntimeAddress(Runtime1::entry_for(exit_id))); }
VtableStub* VtableStubs::create_itable_stub(int itable_index) { // Note well: pd_code_size_limit is the absolute minimum we can get // away with. If you add code here, bump the code stub size // returned by pd_code_size_limit! const int code_length = VtableStub::pd_code_size_limit(false); VtableStub* s = new(code_length) VtableStub(false, itable_index); ResourceMark rm; CodeBuffer cb(s->entry_point(), code_length); MacroAssembler* masm = new MacroAssembler(&cb); #ifndef PRODUCT if (CountCompiledCalls) { __ lea(r10, ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); __ incrementw(Address(r10)); } #endif // Entry arguments: // rscratch2: Interface // j_rarg0: Receiver // Free registers (non-args) are r0 (interface), rmethod // get receiver (need to skip return address on top of stack) assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); // get receiver klass (also an implicit null-check) address npe_addr = __ pc(); // Most registers are in use; we'll use r0, rmethod, r10, r11 __ load_klass(r10, j_rarg0); Label throw_icce; // Get Method* and entrypoint for compiler __ lookup_interface_method(// inputs: rec. class, interface, itable index r10, rscratch2, itable_index, // outputs: method, scan temp. reg rmethod, r11, throw_icce); // method (rmethod): Method* // j_rarg0: receiver #ifdef ASSERT if (DebugVtables) { Label L2; __ cbz(rmethod, L2); __ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset())); __ cbnz(rscratch1, L2); __ stop("compiler entrypoint is null"); __ bind(L2); } #endif // ASSERT // rmethod: Method* // j_rarg0: receiver address ame_addr = __ pc(); __ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset())); __ br(rscratch1); __ bind(throw_icce); __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); __ flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d", itable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); return s; }
void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, vmIntrinsics::ID iid, Register receiver_reg, Register member_reg, bool for_compiler_entry) { assert(is_signature_polymorphic(iid), "expected invoke iid"); // temps used in this code are not used in *either* compiled or interpreted calling sequences Register temp1 = r10; Register temp2 = r11; Register temp3 = r14; // r13 is live by this point: it contains the sender SP if (for_compiler_entry) { assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : j_rarg0), "only valid assignment"); assert_different_registers(temp1, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7); assert_different_registers(temp2, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7); assert_different_registers(temp3, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7); } assert_different_registers(temp1, temp2, temp3, receiver_reg); assert_different_registers(temp1, temp2, temp3, member_reg); if (iid == vmIntrinsics::_invokeBasic) { // indirect through MH.form.vmentry.vmtarget jump_to_lambda_form(_masm, receiver_reg, rmethod, temp1, for_compiler_entry); } else { // The method is a member invoker used by direct method handles. if (VerifyMethodHandles) { // make sure the trailing argument really is a MemberName (caller responsibility) verify_klass(_masm, member_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_invoke_MemberName), "MemberName required for invokeVirtual etc."); } Address member_clazz( member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes())); Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset_in_bytes())); Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())); Register temp1_recv_klass = temp1; if (iid != vmIntrinsics::_linkToStatic) { __ verify_oop(receiver_reg); if (iid == vmIntrinsics::_linkToSpecial) { // Don't actually load the klass; just null-check the receiver. __ null_check(receiver_reg); } else { // load receiver klass itself __ null_check(receiver_reg, oopDesc::klass_offset_in_bytes()); __ load_klass(temp1_recv_klass, receiver_reg); __ verify_klass_ptr(temp1_recv_klass); } BLOCK_COMMENT("check_receiver {"); // The receiver for the MemberName must be in receiver_reg. // Check the receiver against the MemberName.clazz if (VerifyMethodHandles && iid == vmIntrinsics::_linkToSpecial) { // Did not load it above... __ load_klass(temp1_recv_klass, receiver_reg); __ verify_klass_ptr(temp1_recv_klass); } if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) { Label L_ok; Register temp2_defc = temp2; __ load_heap_oop(temp2_defc, member_clazz); load_klass_from_Class(_masm, temp2_defc); __ verify_klass_ptr(temp2_defc); __ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, L_ok); // If we get here, the type check failed! __ hlt(0); // __ STOP("receiver class disagrees with MemberName.clazz"); __ bind(L_ok); } BLOCK_COMMENT("} check_receiver"); } if (iid == vmIntrinsics::_linkToSpecial || iid == vmIntrinsics::_linkToStatic) { DEBUG_ONLY(temp1_recv_klass = noreg); // these guys didn't load the recv_klass } // Live registers at this point: // member_reg - MemberName that was the trailing argument // temp1_recv_klass - klass of stacked receiver, if needed // r13 - interpreter linkage (if interpreted) ??? FIXME // r1 ... r0 - compiler arguments (if compiled) Label L_incompatible_class_change_error; switch (iid) { case vmIntrinsics::_linkToSpecial: if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3); } __ ldr(rmethod, member_vmtarget); break; case vmIntrinsics::_linkToStatic: if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); } __ ldr(rmethod, member_vmtarget); break; case vmIntrinsics::_linkToVirtual: { // same as TemplateTable::invokevirtual, // minus the CP setup and profiling: if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeVirtual, member_reg, temp3); } // pick out the vtable index from the MemberName, and then we can discard it: Register temp2_index = temp2; __ ldr(temp2_index, member_vmindex); if (VerifyMethodHandles) { Label L_index_ok; __ cmpw(temp2_index, 0U); __ br(Assembler::GE, L_index_ok); __ hlt(0); __ BIND(L_index_ok); } // Note: The verifier invariants allow us to ignore MemberName.clazz and vmtarget // at this point. And VerifyMethodHandles has already checked clazz, if needed. // get target Method* & entry point __ lookup_virtual_method(temp1_recv_klass, temp2_index, rmethod); break; } case vmIntrinsics::_linkToInterface: { // same as TemplateTable::invokeinterface // (minus the CP setup and profiling, with different argument motion) if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeInterface, member_reg, temp3); } Register temp3_intf = temp3; __ load_heap_oop(temp3_intf, member_clazz); load_klass_from_Class(_masm, temp3_intf); __ verify_klass_ptr(temp3_intf); Register rindex = rmethod; __ ldr(rindex, member_vmindex); if (VerifyMethodHandles) { Label L; __ cmpw(rindex, 0U); __ br(Assembler::GE, L); __ hlt(0); __ bind(L); } // given intf, index, and recv klass, dispatch to the implementation method __ lookup_interface_method(temp1_recv_klass, temp3_intf, // note: next two args must be the same: rindex, rmethod, temp2, L_incompatible_class_change_error); break; } default: fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } // live at this point: rmethod, r13 (if interpreted) // After figuring out which concrete method to call, jump into it. // Note that this works in the interpreter with no data motion. // But the compiled version will require that r2_recv be shifted out. __ verify_method_ptr(rmethod); jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry); if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); } } }