< 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"
} else {
__ sb(zr, Address(tmp2));
}
}
- void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp) {
- Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
+ void ShenandoahBarrierStubC2::patchable_jump(MacroAssembler& masm, const char test_state, bool active, Label* L_target, bool needs_far_jump) {
+ PhaseOutput* const output = Compile::current()->output();
+ if (output->in_scratch_emit_size()) {
+ // We piggyback on scratch_emit_size mode to compute the slowpath stub size.
+ // Avoid binding entry() or trusting needs_far_jump at this time.
+ // We know the patched check is at worst two instructions long.
+ __ nop();
+ __ nop();
+ return;
+ }
- 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());
+ // Emit the unconditional branch in the first version of the method.
+ // Let the rest of runtime figure out how to manage it. If the jump target
+ // is far away, we need to flip it to make sure patchable jumps are encodeable.
+ if (needs_far_jump) {
+ Label L_over;
+ __ relocate(patchable_barrier_Relocation::spec(ShenandoahNMethod::encode_to_reloc(test_state, !active)));
+ __ j(L_over);
+ __ j(*L_target);
+ __ bind(L_over);
+ } else {
+ __ relocate(patchable_barrier_Relocation::spec(ShenandoahNMethod::encode_to_reloc(test_state, active)));
+ __ j(*L_target);
+ }
+ }
- // This is were the slowpath stub will return to or the code above will
- // jump to if the checks are false
+ 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());
}
+ address ShenandoahBarrierSetAssembler::parse_jump_address(address pc) {
+ NativeInstruction* ni = nativeInstruction_at(pc);
+ assert(ni->is_jump(), "Must be a jump");
+ NativeJump* jmp = nativeJump_at(pc);
+ return jmp->jump_destination();
+ }
+
+ static uint32_t encode_patchable_nop() {
+ return 0x00000013;
+ }
+
+ static uint32_t encode_patchable_jump(address pc, address target_pc) {
+ int32_t disp = checked_cast<int32_t>((intptr_t)target_pc - (intptr_t)pc);
+ return Assembler::encode_jal(x0, disp);
+ }
+
+ void ShenandoahBarrierSetAssembler::insert_patchable_nop(address pc) {
+ *((uint32_t*)pc) = encode_patchable_nop();
+ }
+
+ void ShenandoahBarrierSetAssembler::insert_patchable_jump(address pc, address target_pc) {
+ *((uint32_t*)pc) = encode_patchable_jump(pc, 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) {
+ return *((uint32_t*)pc) == encode_patchable_jump(pc, target_pc);
+ }
+
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());
ShouldNotReachHere();
}
}
void ShenandoahBarrierStubC2::maybe_far_jump_if_zero(MacroAssembler& masm, Register reg) {
- Label L_short_jump;
- __ bnez(reg, L_short_jump);
- __ j(*continuation());
- __ bind(L_short_jump);
+ if (_needs_far_jump) {
+ Label L_short_jump;
+ __ bnez(reg, L_short_jump);
+ __ j(*continuation());
+ __ bind(L_short_jump);
+ } else {
+ __ beqz(reg, *continuation());
+ }
}
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 another barrier is enabled as well, do a 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);
+ assert(L_done == nullptr, "Should be");
+ char state_to_check = ShenandoahHeap::MARKING;
+ patchable_short_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);
}
void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
Label L_slow;
- // If another barrier is enabled as well, do a runtime check for a specific barrier.
+ // 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);
- 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);
+ 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) {
- 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);
+ char state_to_check = ShenandoahHeap::WEAK_ROOTS;
+ patchable_short_jump_if_gc_state(masm, state_to_check, &L_slow);
}
// Cset-check. Fall-through to slow if in collection set.
if (_narrow) {
__ decode_heap_oop_not_null(_tmp2, _obj);
bool ShenandoahBarrierStubC2::is_special_register(Register r) {
Unimplemented(); // Not used
return true;
}
- void ShenandoahBarrierStubC2::post_init() {
- // Do nothing.
+ int ShenandoahBarrierStubC2::max_branch_reach() {
+ // Maximum backward range is 1M. Maximum forward reach is 1M - 4bytes.
+ // Subtract 2K to be ultra conservative.
+ return (int)(1*M - 2*K);
}
#endif // COMPILER2
< prev index next >