< prev index next >

src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp

Print this page
*** 1,7 ***
  /*
!  * 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
--- 1,7 ---
  /*
!  * 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 ***
    // 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);
--- 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, /* 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 ***
  
    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,
--- 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(), /* is_far */ true);
  
    __ bind(*stub->continuation());
  }
  
  void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,

*** 362,44 ***
    }
  }
  
  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
  
--- 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);
    }
  
!   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 >