< prev index next > src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
Print this page
#include "gc/shenandoah/mode/shenandoahMode.hpp"
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
#include "gc/shenandoah/shenandoahBarrierSetAssembler.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/interp_masm.hpp"
#include "interpreter/interpreter.hpp"
+ #include "nativeInst_riscv.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/sharedRuntime.hpp"
#ifdef COMPILER1
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
}
void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp) {
Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
! Address gc_state_fast(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(test_state)));
! __ lbu(tmp, gc_state_fast);
! __ beqz(tmp, *continuation());
__ j(*entry());
// This is were the slowpath stub will return to or the code above will
// jump to if the checks are false
__ 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());
}
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(), (int)ShenandoahNMethod::gc_state_to_reloc(test_state));
__ j(*entry());
// This is were the slowpath stub will return to or the code above will
// jump to if the checks are false
__ 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();
+ }
+
+ static bool is_nop(address pc) {
+ if (*(pc + 0) != 0x13) return false;
+ if (*(pc + 1) != 0x00) return false;
+ if (*(pc + 2) != 0x00) return false;
+ if (*(pc + 3) != 0x00) return false;
+ return true;
+ }
+
+ static void insert_nop(address pc) {
+ *reinterpret_cast<int32_t*>(pc) = 0x00000013;
+ assert(is_nop(pc), "Should be");
+ ICache::invalidate_range(pc, 4);
+ }
+
+ 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));
+ }
+
+ 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)) {
+ 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?");
__ bind(*entry());
void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
Address index(xthread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(xthread, 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");
! Address gc_state_fast(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::MARKING)));
! __ lbu(_tmp1, gc_state_fast);
! __ beqz(_tmp1, L_through);
}
// Fast-path: put object into buffer.
// If buffer is already full, go slow.
__ ld(_tmp1, index);
void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
Address index(xthread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(xthread, 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));
+ __ j(L_over);
+ __ j(L_through);
+ __ bind(L_over);
}
// Fast-path: put object into buffer.
// If buffer is already full, go slow.
__ ld(_tmp1, index);
}
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);
- Address gc_state_fast(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(state_to_check)));
- __ lbu(_tmp1, gc_state_fast);
- 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) {
! Address gc_state_fast(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::WEAK_ROOTS)));
! __ lbu(_tmp1, gc_state_fast);
! __ bnez(_tmp1, L_slow);
}
// Cset-check. Fall-through to slow if in collection set.
if (_narrow) {
__ decode_heap_oop_not_null(_tmp2, _obj);
}
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));
! __ j(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));
+ __ j(L_over);
+ __ j(*continuation());
+ __ bind(L_over);
}
// Cset-check. Fall-through to slow if in collection set.
if (_narrow) {
__ decode_heap_oop_not_null(_tmp2, _obj);
< prev index next >