< prev index next > src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
Print this page
#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 "macroAssembler_ppc.hpp"
+ #include "nativeInst_ppc.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "utilities/globalDefinitions.hpp"
#include "vm_version_ppc.hpp"
#ifdef COMPILER1
#include "c1/c1_MacroAssembler.hpp"
#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
#endif
#ifdef COMPILER2
#include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
+ #include "opto/output.hpp"
#endif
#define __ masm->
void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler *masm,
__ bind(L_skip_loop);
}
#undef __
+ address ShenandoahBarrierSetAssembler::parse_jump_address(address pc) {
+ NativeInstruction* ni = nativeInstruction_at(pc);
+ assert(ni->is_jump(), "Must be");
+ NativeGeneralJump* jmp = nativeGeneralJump_at(pc);
+ return jmp->jump_destination();
+ }
+
+ static uint32_t encode_patchable_nop() {
+ return 0x60000000;
+ }
+
+ void ShenandoahBarrierSetAssembler::insert_patchable_nop(address pc) {
+ *((uint32_t*)pc) = encode_patchable_nop();
+ }
+
+ void ShenandoahBarrierSetAssembler::insert_patchable_jump(address pc, address target_pc) {
+ CodeBuffer cb(pc, BytesPerInstWord + 1);
+ MacroAssembler a(&cb);
+ a.b(target_pc);
+ }
+
+ bool ShenandoahBarrierSetAssembler::is_patchable_nop(address pc) {
+ return *((uint32_t*)pc) == encode_patchable_nop();
+ }
+
+ bool ShenandoahBarrierSetAssembler::is_patchable_jump(address pc, address target_pc) {
+ NativeInstruction* ni = nativeInstruction_at(pc);
+ return ni->is_jump() && nativeGeneralJump_at(pc)->jump_destination() == target_pc;
+ }
+
#ifdef COMPILER1
#define __ ce->masm()->
void ShenandoahBarrierSetAssembler::keepalive_barrier_c1_stub(LIR_Assembler* ce, ShenandoahKeepaliveBarrierStub* stub) {
__ srdi(tmp2, tmp2, CardTable::card_shift());
__ li(R0, CardTable::dirty_card_val());
__ stbx(R0, tmp2, tmp1);
}
! 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);
__ srdi(tmp2, tmp2, CardTable::card_shift());
__ li(R0, CardTable::dirty_card_val());
__ stbx(R0, tmp2, tmp1);
}
! void ShenandoahBarrierStubC2::patchable_jump(MacroAssembler& masm, const char gc_state, bool jump_when_state, Label* L_target) {
! PhaseOutput* const output = Compile::current()->output();
+ if (output->in_scratch_emit_size()) {
+ // Avoid binding L_target in scratch emits.
+ // We know the patched check is exactly one instruction long.
+ __ nop();
+ return;
+ }
+
+ // Emit the unconditional branch in the first version of the method.
+ // Let the rest of runtime figure out how to manage it.
+ __ relocate(patchable_barrier_Relocation::spec(ShenandoahNMethod::encode_to_reloc(gc_state, jump_when_state)));
+ __ b(*L_target);
+ }
! void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state) {
! Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
! patchable_jump_if_gc_state(masm, test_state, entry());
__ bind(*continuation());
}
void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
// 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);
// 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 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");
! char state_to_check = ShenandoahHeap::MARKING;
! patchable_jump_if_not_gc_state(masm, state_to_check, &L_through);
}
// Fast-path: put object into buffer.
// If buffer is already full, go slow.
__ ld(_tmp1, index_offset, R16_thread);
}
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) {
}
void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
Label L_slow;
! // If another barrier is enabled as well, do a 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);
! patchable_jump_if_not_gc_state(masm, state_to_check, 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) {
! char state_to_check = ShenandoahHeap::WEAK_ROOTS;
! patchable_jump_if_gc_state(masm, state_to_check, &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) {
< prev index next >