< prev index next > src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp
Print this page
/*
! * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
/*
! * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
__ bind(done);
}
static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
const Register thread, const Register value, const Register tmp1, const Register tmp2) {
+ assert_different_registers(value, tmp1, tmp2);
// Can we store a value in the given thread's buffer?
// (The index field is typed as size_t.)
__ ld(tmp1, Address(thread, in_bytes(index_offset))); // tmp1 := *(index address)
__ beqz(tmp1, runtime); // jump to runtime if index == 0 (full buffer)
// The buffer is not full, store value into it.
// Do we need to load the previous value?
if (obj != noreg) {
__ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
}
// Is the previous value null?
! __ beqz(pre_val, done, true);
generate_queue_test_and_insertion(masm,
G1ThreadLocalData::satb_mark_queue_index_offset(),
G1ThreadLocalData::satb_mark_queue_buffer_offset(),
runtime,
thread, pre_val, tmp1, tmp2);
// Do we need to load the previous value?
if (obj != noreg) {
__ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
}
// Is the previous value null?
! __ beqz(pre_val, done, /* is_far */ true);
generate_queue_test_and_insertion(masm,
G1ThreadLocalData::satb_mark_queue_index_offset(),
G1ThreadLocalData::satb_mark_queue_buffer_offset(),
runtime,
thread, pre_val, tmp1, tmp2);
__ bind(runtime);
__ push_call_clobbered_registers();
+ // Calling the runtime using the regular call_VM_leaf mechanism generates
+ // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
+ // that checks that the *(fp+frame::interpreter_frame_last_sp) == nullptr.
+ //
+ // If we care generating the pre-barrier without a frame (e.g. in the
+ // intrinsified Reference.get() routine) then fp might be pointing to
+ // the caller frame and so this check will most likely fail at runtime.
+ //
+ // Expanding the call directly bypasses the generation of the check.
+ // So when we do not have have a full interpreter frame on the stack
+ // expand_call should be passed true.
+
if (expand_call) {
assert(pre_val != c_rarg1, "smashed arg");
__ super_call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);
} else {
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);
stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2);
generate_pre_barrier_fast_path(masm, thread, tmp1);
// If marking is active (*(mark queue active address) != 0), jump to stub (slow path)
! __ bnez(tmp1, *stub->entry(), true);
__ bind(*stub->continuation());
}
void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2);
generate_pre_barrier_fast_path(masm, thread, tmp1);
// If marking is active (*(mark queue active address) != 0), jump to stub (slow path)
! __ bnez(tmp1, *stub->entry(), /* is_far */ true);
__ bind(*stub->continuation());
}
void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
}
}
void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
// flatten object address if needed
if (dst.offset() == 0) {
if (dst.base() != tmp3) {
__ mv(tmp3, dst.base());
}
} else {
__ la(tmp3, dst);
}
! g1_write_barrier_pre(masm,
! tmp3 /* obj */,
! tmp2 /* pre_val */,
! xthread /* thread */,
! tmp1 /* tmp1 */,
! t1 /* tmp2 */,
! val != noreg /* tosca_live */,
! false /* expand_call */);
if (val == noreg) {
BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), noreg, noreg, noreg, noreg);
} else {
// G1 barrier needs uncompressed oop for region cross check.
Register new_val = val;
! if (UseCompressedOops) {
! new_val = t1;
! __ mv(new_val, val);
}
BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg);
! g1_write_barrier_post(masm,
! tmp3 /* store_adr */,
! new_val /* new_val */,
! xthread /* thread */,
! tmp1 /* tmp1 */,
! tmp2 /* tmp2 */);
}
}
#ifdef COMPILER1
}
}
void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
+
+ bool in_heap = (decorators & IN_HEAP) != 0;
+ bool as_normal = (decorators & AS_NORMAL) != 0;
+ bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
+
+ bool needs_pre_barrier = as_normal && !dest_uninitialized;
+ bool needs_post_barrier = (val != noreg && in_heap);
+
+ assert_different_registers(val, tmp1, tmp2, tmp3);
+
// flatten object address if needed
if (dst.offset() == 0) {
if (dst.base() != tmp3) {
__ mv(tmp3, dst.base());
}
} else {
__ la(tmp3, dst);
}
! if (needs_pre_barrier) {
! g1_write_barrier_pre(masm,
! tmp3 /* obj */,
! tmp2 /* pre_val */,
! xthread /* thread */,
! tmp1 /* tmp1 */,
! t1 /* tmp2 */,
! val != noreg /* tosca_live */,
+ false /* expand_call */);
+ }
if (val == noreg) {
BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), noreg, noreg, noreg, noreg);
} else {
// G1 barrier needs uncompressed oop for region cross check.
Register new_val = val;
! if (needs_post_barrier) {
! if (UseCompressedOops) {
! new_val = t1;
+ __ mv(new_val, val);
+ }
}
BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg);
! if (needs_post_barrier) {
! g1_write_barrier_post(masm,
! tmp3 /* store_adr */,
! new_val /* new_val */,
! xthread /* thread */,
! tmp1 /* tmp1 */,
+ tmp2 /* tmp2 */);
+ }
}
}
#ifdef COMPILER1
< prev index next >