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