diff src/cpu/x86/vm/x86_64.ad @ 2404:b40d4fa697bf

6964776: c2 should ensure the polling page is reachable on 64 bit Summary: Materialize the pointer to the polling page in a register instead of using rip-relative addressing when the distance from the code cache is larger than disp32. Reviewed-by: never, kvn
author iveresov
date Sun, 27 Mar 2011 13:17:37 -0700
parents 7e88bdae86ec
children 9340a27154cb
line wrap: on
line diff
--- a/src/cpu/x86/vm/x86_64.ad	Sun Mar 27 00:00:14 2011 -0700
+++ b/src/cpu/x86/vm/x86_64.ad	Sun Mar 27 13:17:37 2011 -0700
@@ -574,12 +574,11 @@
 // In os_cpu .ad file
 // int MachCallRuntimeNode::ret_addr_offset()
 
-// Indicate if the safepoint node needs the polling page as an input.
-// Since amd64 does not have absolute addressing but RIP-relative
-// addressing and the polling page is within 2G, it doesn't.
+// Indicate if the safepoint node needs the polling page as an input,
+// it does if the polling page is more than disp32 away.
 bool SafePointNode::needs_polling_address_input()
 {
-  return false;
+  return Assembler::is_polling_page_far();
 }
 
 //
@@ -992,15 +991,21 @@
   framesize -= 2*wordSize;
 
   if (framesize) {
-    st->print_cr("addq\trsp, %d\t# Destroy frame", framesize);
+    st->print_cr("addq    rsp, %d\t# Destroy frame", framesize);
     st->print("\t");
   }
 
-  st->print_cr("popq\trbp");
+  st->print_cr("popq   rbp");
   if (do_polling() && C->is_method_compilation()) {
-    st->print_cr("\ttestl\trax, [rip + #offset_to_poll_page]\t"
-                  "# Safepoint: poll for GC");
     st->print("\t");
+    if (Assembler::is_polling_page_far()) {
+      st->print_cr("movq   rscratch1, #polling_page_address\n\t"
+                   "testl  rax, [rscratch1]\t"
+                   "# Safepoint: poll for GC");
+    } else {
+      st->print_cr("testl  rax, [rip + #offset_to_poll_page]\t"
+                   "# Safepoint: poll for GC");
+    }
   }
 }
 #endif
@@ -1033,45 +1038,22 @@
   emit_opcode(cbuf, 0x58 | RBP_enc);
 
   if (do_polling() && C->is_method_compilation()) {
-    // testl %rax, off(%rip) // Opcode + ModRM + Disp32 == 6 bytes
-    // XXX reg_mem doesn't support RIP-relative addressing yet
-    cbuf.set_insts_mark();
-    cbuf.relocate(cbuf.insts_mark(), relocInfo::poll_return_type, 0); // XXX
-    emit_opcode(cbuf, 0x85); // testl
-    emit_rm(cbuf, 0x0, RAX_enc, 0x5); // 00 rax 101 == 0x5
-    // cbuf.insts_mark() is beginning of instruction
-    emit_d32_reloc(cbuf, os::get_polling_page());
-//                    relocInfo::poll_return_type,
+    MacroAssembler _masm(&cbuf);
+    AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_return_type);
+    if (Assembler::is_polling_page_far()) {
+      __ lea(rscratch1, polling_page);
+      __ relocate(relocInfo::poll_return_type);
+      __ testl(rax, Address(rscratch1, 0));
+    } else {
+      __ testl(rax, polling_page);
+    }
   }
 }
 
 uint MachEpilogNode::size(PhaseRegAlloc* ra_) const
 {
-  Compile* C = ra_->C;
-  int framesize = C->frame_slots() << LogBytesPerInt;
-  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
-  // Remove word for return adr already pushed
-  // and RBP
-  framesize -= 2*wordSize;
-
-  uint size = 0;
-
-  if (do_polling() && C->is_method_compilation()) {
-    size += 6;
-  }
-
-  // count popq rbp
-  size++;
-
-  if (framesize) {
-    if (framesize < 0x80) {
-      size += 4;
-    } else if (framesize) {
-      size += 7;
-    }
-  }
-
-  return size;
+  return MachNode::size(ra_); // too many variables; just compute it
+                              // the hard way
 }
 
 int MachEpilogNode::reloc() const
@@ -3410,8 +3392,8 @@
     }
     if (EmitSync & 1) {
         // Without cast to int32_t a movptr will destroy r10 which is typically obj
-        masm.movptr (Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())) ; 
-        masm.cmpptr(rsp, (int32_t)NULL_WORD) ; 
+        masm.movptr (Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())) ;
+        masm.cmpptr(rsp, (int32_t)NULL_WORD) ;
     } else
     if (EmitSync & 2) {
         Label DONE_LABEL;
@@ -3439,10 +3421,10 @@
     } else {
         Label DONE_LABEL, IsInflated, Egress;
 
-        masm.movptr(tmpReg, Address(objReg, 0)) ; 
+        masm.movptr(tmpReg, Address(objReg, 0)) ;
         masm.testl (tmpReg, 0x02) ;         // inflated vs stack-locked|neutral|biased
-        masm.jcc   (Assembler::notZero, IsInflated) ; 
-         
+        masm.jcc   (Assembler::notZero, IsInflated) ;
+
         // it's stack-locked, biased or neutral
         // TODO: optimize markword triage order to reduce the number of
         // conditional branches in the most common cases.
@@ -3456,9 +3438,9 @@
         }
 
         // was q will it destroy high?
-        masm.orl   (tmpReg, 1) ; 
-        masm.movptr(Address(boxReg, 0), tmpReg) ;  
-        if (os::is_MP()) { masm.lock(); } 
+        masm.orl   (tmpReg, 1) ;
+        masm.movptr(Address(boxReg, 0), tmpReg) ;
+        if (os::is_MP()) { masm.lock(); }
         masm.cmpxchgptr(boxReg, Address(objReg, 0)); // Updates tmpReg
         if (_counters != NULL) {
            masm.cond_inc32(Assembler::equal,
@@ -3485,16 +3467,16 @@
         // fetched _owner.  If the CAS is successful we may
         // avoid an RTO->RTS upgrade on the $line.
         // Without cast to int32_t a movptr will destroy r10 which is typically obj
-        masm.movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())) ; 
-
-        masm.mov    (boxReg, tmpReg) ; 
-        masm.movptr (tmpReg, Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; 
-        masm.testptr(tmpReg, tmpReg) ;   
-        masm.jcc    (Assembler::notZero, DONE_LABEL) ; 
+        masm.movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())) ;
+
+        masm.mov    (boxReg, tmpReg) ;
+        masm.movptr (tmpReg, Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
+        masm.testptr(tmpReg, tmpReg) ;
+        masm.jcc    (Assembler::notZero, DONE_LABEL) ;
 
         // It's inflated and appears unlocked
-        if (os::is_MP()) { masm.lock(); } 
-        masm.cmpxchgptr(r15_thread, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; 
+        if (os::is_MP()) { masm.lock(); }
+        masm.cmpxchgptr(r15_thread, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
         // Intentional fall-through into DONE_LABEL ...
 
         masm.bind  (DONE_LABEL) ;
@@ -3513,8 +3495,8 @@
     Register tmpReg = as_Register($tmp$$reg);
     MacroAssembler masm(&cbuf);
 
-    if (EmitSync & 4) { 
-       masm.cmpptr(rsp, 0) ; 
+    if (EmitSync & 4) {
+       masm.cmpptr(rsp, 0) ;
     } else
     if (EmitSync & 8) {
        Label DONE_LABEL;
@@ -3541,25 +3523,25 @@
        if (UseBiasedLocking && !UseOptoBiasInlining) {
          masm.biased_locking_exit(objReg, tmpReg, DONE_LABEL);
        }
-        
-       masm.movptr(tmpReg, Address(objReg, 0)) ; 
-       masm.cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD) ; 
-       masm.jcc   (Assembler::zero, DONE_LABEL) ; 
-       masm.testl (tmpReg, 0x02) ; 
-       masm.jcc   (Assembler::zero, Stacked) ; 
-        
+
+       masm.movptr(tmpReg, Address(objReg, 0)) ;
+       masm.cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD) ;
+       masm.jcc   (Assembler::zero, DONE_LABEL) ;
+       masm.testl (tmpReg, 0x02) ;
+       masm.jcc   (Assembler::zero, Stacked) ;
+
        // It's inflated
-       masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; 
-       masm.xorptr(boxReg, r15_thread) ; 
-       masm.orptr (boxReg, Address (tmpReg, ObjectMonitor::recursions_offset_in_bytes()-2)) ; 
-       masm.jcc   (Assembler::notZero, DONE_LABEL) ; 
-       masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::cxq_offset_in_bytes()-2)) ; 
-       masm.orptr (boxReg, Address (tmpReg, ObjectMonitor::EntryList_offset_in_bytes()-2)) ; 
-       masm.jcc   (Assembler::notZero, CheckSucc) ; 
-       masm.movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), (int32_t)NULL_WORD) ; 
-       masm.jmp   (DONE_LABEL) ; 
-        
-       if ((EmitSync & 65536) == 0) { 
+       masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
+       masm.xorptr(boxReg, r15_thread) ;
+       masm.orptr (boxReg, Address (tmpReg, ObjectMonitor::recursions_offset_in_bytes()-2)) ;
+       masm.jcc   (Assembler::notZero, DONE_LABEL) ;
+       masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::cxq_offset_in_bytes()-2)) ;
+       masm.orptr (boxReg, Address (tmpReg, ObjectMonitor::EntryList_offset_in_bytes()-2)) ;
+       masm.jcc   (Assembler::notZero, CheckSucc) ;
+       masm.movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), (int32_t)NULL_WORD) ;
+       masm.jmp   (DONE_LABEL) ;
+
+       if ((EmitSync & 65536) == 0) {
          Label LSuccess, LGoSlowPath ;
          masm.bind  (CheckSucc) ;
          masm.cmpptr(Address (tmpReg, ObjectMonitor::succ_offset_in_bytes()-2), (int32_t)NULL_WORD) ;
@@ -3591,9 +3573,9 @@
          masm.jmp   (DONE_LABEL) ;
        }
 
-       masm.bind  (Stacked) ; 
+       masm.bind  (Stacked) ;
        masm.movptr(tmpReg, Address (boxReg, 0)) ;      // re-fetch
-       if (os::is_MP()) { masm.lock(); } 
+       if (os::is_MP()) { masm.lock(); }
        masm.cmpxchgptr(tmpReg, Address(objReg, 0)); // Uses RAX which is box
 
        if (EmitSync & 65536) {
@@ -3914,22 +3896,6 @@
 
     // done:
   %}
-
-  // Safepoint Poll.  This polls the safepoint page, and causes an
-  // exception if it is not readable. Unfortunately, it kills
-  // RFLAGS in the process.
-  enc_class enc_safepoint_poll
-  %{
-    // testl %rax, off(%rip) // Opcode + ModRM + Disp32 == 6 bytes
-    // XXX reg_mem doesn't support RIP-relative addressing yet
-    cbuf.set_insts_mark();
-    cbuf.relocate(cbuf.insts_mark(), relocInfo::poll_type, 0); // XXX
-    emit_opcode(cbuf, 0x85); // testl
-    emit_rm(cbuf, 0x0, RAX_enc, 0x5); // 00 rax 101 == 0x5
-    // cbuf.insts_mark() is beginning of instruction
-    emit_d32_reloc(cbuf, os::get_polling_page());
-//                    relocInfo::poll_type,
-  %}
 %}
 
 
@@ -4233,6 +4199,15 @@
   interface(CONST_INTER);
 %}
 
+operand immP_poll() %{
+  predicate(n->get_ptr() != 0 && n->get_ptr() == (intptr_t)os::get_polling_page());
+  match(ConP);
+
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
 // Pointer Immediate
 operand immN() %{
   match(ConN);
@@ -4840,7 +4815,7 @@
 %}
 
 // Double register operands
-operand regD() 
+operand regD()
 %{
   constraint(ALLOC_IN_RC(double_reg));
   match(RegD);
@@ -6568,6 +6543,16 @@
   ins_pipe(ialu_reg);
 %}
 
+instruct loadConP_poll(rRegP dst, immP_poll src) %{
+  match(Set dst src);
+  format %{ "movq    $dst, $src\t!ptr" %}
+  ins_encode %{
+    AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_type);
+    __ lea($dst$$Register, polling_page);
+  %}
+  ins_pipe(ialu_reg_fat);
+%}
+
 instruct loadConP31(rRegP dst, immP31 src, rFlagsReg cr)
 %{
   match(Set dst src);
@@ -7241,11 +7226,11 @@
 instruct bytes_reverse_unsigned_short(rRegI dst) %{
   match(Set dst (ReverseBytesUS dst));
 
-  format %{ "bswapl  $dst\n\t" 
+  format %{ "bswapl  $dst\n\t"
             "shrl    $dst,16\n\t" %}
   ins_encode %{
     __ bswapl($dst$$Register);
-    __ shrl($dst$$Register, 16); 
+    __ shrl($dst$$Register, 16);
   %}
   ins_pipe( ialu_reg );
 %}
@@ -7253,11 +7238,11 @@
 instruct bytes_reverse_short(rRegI dst) %{
   match(Set dst (ReverseBytesS dst));
 
-  format %{ "bswapl  $dst\n\t" 
+  format %{ "bswapl  $dst\n\t"
             "sar     $dst,16\n\t" %}
   ins_encode %{
     __ bswapl($dst$$Register);
-    __ sarl($dst$$Register, 16); 
+    __ sarl($dst$$Register, 16);
   %}
   ins_pipe( ialu_reg );
 %}
@@ -7480,7 +7465,7 @@
   effect(KILL cr);
   ins_cost(400);
 
-  format %{ 
+  format %{
     $$template
     if (os::is_MP()) {
       $$emit$$"lock addl [rsp + #0], 0\t! membar_volatile"
@@ -8291,7 +8276,7 @@
                            rFlagsReg cr)
 %{
   match(Set cr (StorePConditional heap_top_ptr (Binary oldval newval)));
- 
+
   format %{ "cmpxchgq $heap_top_ptr, $newval\t# (ptr) "
             "If rax == $heap_top_ptr then store $newval into $heap_top_ptr" %}
   opcode(0x0F, 0xB1);
@@ -9854,9 +9839,9 @@
 
 // Xor Register with Immediate -1
 instruct xorI_rReg_im1(rRegI dst, immI_M1 imm) %{
-  match(Set dst (XorI dst imm));  
-
-  format %{ "not    $dst" %}  
+  match(Set dst (XorI dst imm));
+
+  format %{ "not    $dst" %}
   ins_encode %{
      __ notl($dst$$Register);
   %}
@@ -10097,9 +10082,9 @@
 
 // Xor Register with Immediate -1
 instruct xorL_rReg_im1(rRegL dst, immL_M1 imm) %{
-  match(Set dst (XorL dst imm));  
-
-  format %{ "notq   $dst" %}  
+  match(Set dst (XorL dst imm));
+
+  format %{ "notq   $dst" %}
   ins_encode %{
      __ notq($dst$$Register);
   %}
@@ -12473,14 +12458,33 @@
 // Safepoint Instructions
 instruct safePoint_poll(rFlagsReg cr)
 %{
+  predicate(!Assembler::is_polling_page_far());
   match(SafePoint);
   effect(KILL cr);
 
-  format %{ "testl   rax, [rip + #offset_to_poll_page]\t"
+  format %{ "testl  rax, [rip + #offset_to_poll_page]\t"
             "# Safepoint: poll for GC" %}
-  size(6); // Opcode + ModRM + Disp32 == 6 bytes
   ins_cost(125);
-  ins_encode(enc_safepoint_poll);
+  ins_encode %{
+    AddressLiteral addr(os::get_polling_page(), relocInfo::poll_type);
+    __ testl(rax, addr);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
+instruct safePoint_poll_far(rFlagsReg cr, rRegP poll)
+%{
+  predicate(Assembler::is_polling_page_far());
+  match(SafePoint poll);
+  effect(KILL cr, USE poll);
+
+  format %{ "testl  rax, [$poll]\t"
+            "# Safepoint: poll for GC" %}
+  ins_cost(125);
+  ins_encode %{
+    __ relocate(relocInfo::poll_type);
+    __ testl(rax, Address($poll$$Register, 0));
+  %}
   ins_pipe(ialu_reg_mem);
 %}