diff a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp
--- a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -136,10 +136,11 @@
   __ 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.
@@ -174,11 +175,11 @@
   // 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);
+  __ 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);
@@ -212,10 +213,22 @@
 
   __ 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);
@@ -299,11 +312,11 @@
 
   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);
+  __ bnez(tmp1, *stub->entry(), /* is_far */ true);
 
   __ bind(*stub->continuation());
 }
 
 void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
@@ -362,44 +375,60 @@
   }
 }
 
 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);
   }
 
-  g1_write_barrier_pre(masm,
-                       tmp3 /* obj */,
-                       tmp2 /* pre_val */,
-                       xthread /* thread */,
-                       tmp1 /* tmp1 */,
-                       t1 /* tmp2 */,
-                       val != noreg /* tosca_live */,
-                       false /* expand_call */);
+  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 (UseCompressedOops) {
-      new_val = t1;
-      __ mv(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);
-    g1_write_barrier_post(masm,
-                          tmp3 /* store_adr */,
-                          new_val /* new_val */,
-                          xthread /* thread */,
-                          tmp1 /* tmp1 */,
-                          tmp2 /* tmp2 */);
+    if (needs_post_barrier) {
+      g1_write_barrier_post(masm,
+                            tmp3 /* store_adr */,
+                            new_val /* new_val */,
+                            xthread /* thread */,
+                            tmp1 /* tmp1 */,
+                            tmp2 /* tmp2 */);
+    }
   }
 }
 
 #ifdef COMPILER1
 
