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