< prev index next >

src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp

Print this page
@@ -32,10 +32,11 @@
  #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  #include "gc/shenandoah/shenandoahHeapRegion.hpp"
  #include "gc/shenandoah/shenandoahRuntime.hpp"
  #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
  #include "interpreter/interpreter.hpp"
+ #include "nativeInst_x86.hpp"
  #include "runtime/javaThread.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "utilities/macros.hpp"
  #ifdef COMPILER1
  #include "c1/c1_LIRAssembler.hpp"

@@ -1019,16 +1020,80 @@
  }
  
  void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp) {
    Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
  
+   // Emit the unconditional branch in the first version of the method.
+   // Let the rest of runtime figure out how to manage it.
+   __ relocate(barrier_Relocation::spec(), ShenandoahThreadLocalData::gc_state_to_fast_array_index(test_state));
+   __ jmp(*entry(), /* maybe_short = */ false);
+ 
+ #ifdef ASSERT
    Address gc_state_fast(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(test_state)));
    __ cmpb(gc_state_fast, 0);
-   __ jcc(Assembler::notEqual, *entry());
+   __ jccb(Assembler::zero, *continuation());
+   __ hlt(); // Correctness bug: barrier is NOP-ed, but heap is NOT IDLE
+ #endif
+   // TODO: When barriers are consistently turned off at the end of the cycle, assert that barrier is NOP-ed.
+ 
    __ 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");
+   NativeJump* jmp = nativeJump_at(pc);
+   return jmp->jump_destination();
+ }
+ 
+ void insert_5_byte_nop(address pc) {
+   *(pc + 0) = 0x0F;
+   *(pc + 1) = 0x1F;
+   *(pc + 2) = 0x44;
+   *(pc + 3) = 0x00;
+   *(pc + 4) = 0x00;
+   ICache::invalidate_range(pc, 5);
+ }
+ 
+ bool is_5_byte_nop(address pc) {
+   if (*(pc + 0) != 0x0F) return false;
+   if (*(pc + 1) != 0x1F) return false;
+   if (*(pc + 2) != 0x44) return false;
+   if (*(pc + 3) != 0x00) return false;
+   if (*(pc + 4) != 0x00) return false;
+   return true;
+ }
+ 
+ void check_at(bool cond, address pc, const char* msg) {
+   assert(cond, "%s: at PC " PTR_FORMAT ": %02x%02x%02x%02x%02x",
+          msg, p2i(pc), *(pc + 0), *(pc + 1), *(pc + 2), *(pc + 3), *(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_5_byte_nop(pc);
+   } else {
+     check_at(is_5_byte_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_5_byte_nop(pc)) {
+     NativeJump::insert(pc, stub_addr);
+   } else {
+     check_at(ni->is_jump(), pc, "Should already be jump");
+     check_at(nativeJump_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?");
  
    // On x86, there is a significant penalty with unaligned branch target, for example

@@ -1045,11 +1110,11 @@
        __ movq(_obj, _addr);
      }
    }
  
    // If the object is null, there is no point in applying barriers.
-   maybe_far_jump_if_zero(masm, _obj);
+   maybe_far_jump_if_zero(masm, _obj, continuation());
  
    // We need to make sure that loads done by callers survive across slow-path calls.
    // For self-loads, we need to care about the case when both KA and LRB are enabled (rare).
    bool needs_both_barriers = _needs_keep_alive_barrier && _needs_load_ref_barrier;
    if (!_do_load || needs_both_barriers) {

@@ -1075,14 +1140,16 @@
    Address index(r15_thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
    Address buffer(r15_thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
  
    Label L_through, L_pop_and_slow;
  
-   // 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");
-     __ cmpb(gc_state_fast, 0);
+   // Hotpatched GC checks are racy: we can turn off GC state before we patch the barriers.
+   // Therefore, alas we need a separate check here. TODO: Figure this out.
+   __ cmpb(gc_state_fast, 0);
+   if (L_done != nullptr) {
+     __ jcc(Assembler::equal, *L_done);
+   } else {
      __ jcc(Assembler::equal, L_through);
    }
  
    // Need temp to work, allocate one now.
    bool tmp_live;

@@ -1148,17 +1215,16 @@
  }
  
  void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
    Label L_pop_and_slow, 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);
-     Address gc_state_fast(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(state_to_check)));
-     __ cmpb(gc_state_fast, 0);
-     __ jcc(Assembler::equal, *continuation());
-   }
+   // Hotpatched GC checks are racy: we can turn off GC state before we patch the barriers.
+   // Therefore, alas we need a separate check here. TODO: Figure this out.
+   char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
+   Address gc_state_fast(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(state_to_check)));
+   __ cmpb(gc_state_fast, 0);
+   __ jcc(Assembler::equal, *continuation());
  
    // If weak references are being processed, weak/phantom loads need to go slow,
    // regardless of their cset status.
    if (_needs_load_ref_weak_barrier) {
      Address gc_state_fast(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::WEAK_ROOTS)));

@@ -1288,15 +1354,15 @@
  
  void ShenandoahBarrierStubC2::post_init() {
    // Do nothing.
  }
  
- void ShenandoahBarrierStubC2::maybe_far_jump_if_zero(MacroAssembler& masm, Register reg) {
+ void ShenandoahBarrierStubC2::maybe_far_jump_if_zero(MacroAssembler& masm, Register reg, Label* L_target) {
    if (_narrow) {
      __ testl(reg, reg);
    } else {
      __ testq(reg, reg);
    }
-   __ jcc(Assembler::zero, *continuation());
+   __ jcc(Assembler::zero, *L_target);
  }
  
  #endif // COMPILER2
< prev index next >