8079564: Use FP register as proper frame pointer in JIT compiled code on aarch64
Summary: Add support for PreserveFramePointer for debug/profile
Reviewed-by: kvn
--- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Wed Jul 05 20:33:55 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Fri May 15 09:21:48 2015 +0000
@@ -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
@@ -1637,12 +1707,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;
}
@@ -1753,14 +1818,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");
}
@@ -3517,34 +3581,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);
@@ -12561,8 +12597,6 @@
effect(USE meth);
- predicate(!((CallStaticJavaNode*)n)->is_method_handle_invoke());
-
ins_cost(CALL_COST);
format %{ "call,static $meth \t// ==> " %}
@@ -12575,26 +12609,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)
%{
--- a/hotspot/src/cpu/aarch64/vm/c1_FrameMap_aarch64.cpp Wed Jul 05 20:33:55 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/c1_FrameMap_aarch64.cpp Fri May 15 09:21:48 2015 +0000
@@ -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
}
--- a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp Wed Jul 05 20:33:55 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp Fri May 15 09:21:48 2015 +0000
@@ -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
--- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp Wed Jul 05 20:33:55 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp Fri May 15 09:21:48 2015 +0000
@@ -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;
- }
}
}
--- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp Wed Jul 05 20:33:55 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp Fri May 15 09:21:48 2015 +0000
@@ -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:
--- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp Wed Jul 05 20:33:55 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp Fri May 15 09:21:48 2015 +0000
@@ -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;
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Wed Jul 05 20:33:55 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Fri May 15 09:21:48 2015 +0000
@@ -3788,14 +3788,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 {
@@ -3806,9 +3806,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 {
--- a/hotspot/src/cpu/aarch64/vm/register_definitions_aarch64.cpp Wed Jul 05 20:33:55 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/register_definitions_aarch64.cpp Fri May 15 09:21:48 2015 +0000
@@ -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)
--- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Wed Jul 05 20:33:55 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Fri May 15 09:21:48 2015 +0000
@@ -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);