# HG changeset patch # User enevill # Date 1430994478 0 # Thu May 07 10:27:58 2015 +0000 # Node ID 7b9c17141f28002c1b42e765a818c5e632f1359d # Parent c06fef227be6efcf958b013265e34394728d29fc 8079564: Use FP register as proper frame pointer in JIT compiled code on aarch64 Summary: Add support for PreserveFramePointer for debug/profile Reviewed-by: duke diff --git a/src/cpu/aarch64/vm/aarch64.ad b/src/cpu/aarch64/vm/aarch64.ad --- a/src/cpu/aarch64/vm/aarch64.ad +++ b/src/cpu/aarch64/vm/aarch64.ad @@ -421,7 +421,40 @@ ); // Class for all non-special integer registers -reg_class no_special_reg32( +reg_class no_special_reg32_no_fp( + R0, + R1, + R2, + R3, + R4, + R5, + R6, + R7, + R10, + R11, + R12, // rmethod + R13, + R14, + R15, + R16, + R17, + R18, + R19, + R20, + R21, + R22, + R23, + R24, + R25, + R26 + /* R27, */ // heapbase + /* R28, */ // thread + /* R29, */ // fp + /* R30, */ // lr + /* R31 */ // sp +); + +reg_class no_special_reg32_with_fp( R0, R1, R2, @@ -454,8 +487,43 @@ /* R31 */ // sp ); +reg_class_dynamic no_special_reg32(no_special_reg32_no_fp, no_special_reg32_with_fp, %{ PreserveFramePointer %}); + // Class for all non-special long integer registers -reg_class no_special_reg( +reg_class no_special_reg_no_fp( + R0, R0_H, + R1, R1_H, + R2, R2_H, + R3, R3_H, + R4, R4_H, + R5, R5_H, + R6, R6_H, + R7, R7_H, + R10, R10_H, + R11, R11_H, + R12, R12_H, // rmethod + R13, R13_H, + R14, R14_H, + R15, R15_H, + R16, R16_H, + R17, R17_H, + R18, R18_H, + R19, R19_H, + R20, R20_H, + R21, R21_H, + R22, R22_H, + R23, R23_H, + R24, R24_H, + R25, R25_H, + R26, R26_H, + /* R27, R27_H, */ // heapbase + /* R28, R28_H, */ // thread + /* R29, R29_H, */ // fp + /* R30, R30_H, */ // lr + /* R31, R31_H */ // sp +); + +reg_class no_special_reg_with_fp( R0, R0_H, R1, R1_H, R2, R2_H, @@ -488,6 +556,8 @@ /* R31, R31_H */ // sp ); +reg_class_dynamic no_special_reg(no_special_reg_no_fp, no_special_reg_with_fp, %{ PreserveFramePointer %}); + // Class for 64 bit register r0 reg_class r0_reg( R0, R0_H @@ -1640,12 +1710,7 @@ int MachCallStaticJavaNode::ret_addr_offset() { // call should be a simple bl - // unless this is a method handle invoke in which case it is - // mov(rfp, sp), bl, mov(sp, rfp) int off = 4; - if (_method_handle_invoke) { - off += 4; - } return off; } @@ -1756,14 +1821,13 @@ if (C->need_stack_bang(framesize)) st->print("# stack bang size=%d\n\t", framesize); - if (framesize == 0) { - // Is this even possible? - st->print("stp lr, rfp, [sp, #%d]!", -(2 * wordSize)); - } else if (framesize < ((1 << 9) + 2 * wordSize)) { + if (framesize < ((1 << 9) + 2 * wordSize)) { st->print("sub sp, sp, #%d\n\t", framesize); st->print("stp rfp, lr, [sp, #%d]", framesize - 2 * wordSize); + if (PreserveFramePointer) st->print("\n\tadd rfp, sp, #%d", framesize - 2 * wordSize); } else { st->print("stp lr, rfp, [sp, #%d]!\n\t", -(2 * wordSize)); + if (PreserveFramePointer) st->print("mov rfp, sp\n\t"); st->print("mov rscratch1, #%d\n\t", framesize - 2 * wordSize); st->print("sub sp, sp, rscratch1"); } @@ -3520,34 +3584,6 @@ } %} - enc_class aarch64_enc_java_handle_call(method meth) %{ - MacroAssembler _masm(&cbuf); - relocInfo::relocType reloc; - - // RFP is preserved across all calls, even compiled calls. - // Use it to preserve SP. - __ mov(rfp, sp); - - const int start_offset = __ offset(); - address addr = (address)$meth$$method; - if (!_method) { - // A call to a runtime wrapper, e.g. new, new_typeArray_Java, uncommon_trap. - __ trampoline_call(Address(addr, relocInfo::runtime_call_type), &cbuf); - } else if (_optimized_virtual) { - __ trampoline_call(Address(addr, relocInfo::opt_virtual_call_type), &cbuf); - } else { - __ trampoline_call(Address(addr, relocInfo::static_call_type), &cbuf); - } - - if (_method) { - // Emit stub for static call - CompiledStaticCall::emit_to_interp_stub(cbuf); - } - - // now restore sp - __ mov(sp, rfp); - %} - enc_class aarch64_enc_java_dynamic_call(method meth) %{ MacroAssembler _masm(&cbuf); __ ic_call((address)$meth$$method); @@ -12564,8 +12600,6 @@ effect(USE meth); - predicate(!((CallStaticJavaNode*)n)->is_method_handle_invoke()); - ins_cost(CALL_COST); format %{ "call,static $meth \t// ==> " %} @@ -12578,26 +12612,6 @@ // TO HERE -// Call Java Static Instruction (method handle version) - -instruct CallStaticJavaDirectHandle(method meth, iRegP_FP reg_mh_save) -%{ - match(CallStaticJava); - - effect(USE meth); - - predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke()); - - ins_cost(CALL_COST); - - format %{ "call,static $meth \t// (methodhandle) ==> " %} - - ins_encode( aarch64_enc_java_handle_call(meth), - aarch64_enc_call_epilog ); - - ins_pipe(pipe_class_call); -%} - // Call Java Dynamic Instruction instruct CallDynamicJavaDirect(method meth) %{ diff --git a/src/cpu/aarch64/vm/c1_FrameMap_aarch64.cpp b/src/cpu/aarch64/vm/c1_FrameMap_aarch64.cpp --- a/src/cpu/aarch64/vm/c1_FrameMap_aarch64.cpp +++ b/src/cpu/aarch64/vm/c1_FrameMap_aarch64.cpp @@ -346,8 +346,7 @@ // JSR 292 LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - // assert(rfp == rbp_mh_SP_save, "must be same register"); - return rfp_opr; + return LIR_OprFact::illegalOpr; // Not needed on aarch64 } diff --git a/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp b/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp --- a/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp +++ b/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp @@ -443,18 +443,8 @@ restore_live_registers(sasm, id != handle_exception_nofpu_id); break; case handle_exception_from_callee_id: - // Pop the return address since we are possibly changing SP (restoring from BP). + // Pop the return address. __ leave(); - - // Restore SP from FP if the exception PC is a method handle call site. - { - Label nope; - __ ldrw(rscratch1, Address(rthread, JavaThread::is_method_handle_return_offset())); - __ cbzw(rscratch1, nope); - __ mov(sp, rfp); - __ bind(nope); - } - __ ret(lr); // jump to exception handler break; default: ShouldNotReachHere(); @@ -514,14 +504,6 @@ __ verify_not_null_oop(exception_oop); - { - Label foo; - __ ldrw(rscratch1, Address(rthread, JavaThread::is_method_handle_return_offset())); - __ cbzw(rscratch1, foo); - __ mov(sp, rfp); - __ bind(foo); - } - // continue at exception handler (return address removed) // note: do *not* remove arguments when unwinding the // activation since the caller assumes having diff --git a/src/cpu/aarch64/vm/frame_aarch64.cpp b/src/cpu/aarch64/vm/frame_aarch64.cpp --- a/src/cpu/aarch64/vm/frame_aarch64.cpp +++ b/src/cpu/aarch64/vm/frame_aarch64.cpp @@ -223,7 +223,8 @@ if (sender_blob->is_nmethod()) { nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != NULL) { - if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc)) { + if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || + nm->method()->is_method_handle_intrinsic()) { return false; } } @@ -389,10 +390,9 @@ // frame::verify_deopt_original_pc // // Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. The unextended SP might also be the saved SP -// for MethodHandle call sites. +// given unextended SP. #ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) { +void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { frame fr; // This is ugly but it's better than to change {get,set}_original_pc @@ -402,33 +402,23 @@ address original_pc = nm->get_original_pc(&fr); assert(nm->insts_contains(original_pc), "original PC must be in nmethod"); - assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be"); } #endif //------------------------------------------------------------------------------ // frame::adjust_unextended_sp void frame::adjust_unextended_sp() { - // If we are returning to a compiled MethodHandle call site, the - // saved_fp will in fact be a saved value of the unextended SP. The - // simplest way to tell whether we are returning to such a call site - // is as follows: + // On aarch64, sites calling method handle intrinsics and lambda forms are treated + // as any other call site. Therefore, no special action is needed when we are + // returning to any of these call sites. nmethod* sender_nm = (_cb == NULL) ? NULL : _cb->as_nmethod_or_null(); if (sender_nm != NULL) { - // If the sender PC is a deoptimization point, get the original - // PC. For MethodHandle call site the unextended_sp is stored in - // saved_fp. - if (sender_nm->is_deopt_mh_entry(_pc)) { - DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, _fp)); - _unextended_sp = _fp; - } - else if (sender_nm->is_deopt_entry(_pc)) { + // If the sender PC is a deoptimization point, get the original PC. + if (sender_nm->is_deopt_entry(_pc) || + sender_nm->is_deopt_mh_entry(_pc)) { DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp)); } - else if (sender_nm->is_method_handle_return(_pc)) { - _unextended_sp = _fp; - } } } diff --git a/src/cpu/aarch64/vm/frame_aarch64.hpp b/src/cpu/aarch64/vm/frame_aarch64.hpp --- a/src/cpu/aarch64/vm/frame_aarch64.hpp +++ b/src/cpu/aarch64/vm/frame_aarch64.hpp @@ -167,10 +167,7 @@ #ifdef ASSERT // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); - static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) { - verify_deopt_original_pc(nm, unextended_sp, true); - } + static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp); #endif public: diff --git a/src/cpu/aarch64/vm/frame_aarch64.inline.hpp b/src/cpu/aarch64/vm/frame_aarch64.inline.hpp --- a/src/cpu/aarch64/vm/frame_aarch64.inline.hpp +++ b/src/cpu/aarch64/vm/frame_aarch64.inline.hpp @@ -47,12 +47,6 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) { intptr_t a = intptr_t(sp); intptr_t b = intptr_t(fp); -#ifndef PRODUCT - if (fp) - if (sp > fp || (fp - sp > 0x100000)) - for(;;) - asm("nop"); -#endif _sp = sp; _unextended_sp = sp; _fp = fp; diff --git a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp --- a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -3796,14 +3796,14 @@ } void MacroAssembler::build_frame(int framesize) { - if (framesize == 0) { - // Is this even possible? - stp(rfp, lr, Address(pre(sp, -2 * wordSize))); - } else if (framesize < ((1 << 9) + 2 * wordSize)) { + assert(framesize > 0, "framesize must be > 0"); + if (framesize < ((1 << 9) + 2 * wordSize)) { sub(sp, sp, framesize); stp(rfp, lr, Address(sp, framesize - 2 * wordSize)); + if (PreserveFramePointer) add(rfp, sp, framesize - 2 * wordSize); } else { stp(rfp, lr, Address(pre(sp, -2 * wordSize))); + if (PreserveFramePointer) mov(rfp, sp); if (framesize < ((1 << 12) + 2 * wordSize)) sub(sp, sp, framesize - 2 * wordSize); else { @@ -3814,9 +3814,8 @@ } void MacroAssembler::remove_frame(int framesize) { - if (framesize == 0) { - ldp(rfp, lr, Address(post(sp, 2 * wordSize))); - } else if (framesize < ((1 << 9) + 2 * wordSize)) { + assert(framesize > 0, "framesize must be > 0"); + if (framesize < ((1 << 9) + 2 * wordSize)) { ldp(rfp, lr, Address(sp, framesize - 2 * wordSize)); add(sp, sp, framesize); } else { diff --git a/src/cpu/aarch64/vm/register_definitions_aarch64.cpp b/src/cpu/aarch64/vm/register_definitions_aarch64.cpp --- a/src/cpu/aarch64/vm/register_definitions_aarch64.cpp +++ b/src/cpu/aarch64/vm/register_definitions_aarch64.cpp @@ -149,7 +149,3 @@ REGISTER_DEFINITION(Register, rheapbase); REGISTER_DEFINITION(Register, r31_sp); - -// TODO : x86 uses rbp to save SP in method handle code -// we may need to do the same with fp -// REGISTER_DEFINITION(Register, rbp_mh_SP_save) diff --git a/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp --- a/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp +++ b/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp @@ -2995,21 +2995,6 @@ // r0: exception handler - // Restore SP from BP if the exception PC is a MethodHandle call site. - __ ldrw(rscratch1, Address(rthread, JavaThread::is_method_handle_return_offset())); - // n.b. Intel uses special register rbp_mh_SP_save here but we will - // just hard wire rfp - __ cmpw(rscratch1, zr); - // the obvious way to conditionally copy rfp to sp if NE - // Label skip; - // __ br(Assembler::EQ, skip); - // __ mov(sp, rfp); - // __ bind(skip); - // same but branchless - __ mov(rscratch1, sp); - __ csel(rscratch1, rfp, rscratch1, Assembler::NE); - __ mov(sp, rscratch1); - // We have a handler in r0 (could be deopt blob). __ mov(r8, r0);