< prev index next >

src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp

Print this page
*** 32,13 ***
--- 32,15 ---
  #include "gc/shenandoah/shenandoahBarrierSet.hpp"
  #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
  #include "gc/shenandoah/shenandoahHeap.hpp"
  #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  #include "gc/shenandoah/shenandoahHeapRegion.hpp"
+ #include "gc/shenandoah/shenandoahNMethod.inline.hpp"
  #include "gc/shenandoah/shenandoahRuntime.hpp"
  #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
  #include "interpreter/interpreter.hpp"
+ #include "nativeInst_ppc.hpp"
  #include "macroAssembler_ppc.hpp"
  #include "runtime/javaThread.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "utilities/globalDefinitions.hpp"
  #include "vm_version_ppc.hpp"

*** 1050,18 ***
  }
  
  void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp) {
    Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
  
!   __ lbz(tmp, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(test_state)), R16_thread);
!   __ cmpdi(CR0, tmp, 0);
!   // Branch to entry if not equal
-   __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CR0, Assembler::equal), *entry());
    // This is were the slowpath stub will return to
    __ bind(*continuation());
  }
  
  void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
    Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
    assert(_needs_keep_alive_barrier || _needs_load_ref_barrier, "Why are you here?");
  
    __ bind(*entry());
--- 1052,67 ---
  }
  
  void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp) {
    Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
  
!   __ relocate(barrier_Relocation::spec(), ShenandoahNMethod::gc_state_to_reloc(test_state));
!   __ b(*entry());
! 
    // This is were the slowpath stub will return to
    __ bind(*continuation());
  }
  
+ address ShenandoahBarrierSetAssembler::parse_stub_address(address pc) {
+   NativeInstruction* ni = nativeInstruction_at(pc);
+   assert(ni->is_jump(), "Initial code version: GC barrier fastpath must be a jump");
+   NativeGeneralJump* jmp = nativeGeneralJump_at(pc);
+   return jmp->jump_destination();
+ }
+ 
+ static void check_at(bool cond, address pc, const char* msg) {
+   assert(cond, "%s: at PC " PTR_FORMAT ": %02x%02x%02x%02x",
+          msg, p2i(pc), *(pc + 0), *(pc + 1), *(pc + 2), *(pc + 3));
+ }
+ 
+ static bool is_nop(address pc) {
+   if (*(pc + 0) != 0x00) return false;
+   if (*(pc + 1) != 0x00) return false;
+   if (*(pc + 2) != 0x00) return false;
+   if (*(pc + 3) != 0x60) return false;
+   return true;
+ }
+ 
+ static void insert_nop(address pc) {
+   *reinterpret_cast<int32_t*>(pc) = 0x60000000;
+   check_at(is_nop(pc), pc, "Should be nop");
+   ICache::invalidate_range(pc, 4);
+ }
+ 
+ bool ShenandoahBarrierSetAssembler::is_active(address pc) {
+   NativeInstruction* ni = nativeInstruction_at(pc);
+   return ni->is_jump();
+ }
+ 
+ void ShenandoahBarrierSetAssembler::patch_branch_to_nop(address pc) {
+   NativeInstruction* ni = nativeInstruction_at(pc);
+   if (ni->is_jump()) {
+     insert_nop(pc);
+   } else {
+     check_at(is_nop(pc), pc, "Should already be nop");
+   }
+ }
+ 
+ void ShenandoahBarrierSetAssembler::patch_nop_to_branch(address pc, address stub_addr) {
+   NativeInstruction* ni = nativeInstruction_at(pc);
+   if (is_nop(pc)) {
+     NativeGeneralJump::insert_unconditional(pc, stub_addr);
+   } else {
+     check_at(ni->is_jump(), pc, "Should already be jump");
+     check_at(nativeGeneralJump_at(pc)->jump_destination() == stub_addr, pc, "Jump should be to the same address");
+   }
+ }
+ 
  void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
    Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
    assert(_needs_keep_alive_barrier || _needs_load_ref_barrier, "Why are you here?");
  
    __ bind(*entry());

*** 1099,26 ***
    }
  }
  
  void ShenandoahBarrierStubC2::maybe_far_jump_if_zero(MacroAssembler& masm, Register reg) {
    __ cmpdi(CR0, reg, 0);
!   // Branch to continuation if equal
    __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *continuation());
  }
  
  void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
-   const int gcstate_offset = in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::MARKING));
    const int index_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset());
    const int buffer_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset());
    Label L_through, L_slowpath;
  
!   // If another barrier is enabled as well, do a runtime check for a specific barrier.
    if (_needs_load_ref_barrier) {
!     assert(L_done == nullptr, "L_done is always null when _needs_load_ref_barrier is true");
!     __ lbz(_tmp1, gcstate_offset, R16_thread);
!     __ cmpdi(CR0, _tmp1, 0);
!     __ beq(CR0, L_through);
    }
  
    // Fast-path: put object into buffer.
    // If buffer is already full, go slow.
    __ ld(_tmp1, index_offset, R16_thread);
--- 1150,31 ---
    }
  }
  
  void ShenandoahBarrierStubC2::maybe_far_jump_if_zero(MacroAssembler& masm, Register reg) {
    __ cmpdi(CR0, reg, 0);
!   // Branch to target if equal
    __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *continuation());
  }
  
  void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
    const int index_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset());
    const int buffer_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset());
    Label L_through, L_slowpath;
  
!   // If another barrier is enabled as well, do a check for a specific barrier.
    if (_needs_load_ref_barrier) {
!     assert(L_done == nullptr, "Should be");
!     // Emit the unconditional branch in the first version of the method.
!     // Let the rest of runtime figure out how to manage it.
!     // TODO: We could have spared the over-jump if patching knew we need the inverse branch.
+     char state_to_check = ShenandoahHeap::MARKING;
+     Label L_over;
+     __ relocate(barrier_Relocation::spec(), ShenandoahNMethod::gc_state_to_reloc(state_to_check));
+     __ b(L_over);
+     __ b(L_through);
+     __ bind(L_over);
    }
  
    // Fast-path: put object into buffer.
    // If buffer is already full, go slow.
    __ ld(_tmp1, index_offset, R16_thread);

*** 1163,23 ***
  }
  
  void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
    Label L_slow;
  
-   // If another barrier is enabled as well, do a runtime check for a specific barrier.
-   if (_needs_keep_alive_barrier) {
-     char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
-     __ lbz(_tmp1, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(state_to_check)), R16_thread);
-     maybe_far_jump_if_zero(masm, _tmp1);
-   }
- 
    // If weak references are being processed, weak/phantom loads need to go slow,
    // regardless of their cset status.
    if (_needs_load_ref_weak_barrier) {
!     __ lbz(_tmp1, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::WEAK_ROOTS)), R16_thread);
!     __ cmpdi(CR0, _tmp1, 0);
!     __ bne(CR0, L_slow);
    }
  
    // Cset-check. Fall-through to slow if in collection set.
    __ load_const_optimized(_tmp1, ShenandoahHeap::in_cset_fast_test_addr(), _tmp2);
    if (_narrow) {
--- 1219,28 ---
  }
  
  void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
    Label L_slow;
  
    // If weak references are being processed, weak/phantom loads need to go slow,
    // regardless of their cset status.
    if (_needs_load_ref_weak_barrier) {
!     char state_to_check = ShenandoahHeap::WEAK_ROOTS;
!     __ relocate(barrier_Relocation::spec(), ShenandoahNMethod::gc_state_to_reloc(state_to_check));
!     __ b(L_slow);
+   }
+ 
+   if (_needs_keep_alive_barrier) {
+     // Emit the unconditional branch in the first version of the method.
+     // Let the rest of runtime figure out how to manage it.
+     // TODO: We could have spared the over-jump if patching knew we need the inverse branch.
+     char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
+     Label L_over;
+     __ relocate(barrier_Relocation::spec(), ShenandoahNMethod::gc_state_to_reloc(state_to_check));
+     __ b(L_over);
+     __ b(*continuation());
+     __ bind(L_over);
    }
  
    // Cset-check. Fall-through to slow if in collection set.
    __ load_const_optimized(_tmp1, ShenandoahHeap::in_cset_fast_test_addr(), _tmp2);
    if (_narrow) {
< prev index next >