8079564: Use FP register as proper frame pointer in JIT compiled code on aarch64
authorenevill
Fri, 15 May 2015 09:21:48 +0000
changeset 30552 ff209a4a81b5
parent 30531 4915246064b2
child 30553 27039e118599
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
hotspot/src/cpu/aarch64/vm/aarch64.ad
hotspot/src/cpu/aarch64/vm/c1_FrameMap_aarch64.cpp
hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp
hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp
hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp
hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp
hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
hotspot/src/cpu/aarch64/vm/register_definitions_aarch64.cpp
hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp
--- 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);