1 /* 2 * Copyright (c) 2018, 2024, Red Hat, Inc. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "c1/c1_IR.hpp" 27 #include "gc/shared/satbMarkQueue.hpp" 28 #include "gc/shenandoah/shenandoahBarrierSet.hpp" 29 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" 30 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 31 #include "gc/shenandoah/shenandoahHeapRegion.hpp" 32 #include "gc/shenandoah/shenandoahRuntime.hpp" 33 #include "gc/shenandoah/shenandoahThreadLocalData.hpp" 34 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" 35 36 #ifdef ASSERT 37 #define __ gen->lir(__FILE__, __LINE__)-> 38 #else 39 #define __ gen->lir()-> 40 #endif 41 42 void ShenandoahPreBarrierStub::emit_code(LIR_Assembler* ce) { 43 ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); 44 bs->gen_pre_barrier_stub(ce, this); 45 } 46 47 void ShenandoahLoadReferenceBarrierStub::emit_code(LIR_Assembler* ce) { 48 ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); 49 bs->gen_load_reference_barrier_stub(ce, this); 50 } 51 52 ShenandoahBarrierSetC1::ShenandoahBarrierSetC1() : 53 _pre_barrier_c1_runtime_code_blob(nullptr), 54 _load_reference_barrier_strong_rt_code_blob(nullptr), 55 _load_reference_barrier_strong_native_rt_code_blob(nullptr), 56 _load_reference_barrier_weak_rt_code_blob(nullptr), 57 _load_reference_barrier_phantom_rt_code_blob(nullptr) {} 58 59 void ShenandoahBarrierSetC1::pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val) { 60 // First we test whether marking is in progress. 61 62 bool patch = (decorators & C1_NEEDS_PATCHING) != 0; 63 bool do_load = pre_val == LIR_OprFact::illegalOpr; 64 65 LIR_Opr thrd = gen->getThreadPointer(); 66 LIR_Address* gc_state_addr = 67 new LIR_Address(thrd, 68 in_bytes(ShenandoahThreadLocalData::gc_state_offset()), 69 T_BYTE); 70 // Read the gc_state flag. 71 LIR_Opr flag_val = gen->new_register(T_INT); 72 __ load(gc_state_addr, flag_val); 73 74 // Create a mask to test if the marking bit is set. 75 // TODO: can we directly test if bit is set? 76 LIR_Opr mask = LIR_OprFact::intConst(ShenandoahHeap::MARKING); 77 LIR_Opr mask_reg = gen->new_register(T_INT); 78 __ move(mask, mask_reg); 79 80 if (two_operand_lir_form) { 81 __ logical_and(flag_val, mask_reg, flag_val); 82 } else { 83 LIR_Opr masked_flag = gen->new_register(T_INT); 84 __ logical_and(flag_val, mask_reg, masked_flag); 85 flag_val = masked_flag; 86 } 87 __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0)); 88 89 LIR_PatchCode pre_val_patch_code = lir_patch_none; 90 91 CodeStub* slow; 92 93 if (do_load) { 94 assert(pre_val == LIR_OprFact::illegalOpr, "sanity"); 95 assert(addr_opr != LIR_OprFact::illegalOpr, "sanity"); 96 97 if (patch) 98 pre_val_patch_code = lir_patch_normal; 99 100 pre_val = gen->new_register(T_OBJECT); 101 102 if (!addr_opr->is_address()) { 103 assert(addr_opr->is_register(), "must be"); 104 addr_opr = LIR_OprFact::address(new LIR_Address(addr_opr, T_OBJECT)); 105 } 106 slow = new ShenandoahPreBarrierStub(addr_opr, pre_val, pre_val_patch_code, info ? new CodeEmitInfo(info) : nullptr); 107 } else { 108 assert(addr_opr == LIR_OprFact::illegalOpr, "sanity"); 109 assert(pre_val->is_register(), "must be"); 110 assert(pre_val->type() == T_OBJECT, "must be an object"); 111 112 slow = new ShenandoahPreBarrierStub(pre_val); 113 } 114 115 __ branch(lir_cond_notEqual, slow); 116 __ branch_destination(slow->continuation()); 117 } 118 119 LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr, DecoratorSet decorators) { 120 if (ShenandoahLoadRefBarrier) { 121 return load_reference_barrier_impl(gen, obj, addr, decorators); 122 } else { 123 return obj; 124 } 125 } 126 127 LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr, DecoratorSet decorators) { 128 assert(ShenandoahLoadRefBarrier, "Should be enabled"); 129 130 obj = ensure_in_register(gen, obj, T_OBJECT); 131 assert(obj->is_register(), "must be a register at this point"); 132 addr = ensure_in_register(gen, addr, T_ADDRESS); 133 assert(addr->is_register(), "must be a register at this point"); 134 LIR_Opr result = gen->result_register_for(obj->value_type()); 135 __ move(obj, result); 136 LIR_Opr tmp1 = gen->new_register(T_ADDRESS); 137 LIR_Opr tmp2 = gen->new_register(T_ADDRESS); 138 139 LIR_Opr thrd = gen->getThreadPointer(); 140 LIR_Address* active_flag_addr = 141 new LIR_Address(thrd, 142 in_bytes(ShenandoahThreadLocalData::gc_state_offset()), 143 T_BYTE); 144 // Read and check the gc-state-flag. 145 LIR_Opr flag_val = gen->new_register(T_INT); 146 __ load(active_flag_addr, flag_val); 147 int flags = ShenandoahHeap::HAS_FORWARDED; 148 if (!ShenandoahBarrierSet::is_strong_access(decorators)) { 149 flags |= ShenandoahHeap::WEAK_ROOTS; 150 } 151 LIR_Opr mask = LIR_OprFact::intConst(flags); 152 LIR_Opr mask_reg = gen->new_register(T_INT); 153 __ move(mask, mask_reg); 154 155 if (two_operand_lir_form) { 156 __ logical_and(flag_val, mask_reg, flag_val); 157 } else { 158 LIR_Opr masked_flag = gen->new_register(T_INT); 159 __ logical_and(flag_val, mask_reg, masked_flag); 160 flag_val = masked_flag; 161 } 162 __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0)); 163 164 CodeStub* slow = new ShenandoahLoadReferenceBarrierStub(obj, addr, result, tmp1, tmp2, decorators); 165 __ branch(lir_cond_notEqual, slow); 166 __ branch_destination(slow->continuation()); 167 168 return result; 169 } 170 171 LIR_Opr ShenandoahBarrierSetC1::ensure_in_register(LIRGenerator* gen, LIR_Opr obj, BasicType type) { 172 if (!obj->is_register()) { 173 LIR_Opr obj_reg; 174 if (obj->is_constant()) { 175 obj_reg = gen->new_register(type); 176 __ move(obj, obj_reg); 177 } else { 178 obj_reg = gen->new_pointer_register(); 179 __ leal(obj, obj_reg); 180 } 181 obj = obj_reg; 182 } 183 return obj; 184 } 185 186 void ShenandoahBarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) { 187 if (access.is_oop()) { 188 if (ShenandoahSATBBarrier) { 189 pre_barrier(access.gen(), access.access_emit_info(), access.decorators(), access.resolved_addr(), LIR_OprFact::illegalOpr /* pre_val */); 190 } 191 } 192 BarrierSetC1::store_at_resolved(access, value); 193 } 194 195 LIR_Opr ShenandoahBarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) { 196 // We must resolve in register when patching. This is to avoid 197 // having a patch area in the load barrier stub, since the call 198 // into the runtime to patch will not have the proper oop map. 199 const bool patch_before_barrier = access.is_oop() && (access.decorators() & C1_NEEDS_PATCHING) != 0; 200 return BarrierSetC1::resolve_address(access, resolve_in_register || patch_before_barrier); 201 } 202 203 void ShenandoahBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { 204 // 1: non-reference load, no additional barrier is needed 205 if (!access.is_oop()) { 206 BarrierSetC1::load_at_resolved(access, result); 207 return; 208 } 209 210 LIRGenerator* gen = access.gen(); 211 DecoratorSet decorators = access.decorators(); 212 BasicType type = access.type(); 213 214 // 2: load a reference from src location and apply LRB if ShenandoahLoadRefBarrier is set 215 if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) { 216 LIR_Opr tmp = gen->new_register(T_OBJECT); 217 BarrierSetC1::load_at_resolved(access, tmp); 218 tmp = load_reference_barrier(gen, tmp, access.resolved_addr(), decorators); 219 __ move(tmp, result); 220 } else { 221 BarrierSetC1::load_at_resolved(access, result); 222 } 223 224 // 3: apply keep-alive barrier for java.lang.ref.Reference if needed 225 if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { 226 bool is_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; 227 228 // Register the value in the referent field with the pre-barrier 229 LabelObj *Lcont_anonymous; 230 if (is_anonymous) { 231 Lcont_anonymous = new LabelObj(); 232 generate_referent_check(access, Lcont_anonymous); 233 } 234 pre_barrier(gen, access.access_emit_info(), decorators, LIR_OprFact::illegalOpr /* addr_opr */, 235 result /* pre_val */); 236 if (is_anonymous) { 237 __ branch_destination(Lcont_anonymous->label()); 238 } 239 } 240 } 241 242 class C1ShenandoahPreBarrierCodeGenClosure : public StubAssemblerCodeGenClosure { 243 virtual OopMapSet* generate_code(StubAssembler* sasm) { 244 ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); 245 bs->generate_c1_pre_barrier_runtime_stub(sasm); 246 return nullptr; 247 } 248 }; 249 250 class C1ShenandoahLoadReferenceBarrierCodeGenClosure : public StubAssemblerCodeGenClosure { 251 private: 252 const DecoratorSet _decorators; 253 254 public: 255 C1ShenandoahLoadReferenceBarrierCodeGenClosure(DecoratorSet decorators) : _decorators(decorators) {} 256 257 virtual OopMapSet* generate_code(StubAssembler* sasm) { 258 ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); 259 bs->generate_c1_load_reference_barrier_runtime_stub(sasm, _decorators); 260 return nullptr; 261 } 262 }; 263 264 void ShenandoahBarrierSetC1::generate_c1_runtime_stubs(BufferBlob* buffer_blob) { 265 C1ShenandoahPreBarrierCodeGenClosure pre_code_gen_cl; 266 _pre_barrier_c1_runtime_code_blob = Runtime1::generate_blob(buffer_blob, C1StubId::NO_STUBID, 267 "shenandoah_pre_barrier_slow", 268 false, &pre_code_gen_cl); 269 if (ShenandoahLoadRefBarrier) { 270 C1ShenandoahLoadReferenceBarrierCodeGenClosure lrb_strong_code_gen_cl(ON_STRONG_OOP_REF); 271 _load_reference_barrier_strong_rt_code_blob = Runtime1::generate_blob(buffer_blob, C1StubId::NO_STUBID, 272 "shenandoah_load_reference_barrier_strong_slow", 273 false, &lrb_strong_code_gen_cl); 274 275 C1ShenandoahLoadReferenceBarrierCodeGenClosure lrb_strong_native_code_gen_cl(ON_STRONG_OOP_REF | IN_NATIVE); 276 _load_reference_barrier_strong_native_rt_code_blob = Runtime1::generate_blob(buffer_blob, C1StubId::NO_STUBID, 277 "shenandoah_load_reference_barrier_strong_native_slow", 278 false, &lrb_strong_native_code_gen_cl); 279 280 C1ShenandoahLoadReferenceBarrierCodeGenClosure lrb_weak_code_gen_cl(ON_WEAK_OOP_REF); 281 _load_reference_barrier_weak_rt_code_blob = Runtime1::generate_blob(buffer_blob, C1StubId::NO_STUBID, 282 "shenandoah_load_reference_barrier_weak_slow", 283 false, &lrb_weak_code_gen_cl); 284 285 C1ShenandoahLoadReferenceBarrierCodeGenClosure lrb_phantom_code_gen_cl(ON_PHANTOM_OOP_REF | IN_NATIVE); 286 _load_reference_barrier_phantom_rt_code_blob = Runtime1::generate_blob(buffer_blob, C1StubId::NO_STUBID, 287 "shenandoah_load_reference_barrier_phantom_slow", 288 false, &lrb_phantom_code_gen_cl); 289 } 290 }