1 /* 2 * Copyright (c) 2018, 2020, Red Hat, Inc. All rights reserved. 3 * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 #include "precompiled.hpp" 27 #include "gc/shenandoah/shenandoahBarrierSet.hpp" 28 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" 29 #include "gc/shenandoah/shenandoahForwarding.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/heuristics/shenandoahHeuristics.hpp" 35 #include "interpreter/interpreter.hpp" 36 #include "interpreter/interp_masm.hpp" 37 #include "runtime/javaThread.hpp" 38 #include "runtime/sharedRuntime.hpp" 39 #ifdef COMPILER1 40 #include "c1/c1_LIRAssembler.hpp" 41 #include "c1/c1_MacroAssembler.hpp" 42 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" 43 #endif 44 45 #define __ masm-> 46 47 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, 48 Register src, Register dst, Register count, RegSet saved_regs) { 49 if (is_oop) { 50 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; 51 if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) { 52 53 Label done; 54 55 // Avoid calling runtime if count == 0 56 __ beqz(count, done); 57 58 // Is GC active? 59 Address gc_state(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); 60 assert_different_registers(src, dst, count, t0); 61 62 __ lbu(t0, gc_state); 63 if (ShenandoahSATBBarrier && dest_uninitialized) { 64 __ test_bit(t0, t0, ShenandoahHeap::HAS_FORWARDED_BITPOS); 65 __ beqz(t0, done); 66 } else { 67 __ andi(t0, t0, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING); 68 __ beqz(t0, done); 69 } 70 71 __ push_reg(saved_regs, sp); 72 if (UseCompressedOops) { 73 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop), 74 src, dst, count); 75 } else { 76 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop), src, dst, count); 77 } 78 __ pop_reg(saved_regs, sp); 79 __ bind(done); 80 } 81 } 82 } 83 84 void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm, 85 Register obj, 86 Register pre_val, 87 Register thread, 88 Register tmp, 89 bool tosca_live, 90 bool expand_call) { 91 if (ShenandoahSATBBarrier) { 92 satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, t0, tosca_live, expand_call); 93 } 94 } 95 96 void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, 97 Register obj, 98 Register pre_val, 99 Register thread, 100 Register tmp1, 101 Register tmp2, 102 bool tosca_live, 103 bool expand_call) { 104 // If expand_call is true then we expand the call_VM_leaf macro 105 // directly to skip generating the check by 106 // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. 107 assert(thread == xthread, "must be"); 108 109 Label done; 110 Label runtime; 111 112 assert_different_registers(obj, pre_val, tmp1, tmp2); 113 assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); 114 115 Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); 116 Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset())); 117 118 // Is marking active? 119 Address gc_state(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); 120 __ lbu(t1, gc_state); 121 __ test_bit(t1, t1, ShenandoahHeap::MARKING_BITPOS); 122 __ beqz(t1, done); 123 124 // Do we need to load the previous value? 125 if (obj != noreg) { 126 __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); 127 } 128 129 // Is the previous value null? 130 __ beqz(pre_val, done); 131 132 // Can we store original value in the thread's buffer? 133 // Is index == 0? 134 // (The index field is typed as size_t.) 135 __ ld(tmp1, index); // tmp := *index_adr 136 __ beqz(tmp1, runtime); // tmp == 0? If yes, goto runtime 137 138 __ sub(tmp1, tmp1, wordSize); // tmp := tmp - wordSize 139 __ sd(tmp1, index); // *index_adr := tmp 140 __ ld(tmp2, buffer); 141 __ add(tmp1, tmp1, tmp2); // tmp := tmp + *buffer_adr 142 143 // Record the previous value 144 __ sd(pre_val, Address(tmp1, 0)); 145 __ j(done); 146 147 __ bind(runtime); 148 // save the live input values 149 RegSet saved = RegSet::of(pre_val); 150 if (tosca_live) saved += RegSet::of(x10); 151 if (obj != noreg) saved += RegSet::of(obj); 152 153 __ push_reg(saved, sp); 154 155 // Calling the runtime using the regular call_VM_leaf mechanism generates 156 // code (generated by InterpreterMacroAssember::call_VM_leaf_base) 157 // that checks that the *(rfp+frame::interpreter_frame_last_sp) is null. 158 // 159 // If we care generating the pre-barrier without a frame (e.g. in the 160 // intrinsified Reference.get() routine) then ebp might be pointing to 161 // the caller frame and so this check will most likely fail at runtime. 162 // 163 // Expanding the call directly bypasses the generation of the check. 164 // So when we do not have have a full interpreter frame on the stack 165 // expand_call should be passed true. 166 if (expand_call) { 167 assert(pre_val != c_rarg1, "smashed arg"); 168 __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); 169 } else { 170 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); 171 } 172 173 __ pop_reg(saved, sp); 174 175 __ bind(done); 176 } 177 178 void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp) { 179 assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled"); 180 181 Label is_null; 182 __ beqz(dst, is_null); 183 resolve_forward_pointer_not_null(masm, dst, tmp); 184 __ bind(is_null); 185 } 186 187 // IMPORTANT: This must preserve all registers, even t0 and t1, except those explicitly 188 // passed in. 189 void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp) { 190 assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled"); 191 // The below loads the mark word, checks if the lowest two bits are 192 // set, and if so, clear the lowest two bits and copy the result 193 // to dst. Otherwise it leaves dst alone. 194 // Implementing this is surprisingly awkward. I do it here by: 195 // - Inverting the mark word 196 // - Test lowest two bits == 0 197 // - If so, set the lowest two bits 198 // - Invert the result back, and copy to dst 199 RegSet saved_regs = RegSet::of(t2); 200 bool borrow_reg = (tmp == noreg); 201 if (borrow_reg) { 202 // No free registers available. Make one useful. 203 tmp = t0; 204 if (tmp == dst) { 205 tmp = t1; 206 } 207 saved_regs += RegSet::of(tmp); 208 } 209 210 assert_different_registers(tmp, dst, t2); 211 __ push_reg(saved_regs, sp); 212 213 Label done; 214 __ ld(tmp, Address(dst, oopDesc::mark_offset_in_bytes())); 215 __ xori(tmp, tmp, -1); // eon with 0 is equivalent to XOR with -1 216 __ andi(t2, tmp, markWord::lock_mask_in_place); 217 __ bnez(t2, done); 218 __ ori(tmp, tmp, markWord::marked_value); 219 __ xori(dst, tmp, -1); // eon with 0 is equivalent to XOR with -1 220 __ bind(done); 221 222 __ pop_reg(saved_regs, sp); 223 } 224 225 void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, 226 Register dst, 227 Address load_addr, 228 DecoratorSet decorators) { 229 assert(ShenandoahLoadRefBarrier, "Should be enabled"); 230 assert(dst != t1 && load_addr.base() != t1, "need t1"); 231 assert_different_registers(load_addr.base(), t0, t1); 232 233 bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); 234 bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); 235 bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); 236 bool is_native = ShenandoahBarrierSet::is_native_access(decorators); 237 bool is_narrow = UseCompressedOops && !is_native; 238 239 Label heap_stable, not_cset; 240 __ enter(); 241 Address gc_state(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); 242 __ lbu(t1, gc_state); 243 244 // Check for heap stability 245 if (is_strong) { 246 __ test_bit(t1, t1, ShenandoahHeap::HAS_FORWARDED_BITPOS); 247 __ beqz(t1, heap_stable); 248 } else { 249 Label lrb; 250 __ test_bit(t0, t1, ShenandoahHeap::WEAK_ROOTS_BITPOS); 251 __ bnez(t0, lrb); 252 __ test_bit(t0, t1, ShenandoahHeap::HAS_FORWARDED_BITPOS); 253 __ beqz(t0, heap_stable); 254 __ bind(lrb); 255 } 256 257 // use x11 for load address 258 Register result_dst = dst; 259 if (dst == x11) { 260 __ mv(t1, dst); 261 dst = t1; 262 } 263 264 // Save x10 and x11, unless it is an output register 265 RegSet saved_regs = RegSet::of(x10, x11) - result_dst; 266 __ push_reg(saved_regs, sp); 267 __ la(x11, load_addr); 268 __ mv(x10, dst); 269 270 // Test for in-cset 271 if (is_strong) { 272 __ mv(t1, ShenandoahHeap::in_cset_fast_test_addr()); 273 __ srli(t0, x10, ShenandoahHeapRegion::region_size_bytes_shift_jint()); 274 __ add(t1, t1, t0); 275 __ lbu(t1, Address(t1)); 276 __ test_bit(t0, t1, 0); 277 __ beqz(t0, not_cset); 278 } 279 280 __ push_call_clobbered_registers(); 281 address target = nullptr; 282 if (is_strong) { 283 if (is_narrow) { 284 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow); 285 } else { 286 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); 287 } 288 } else if (is_weak) { 289 if (is_narrow) { 290 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow); 291 } else { 292 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak); 293 } 294 } else { 295 assert(is_phantom, "only remaining strength"); 296 assert(!is_narrow, "phantom access cannot be narrow"); 297 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak); 298 } 299 __ rt_call(target); 300 __ mv(t0, x10); 301 __ pop_call_clobbered_registers(); 302 __ mv(x10, t0); 303 __ bind(not_cset); 304 __ mv(result_dst, x10); 305 __ pop_reg(saved_regs, sp); 306 307 __ bind(heap_stable); 308 __ leave(); 309 } 310 311 // 312 // Arguments: 313 // 314 // Inputs: 315 // src: oop location to load from, might be clobbered 316 // 317 // Output: 318 // dst: oop loaded from src location 319 // 320 // Kill: 321 // x30 (tmp reg) 322 // 323 // Alias: 324 // dst: x30 (might use x30 as temporary output register to avoid clobbering src) 325 // 326 void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, 327 DecoratorSet decorators, 328 BasicType type, 329 Register dst, 330 Address src, 331 Register tmp1, 332 Register tmp2) { 333 // 1: non-reference load, no additional barrier is needed 334 if (!is_reference_type(type)) { 335 BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2); 336 return; 337 } 338 339 // 2: load a reference from src location and apply LRB if needed 340 if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) { 341 Register result_dst = dst; 342 343 // Preserve src location for LRB 344 RegSet saved_regs; 345 if (dst == src.base()) { 346 dst = (src.base() == x28) ? x29 : x28; 347 saved_regs = RegSet::of(dst); 348 __ push_reg(saved_regs, sp); 349 } 350 assert_different_registers(dst, src.base()); 351 352 BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2); 353 354 load_reference_barrier(masm, dst, src, decorators); 355 356 if (dst != result_dst) { 357 __ mv(result_dst, dst); 358 dst = result_dst; 359 } 360 361 if (saved_regs.bits() != 0) { 362 __ pop_reg(saved_regs, sp); 363 } 364 } else { 365 BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2); 366 } 367 368 // 3: apply keep-alive barrier if needed 369 if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { 370 __ enter(); 371 __ push_call_clobbered_registers(); 372 satb_write_barrier_pre(masm /* masm */, 373 noreg /* obj */, 374 dst /* pre_val */, 375 xthread /* thread */, 376 tmp1 /* tmp1 */, 377 tmp2 /* tmp2 */, 378 true /* tosca_live */, 379 true /* expand_call */); 380 __ pop_call_clobbered_registers(); 381 __ leave(); 382 } 383 } 384 385 void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, 386 Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { 387 bool on_oop = is_reference_type(type); 388 if (!on_oop) { 389 BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); 390 return; 391 } 392 393 // flatten object address if needed 394 if (dst.offset() == 0) { 395 if (dst.base() != tmp3) { 396 __ mv(tmp3, dst.base()); 397 } 398 } else { 399 __ la(tmp3, dst); 400 } 401 402 shenandoah_write_barrier_pre(masm, 403 tmp3 /* obj */, 404 tmp2 /* pre_val */, 405 xthread /* thread */, 406 tmp1 /* tmp */, 407 val != noreg /* tosca_live */, 408 false /* expand_call */); 409 410 if (val == noreg) { 411 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), noreg, noreg, noreg, noreg); 412 } else { 413 // Barrier needs uncompressed oop for region cross check. 414 Register new_val = val; 415 if (UseCompressedOops) { 416 new_val = t1; 417 __ mv(new_val, val); 418 } 419 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg); 420 } 421 } 422 423 void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, 424 Register obj, Register tmp, Label& slowpath) { 425 Label done; 426 // Resolve jobject 427 BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath); 428 429 // Check for null. 430 __ beqz(obj, done); 431 432 assert(obj != t1, "need t1"); 433 Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset()); 434 __ lbu(t1, gc_state); 435 436 // Check for heap in evacuation phase 437 __ test_bit(t0, t1, ShenandoahHeap::EVACUATION_BITPOS); 438 __ bnez(t0, slowpath); 439 440 __ bind(done); 441 } 442 443 // Special Shenandoah CAS implementation that handles false negatives due 444 // to concurrent evacuation. The service is more complex than a 445 // traditional CAS operation because the CAS operation is intended to 446 // succeed if the reference at addr exactly matches expected or if the 447 // reference at addr holds a pointer to a from-space object that has 448 // been relocated to the location named by expected. There are two 449 // races that must be addressed: 450 // a) A parallel thread may mutate the contents of addr so that it points 451 // to a different object. In this case, the CAS operation should fail. 452 // b) A parallel thread may heal the contents of addr, replacing a 453 // from-space pointer held in addr with the to-space pointer 454 // representing the new location of the object. 455 // Upon entry to cmpxchg_oop, it is assured that new_val equals null 456 // or it refers to an object that is not being evacuated out of 457 // from-space, or it refers to the to-space version of an object that 458 // is being evacuated out of from-space. 459 // 460 // By default the value held in the result register following execution 461 // of the generated code sequence is 0 to indicate failure of CAS, 462 // non-zero to indicate success. If is_cae, the result is the value most 463 // recently fetched from addr rather than a boolean success indicator. 464 // 465 // Clobbers t0, t1 466 void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, 467 Register addr, 468 Register expected, 469 Register new_val, 470 Assembler::Aqrl acquire, 471 Assembler::Aqrl release, 472 bool is_cae, 473 Register result) { 474 bool is_narrow = UseCompressedOops; 475 Assembler::operand_size size = is_narrow ? Assembler::uint32 : Assembler::int64; 476 477 assert_different_registers(addr, expected, t0, t1); 478 assert_different_registers(addr, new_val, t0, t1); 479 480 Label retry, success, fail, done; 481 482 __ bind(retry); 483 484 // Step1: Try to CAS. 485 __ cmpxchg(addr, expected, new_val, size, acquire, release, /* result */ t1); 486 487 // If success, then we are done. 488 __ beq(expected, t1, success); 489 490 // Step2: CAS failed, check the forwarded pointer. 491 __ mv(t0, t1); 492 493 if (is_narrow) { 494 __ decode_heap_oop(t0, t0); 495 } 496 resolve_forward_pointer(masm, t0); 497 498 __ encode_heap_oop(t0, t0); 499 500 // Report failure when the forwarded oop was not expected. 501 __ bne(t0, expected, fail); 502 503 // Step 3: CAS again using the forwarded oop. 504 __ cmpxchg(addr, t1, new_val, size, acquire, release, /* result */ t0); 505 506 // Retry when failed. 507 __ bne(t0, t1, retry); 508 509 __ bind(success); 510 if (is_cae) { 511 __ mv(result, expected); 512 } else { 513 __ mv(result, 1); 514 } 515 __ j(done); 516 517 __ bind(fail); 518 if (is_cae) { 519 __ mv(result, t0); 520 } else { 521 __ mv(result, zr); 522 } 523 524 __ bind(done); 525 } 526 527 #undef __ 528 529 #ifdef COMPILER1 530 531 #define __ ce->masm()-> 532 533 void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub) { 534 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); 535 // At this point we know that marking is in progress. 536 // If do_load() is true then we have to emit the 537 // load of the previous value; otherwise it has already 538 // been loaded into _pre_val. 539 __ bind(*stub->entry()); 540 541 assert(stub->pre_val()->is_register(), "Precondition."); 542 543 Register pre_val_reg = stub->pre_val()->as_register(); 544 545 if (stub->do_load()) { 546 ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /* wide */); 547 } 548 __ beqz(pre_val_reg, *stub->continuation(), /* is_far */ true); 549 ce->store_parameter(stub->pre_val()->as_register(), 0); 550 __ far_call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin())); 551 __ j(*stub->continuation()); 552 } 553 554 void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assembler* ce, 555 ShenandoahLoadReferenceBarrierStub* stub) { 556 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); 557 __ bind(*stub->entry()); 558 559 DecoratorSet decorators = stub->decorators(); 560 bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); 561 bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); 562 bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); 563 bool is_native = ShenandoahBarrierSet::is_native_access(decorators); 564 565 Register obj = stub->obj()->as_register(); 566 Register res = stub->result()->as_register(); 567 Register addr = stub->addr()->as_pointer_register(); 568 Register tmp1 = stub->tmp1()->as_register(); 569 Register tmp2 = stub->tmp2()->as_register(); 570 571 assert(res == x10, "result must arrive in x10"); 572 assert_different_registers(tmp1, tmp2, t0); 573 574 if (res != obj) { 575 __ mv(res, obj); 576 } 577 578 if (is_strong) { 579 // Check for object in cset. 580 __ mv(tmp2, ShenandoahHeap::in_cset_fast_test_addr()); 581 __ srli(tmp1, res, ShenandoahHeapRegion::region_size_bytes_shift_jint()); 582 __ add(tmp2, tmp2, tmp1); 583 __ lbu(tmp2, Address(tmp2)); 584 __ beqz(tmp2, *stub->continuation(), true /* is_far */); 585 } 586 587 ce->store_parameter(res, 0); 588 ce->store_parameter(addr, 1); 589 590 if (is_strong) { 591 if (is_native) { 592 __ far_call(RuntimeAddress(bs->load_reference_barrier_strong_native_rt_code_blob()->code_begin())); 593 } else { 594 __ far_call(RuntimeAddress(bs->load_reference_barrier_strong_rt_code_blob()->code_begin())); 595 } 596 } else if (is_weak) { 597 __ far_call(RuntimeAddress(bs->load_reference_barrier_weak_rt_code_blob()->code_begin())); 598 } else { 599 assert(is_phantom, "only remaining strength"); 600 __ far_call(RuntimeAddress(bs->load_reference_barrier_phantom_rt_code_blob()->code_begin())); 601 } 602 603 __ j(*stub->continuation()); 604 } 605 606 #undef __ 607 608 #define __ sasm-> 609 610 void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { 611 __ prologue("shenandoah_pre_barrier", false); 612 613 // arg0 : previous value of memory 614 615 BarrierSet* bs = BarrierSet::barrier_set(); 616 617 const Register pre_val = x10; 618 const Register thread = xthread; 619 const Register tmp = t0; 620 621 Address queue_index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); 622 Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset())); 623 624 Label done; 625 Label runtime; 626 627 // Is marking still active? 628 Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); 629 __ lb(tmp, gc_state); 630 __ test_bit(tmp, tmp, ShenandoahHeap::MARKING_BITPOS); 631 __ beqz(tmp, done); 632 633 // Can we store original value in the thread's buffer? 634 __ ld(tmp, queue_index); 635 __ beqz(tmp, runtime); 636 637 __ sub(tmp, tmp, wordSize); 638 __ sd(tmp, queue_index); 639 __ ld(t1, buffer); 640 __ add(tmp, tmp, t1); 641 __ load_parameter(0, t1); 642 __ sd(t1, Address(tmp, 0)); 643 __ j(done); 644 645 __ bind(runtime); 646 __ push_call_clobbered_registers(); 647 __ load_parameter(0, pre_val); 648 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); 649 __ pop_call_clobbered_registers(); 650 __ bind(done); 651 652 __ epilogue(); 653 } 654 655 void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, 656 DecoratorSet decorators) { 657 __ prologue("shenandoah_load_reference_barrier", false); 658 // arg0 : object to be resolved 659 660 __ push_call_clobbered_registers(); 661 __ load_parameter(0, x10); 662 __ load_parameter(1, x11); 663 664 bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); 665 bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); 666 bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); 667 bool is_native = ShenandoahBarrierSet::is_native_access(decorators); 668 address target = nullptr; 669 if (is_strong) { 670 if (is_native) { 671 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); 672 } else { 673 if (UseCompressedOops) { 674 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow); 675 } else { 676 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); 677 } 678 } 679 } else if (is_weak) { 680 assert(!is_native, "weak must not be called off-heap"); 681 if (UseCompressedOops) { 682 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow); 683 } else { 684 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak); 685 } 686 } else { 687 assert(is_phantom, "only remaining strength"); 688 assert(is_native, "phantom must only be called off-heap"); 689 target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom); 690 } 691 __ rt_call(target); 692 __ mv(t0, x10); 693 __ pop_call_clobbered_registers(); 694 __ mv(x10, t0); 695 696 __ epilogue(); 697 } 698 699 #undef __ 700 701 #endif // COMPILER1