1 /* 2 * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. 3 * Copyright (c) 2012, 2022 SAP SE. 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 "gc/shared/gcArguments.hpp" 27 #include "gc/shared/gc_globals.hpp" 28 #include "macroAssembler_ppc.hpp" 29 #include "precompiled.hpp" 30 #include "asm/macroAssembler.inline.hpp" 31 #include "gc/shenandoah/shenandoahBarrierSet.hpp" 32 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" 33 #include "gc/shenandoah/shenandoahForwarding.hpp" 34 #include "gc/shenandoah/shenandoahHeap.hpp" 35 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 36 #include "gc/shenandoah/shenandoahHeapRegion.hpp" 37 #include "gc/shenandoah/shenandoahRuntime.hpp" 38 #include "gc/shenandoah/shenandoahThreadLocalData.hpp" 39 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" 40 #include "gc/shenandoah/mode/shenandoahMode.hpp" 41 #include "interpreter/interpreter.hpp" 42 #include "runtime/javaThread.hpp" 43 #include "runtime/sharedRuntime.hpp" 44 #include "utilities/globalDefinitions.hpp" 45 #include "vm_version_ppc.hpp" 46 #ifdef COMPILER1 47 #include "c1/c1_LIRAssembler.hpp" 48 #include "c1/c1_MacroAssembler.hpp" 49 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" 50 #endif 51 52 #define __ masm-> 53 54 void ShenandoahBarrierSetAssembler::satb_write_barrier(MacroAssembler *masm, 55 Register base, RegisterOrConstant ind_or_offs, 56 Register tmp1, Register tmp2, Register tmp3, 57 MacroAssembler::PreservationLevel preservation_level) { 58 if (ShenandoahSATBBarrier) { 59 __ block_comment("satb_write_barrier (shenandoahgc) {"); 60 satb_write_barrier_impl(masm, 0, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); 61 __ block_comment("} satb_write_barrier (shenandoahgc)"); 62 } 63 } 64 65 void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler *masm, 66 Register val, 67 Register tmp1, Register tmp2, 68 MacroAssembler::PreservationLevel preservation_level, 69 DecoratorSet decorators) { 70 // IU barriers are also employed to avoid resurrection of weak references, 71 // even if Shenandoah does not operate in incremental update mode. 72 if (ShenandoahIUBarrier || ShenandoahSATBBarrier) { 73 __ block_comment("iu_barrier (shenandoahgc) {"); 74 satb_write_barrier_impl(masm, decorators, noreg, noreg, val, tmp1, tmp2, preservation_level); 75 __ block_comment("} iu_barrier (shenandoahgc)"); 76 } 77 } 78 79 void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler *masm, DecoratorSet decorators, 80 Register base, RegisterOrConstant ind_or_offs, 81 Register dst, 82 Register tmp1, Register tmp2, 83 MacroAssembler::PreservationLevel preservation_level) { 84 if (ShenandoahLoadRefBarrier) { 85 __ block_comment("load_reference_barrier (shenandoahgc) {"); 86 load_reference_barrier_impl(masm, decorators, base, ind_or_offs, dst, tmp1, tmp2, preservation_level); 87 __ block_comment("} load_reference_barrier (shenandoahgc)"); 88 } 89 } 90 91 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler *masm, DecoratorSet decorators, BasicType type, 92 Register src, Register dst, Register count, 93 Register preserve1, Register preserve2) { 94 Register R11_tmp = R11_scratch1; 95 96 assert_different_registers(src, dst, count, R11_tmp, noreg); 97 if (preserve1 != noreg) { 98 // Technically not required, but likely to indicate an error. 99 assert_different_registers(preserve1, preserve2); 100 } 101 102 /* ==== Check whether barrier is required (optimizations) ==== */ 103 // Fast path: Component type of array is not a reference type. 104 if (!is_reference_type(type)) { 105 return; 106 } 107 108 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; 109 110 // Fast path: No barrier required if for every barrier type, it is either disabled or would not store 111 // any useful information. 112 if ((!ShenandoahSATBBarrier || dest_uninitialized) && !ShenandoahIUBarrier && !ShenandoahLoadRefBarrier) { 113 return; 114 } 115 116 __ block_comment("arraycopy_prologue (shenandoahgc) {"); 117 Label skip_prologue; 118 119 // Fast path: Array is of length zero. 120 __ cmpdi(CCR0, count, 0); 121 __ beq(CCR0, skip_prologue); 122 123 /* ==== Check whether barrier is required (gc state) ==== */ 124 __ lbz(R11_tmp, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), 125 R16_thread); 126 127 // The set of garbage collection states requiring barriers depends on the available barrier types and the 128 // type of the reference in question. 129 // For instance, satb barriers may be skipped if it is certain that the overridden values are not relevant 130 // for the garbage collector. 131 const int required_states = ShenandoahSATBBarrier && dest_uninitialized 132 ? ShenandoahHeap::HAS_FORWARDED 133 : ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING; 134 135 __ andi_(R11_tmp, R11_tmp, required_states); 136 __ beq(CCR0, skip_prologue); 137 138 /* ==== Invoke runtime ==== */ 139 // Save to-be-preserved registers. 140 int highest_preserve_register_index = 0; 141 { 142 if (preserve1 != noreg && preserve1->is_volatile()) { 143 __ std(preserve1, -BytesPerWord * ++highest_preserve_register_index, R1_SP); 144 } 145 if (preserve2 != noreg && preserve2 != preserve1 && preserve2->is_volatile()) { 146 __ std(preserve2, -BytesPerWord * ++highest_preserve_register_index, R1_SP); 147 } 148 149 __ std(src, -BytesPerWord * ++highest_preserve_register_index, R1_SP); 150 __ std(dst, -BytesPerWord * ++highest_preserve_register_index, R1_SP); 151 __ std(count, -BytesPerWord * ++highest_preserve_register_index, R1_SP); 152 153 __ save_LR_CR(R11_tmp); 154 __ push_frame_reg_args(-BytesPerWord * highest_preserve_register_index, 155 R11_tmp); 156 } 157 158 // Invoke runtime. 159 address jrt_address = nullptr; 160 if (UseCompressedOops) { 161 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry); 162 } else { 163 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry); 164 } 165 assert(jrt_address != nullptr, "jrt routine cannot be found"); 166 167 __ call_VM_leaf(jrt_address, src, dst, count); 168 169 // Restore to-be-preserved registers. 170 { 171 __ pop_frame(); 172 __ restore_LR_CR(R11_tmp); 173 174 __ ld(count, -BytesPerWord * highest_preserve_register_index--, R1_SP); 175 __ ld(dst, -BytesPerWord * highest_preserve_register_index--, R1_SP); 176 __ ld(src, -BytesPerWord * highest_preserve_register_index--, R1_SP); 177 178 if (preserve2 != noreg && preserve2 != preserve1 && preserve2->is_volatile()) { 179 __ ld(preserve2, -BytesPerWord * highest_preserve_register_index--, R1_SP); 180 } 181 if (preserve1 != noreg && preserve1->is_volatile()) { 182 __ ld(preserve1, -BytesPerWord * highest_preserve_register_index--, R1_SP); 183 } 184 } 185 186 __ bind(skip_prologue); 187 __ block_comment("} arraycopy_prologue (shenandoahgc)"); 188 } 189 190 void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, 191 Register dst, Register count, 192 Register preserve) { 193 if (ShenandoahCardBarrier && is_reference_type(type)) { 194 __ block_comment("arraycopy_epilogue (shenandoahgc) {"); 195 gen_write_ref_array_post_barrier(masm, decorators, dst, count, preserve); 196 __ block_comment("} arraycopy_epilogue (shenandoahgc)"); 197 } 198 } 199 200 // The to-be-enqueued value can either be determined 201 // - dynamically by passing the reference's address information (load mode) or 202 // - statically by passing a register the value is stored in (preloaded mode) 203 // - for performance optimizations in cases where the previous value is known (currently not implemented) and 204 // - for incremental-update barriers. 205 // 206 // decorators: The previous value's decorator set. 207 // In "load mode", the value must equal '0'. 208 // base: Base register of the reference's address (load mode). 209 // In "preloaded mode", the register must equal 'noreg'. 210 // ind_or_offs: Index or offset of the reference's address (load mode). 211 // If 'base' equals 'noreg' (preloaded mode), the passed value is ignored. 212 // pre_val: Register holding the to-be-stored value (preloaded mode). 213 // In "load mode", this register acts as a temporary register and must 214 // thus not be 'noreg'. In "preloaded mode", its content will be sustained. 215 // tmp1/tmp2: Temporary registers, one of which must be non-volatile in "preloaded mode". 216 void ShenandoahBarrierSetAssembler::satb_write_barrier_impl(MacroAssembler *masm, DecoratorSet decorators, 217 Register base, RegisterOrConstant ind_or_offs, 218 Register pre_val, 219 Register tmp1, Register tmp2, 220 MacroAssembler::PreservationLevel preservation_level) { 221 assert_different_registers(tmp1, tmp2, pre_val, noreg); 222 223 Label skip_barrier; 224 225 /* ==== Determine necessary runtime invocation preservation measures ==== */ 226 const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR; 227 const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS; 228 const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS; 229 230 // Check whether marking is active. 231 __ lbz(tmp1, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), R16_thread); 232 233 __ andi_(tmp1, tmp1, ShenandoahHeap::MARKING); 234 __ beq(CCR0, skip_barrier); 235 236 /* ==== Determine the reference's previous value ==== */ 237 bool preloaded_mode = base == noreg; 238 Register pre_val_save = noreg; 239 240 if (preloaded_mode) { 241 // Previous value has been passed to the method, so it must not be determined manually. 242 // In case 'pre_val' is a volatile register, it must be saved across the C-call 243 // as callers may depend on its value. 244 // Unless the general purposes registers are saved anyway, one of the temporary registers 245 // (i.e., 'tmp1' and 'tmp2') is used to the preserve 'pre_val'. 246 if (!preserve_gp_registers && pre_val->is_volatile()) { 247 pre_val_save = !tmp1->is_volatile() ? tmp1 : tmp2; 248 assert(!pre_val_save->is_volatile(), "at least one of the temporary registers must be non-volatile"); 249 } 250 251 if ((decorators & IS_NOT_NULL) != 0) { 252 #ifdef ASSERT 253 __ cmpdi(CCR0, pre_val, 0); 254 __ asm_assert_ne("null oop is not allowed"); 255 #endif // ASSERT 256 } else { 257 __ cmpdi(CCR0, pre_val, 0); 258 __ beq(CCR0, skip_barrier); 259 } 260 } else { 261 // Load from the reference address to determine the reference's current value (before the store is being performed). 262 // Contrary to the given value in "preloaded mode", it is not necessary to preserve it. 263 assert(decorators == 0, "decorator set must be empty"); 264 assert(base != noreg, "base must be a register"); 265 assert(!ind_or_offs.is_register() || ind_or_offs.as_register() != noreg, "ind_or_offs must be a register"); 266 if (UseCompressedOops) { 267 __ lwz(pre_val, ind_or_offs, base); 268 } else { 269 __ ld(pre_val, ind_or_offs, base); 270 } 271 272 __ cmpdi(CCR0, pre_val, 0); 273 __ beq(CCR0, skip_barrier); 274 275 if (UseCompressedOops) { 276 __ decode_heap_oop_not_null(pre_val); 277 } 278 } 279 280 /* ==== Try to enqueue the to-be-stored value directly into thread's local SATB mark queue ==== */ 281 { 282 Label runtime; 283 Register Rbuffer = tmp1, Rindex = tmp2; 284 285 // Check whether the queue has enough capacity to store another oop. 286 // If not, jump to the runtime to commit the buffer and to allocate a new one. 287 // (The buffer's index corresponds to the amount of remaining free space.) 288 __ ld(Rindex, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread); 289 __ cmpdi(CCR0, Rindex, 0); 290 __ beq(CCR0, runtime); // If index == 0 (buffer is full), goto runtime. 291 292 // Capacity suffices. Decrement the queue's size by the size of one oop. 293 // (The buffer is filled contrary to the heap's growing direction, i.e., it is filled downwards.) 294 __ addi(Rindex, Rindex, -wordSize); 295 __ std(Rindex, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread); 296 297 // Enqueue the previous value and skip the invocation of the runtime. 298 __ ld(Rbuffer, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()), R16_thread); 299 __ stdx(pre_val, Rbuffer, Rindex); 300 __ b(skip_barrier); 301 302 __ bind(runtime); 303 } 304 305 /* ==== Invoke runtime to commit SATB mark queue to gc and allocate a new buffer ==== */ 306 // Save to-be-preserved registers. 307 int nbytes_save = 0; 308 309 if (needs_frame) { 310 if (preserve_gp_registers) { 311 nbytes_save = (preserve_fp_registers 312 ? MacroAssembler::num_volatile_gp_regs + MacroAssembler::num_volatile_fp_regs 313 : MacroAssembler::num_volatile_gp_regs) * BytesPerWord; 314 __ save_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers); 315 } 316 317 __ save_LR_CR(tmp1); 318 __ push_frame_reg_args(nbytes_save, tmp2); 319 } 320 321 if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) { 322 assert(pre_val_save != noreg, "nv_save must not be noreg"); 323 324 // 'pre_val' register must be saved manually unless general-purpose are preserved in general. 325 __ mr(pre_val_save, pre_val); 326 } 327 328 // Invoke runtime. 329 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, R16_thread); 330 331 // Restore to-be-preserved registers. 332 if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) { 333 __ mr(pre_val, pre_val_save); 334 } 335 336 if (needs_frame) { 337 __ pop_frame(); 338 __ restore_LR_CR(tmp1); 339 340 if (preserve_gp_registers) { 341 __ restore_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers); 342 } 343 } 344 345 __ bind(skip_barrier); 346 } 347 348 void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler *masm, Register dst, Register tmp) { 349 __ block_comment("resolve_forward_pointer_not_null (shenandoahgc) {"); 350 351 Register tmp1 = tmp, 352 R0_tmp2 = R0; 353 assert_different_registers(dst, tmp1, R0_tmp2, noreg); 354 355 // If the object has been evacuated, the mark word layout is as follows: 356 // | forwarding pointer (62-bit) | '11' (2-bit) | 357 358 // The invariant that stack/thread pointers have the lowest two bits cleared permits retrieving 359 // the forwarding pointer solely by inversing the lowest two bits. 360 // This invariant follows inevitably from hotspot's minimal alignment. 361 assert(markWord::marked_value <= (unsigned long) MinObjAlignmentInBytes, 362 "marked value must not be higher than hotspot's minimal alignment"); 363 364 Label done; 365 366 // Load the object's mark word. 367 __ ld(tmp1, oopDesc::mark_offset_in_bytes(), dst); 368 369 // Load the bit mask for the lock bits. 370 __ li(R0_tmp2, markWord::lock_mask_in_place); 371 372 // Check whether all bits matching the bit mask are set. 373 // If that is the case, the object has been evacuated and the most significant bits form the forward pointer. 374 __ andc_(R0_tmp2, R0_tmp2, tmp1); 375 376 assert(markWord::lock_mask_in_place == markWord::marked_value, 377 "marked value must equal the value obtained when all lock bits are being set"); 378 if (VM_Version::has_isel()) { 379 __ xori(tmp1, tmp1, markWord::lock_mask_in_place); 380 __ isel(dst, CCR0, Assembler::equal, false, tmp1); 381 } else { 382 __ bne(CCR0, done); 383 __ xori(dst, tmp1, markWord::lock_mask_in_place); 384 } 385 386 __ bind(done); 387 __ block_comment("} resolve_forward_pointer_not_null (shenandoahgc)"); 388 } 389 390 // base: Base register of the reference's address. 391 // ind_or_offs: Index or offset of the reference's address (load mode). 392 // dst: Reference's address. In case the object has been evacuated, this is the to-space version 393 // of that object. 394 void ShenandoahBarrierSetAssembler::load_reference_barrier_impl( 395 MacroAssembler *masm, DecoratorSet decorators, 396 Register base, RegisterOrConstant ind_or_offs, 397 Register dst, 398 Register tmp1, Register tmp2, 399 MacroAssembler::PreservationLevel preservation_level) { 400 if (ind_or_offs.is_register()) { 401 assert_different_registers(tmp1, tmp2, base, ind_or_offs.as_register(), dst, noreg); 402 } else { 403 assert_different_registers(tmp1, tmp2, base, dst, noreg); 404 } 405 406 Label skip_barrier; 407 408 bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); 409 bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); 410 bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); 411 bool is_native = ShenandoahBarrierSet::is_native_access(decorators); 412 bool is_narrow = UseCompressedOops && !is_native; 413 414 /* ==== Check whether heap is stable ==== */ 415 __ lbz(tmp2, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), R16_thread); 416 417 if (is_strong) { 418 // For strong references, the heap is considered stable if "has forwarded" is not active. 419 __ andi_(tmp1, tmp2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION); 420 __ beq(CCR0, skip_barrier); 421 #ifdef ASSERT 422 // "evacuation" -> (implies) "has forwarded". If we reach this code, "has forwarded" must thus be set. 423 __ andi_(tmp1, tmp1, ShenandoahHeap::HAS_FORWARDED); 424 __ asm_assert_ne("'has forwarded' is missing"); 425 #endif // ASSERT 426 } else { 427 // For all non-strong references, the heap is considered stable if not any of "has forwarded", 428 // "root set processing", and "weak reference processing" is active. 429 // The additional phase conditions are in place to avoid the resurrection of weak references (see JDK-8266440). 430 Label skip_fastpath; 431 __ andi_(tmp1, tmp2, ShenandoahHeap::WEAK_ROOTS); 432 __ bne(CCR0, skip_fastpath); 433 434 __ andi_(tmp1, tmp2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION); 435 __ beq(CCR0, skip_barrier); 436 #ifdef ASSERT 437 // "evacuation" -> (implies) "has forwarded". If we reach this code, "has forwarded" must thus be set. 438 __ andi_(tmp1, tmp1, ShenandoahHeap::HAS_FORWARDED); 439 __ asm_assert_ne("'has forwarded' is missing"); 440 #endif // ASSERT 441 442 __ bind(skip_fastpath); 443 } 444 445 /* ==== Check whether region is in collection set ==== */ 446 if (is_strong) { 447 // Shenandoah stores metadata on regions in a continuous area of memory in which a single byte corresponds to 448 // an entire region of the shenandoah heap. At present, only the least significant bit is of significance 449 // and indicates whether the region is part of the collection set. 450 // 451 // All regions are of the same size and are always aligned by a power of two. 452 // Any address can thus be shifted by a fixed number of bits to retrieve the address prefix shared by 453 // all objects within that region (region identification bits). 454 // 455 // | unused bits | region identification bits | object identification bits | 456 // (Region size depends on a couple of criteria, such as page size, user-provided arguments and the max heap size. 457 // The number of object identification bits can thus not be determined at compile time.) 458 // 459 // ------------------------------------------------------- <--- cs (collection set) base address 460 // | lost space due to heap space base address -> 'ShenandoahHeap::in_cset_fast_test_addr()' 461 // | (region identification bits contain heap base offset) 462 // |------------------------------------------------------ <--- cs base address + (heap_base >> region size shift) 463 // | collection set in the proper -> shift: 'region_size_bytes_shift_jint()' 464 // | 465 // |------------------------------------------------------ <--- cs base address + (heap_base >> region size shift) 466 // + number of regions 467 __ load_const_optimized(tmp2, ShenandoahHeap::in_cset_fast_test_addr(), tmp1); 468 __ srdi(tmp1, dst, ShenandoahHeapRegion::region_size_bytes_shift_jint()); 469 __ lbzx(tmp2, tmp1, tmp2); 470 __ andi_(tmp2, tmp2, 1); 471 __ beq(CCR0, skip_barrier); 472 } 473 474 /* ==== Invoke runtime ==== */ 475 // Save to-be-preserved registers. 476 int nbytes_save = 0; 477 478 const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR; 479 const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS; 480 const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS; 481 482 if (needs_frame) { 483 if (preserve_gp_registers) { 484 nbytes_save = (preserve_fp_registers 485 ? MacroAssembler::num_volatile_gp_regs + MacroAssembler::num_volatile_fp_regs 486 : MacroAssembler::num_volatile_gp_regs) * BytesPerWord; 487 __ save_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers); 488 } 489 490 __ save_LR_CR(tmp1); 491 __ push_frame_reg_args(nbytes_save, tmp1); 492 } 493 494 // Calculate the reference's absolute address. 495 __ add(R4_ARG2, ind_or_offs, base); 496 497 // Invoke runtime. 498 address jrt_address = nullptr; 499 500 if (is_strong) { 501 if (is_narrow) { 502 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow); 503 } else { 504 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); 505 } 506 } else if (is_weak) { 507 if (is_narrow) { 508 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow); 509 } else { 510 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak); 511 } 512 } else { 513 assert(is_phantom, "only remaining strength"); 514 assert(!is_narrow, "phantom access cannot be narrow"); 515 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom); 516 } 517 assert(jrt_address != nullptr, "jrt routine cannot be found"); 518 519 __ call_VM_leaf(jrt_address, dst /* reference */, R4_ARG2 /* reference address */); 520 521 // Restore to-be-preserved registers. 522 if (preserve_gp_registers) { 523 __ mr(R0, R3_RET); 524 } else { 525 __ mr_if_needed(dst, R3_RET); 526 } 527 528 if (needs_frame) { 529 __ pop_frame(); 530 __ restore_LR_CR(tmp1); 531 532 if (preserve_gp_registers) { 533 __ restore_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers); 534 __ mr(dst, R0); 535 } 536 } 537 538 __ bind(skip_barrier); 539 } 540 541 // base: Base register of the reference's address. 542 // ind_or_offs: Index or offset of the reference's address. 543 // L_handle_null: An optional label that will be jumped to if the reference is null. 544 void ShenandoahBarrierSetAssembler::load_at( 545 MacroAssembler *masm, DecoratorSet decorators, BasicType type, 546 Register base, RegisterOrConstant ind_or_offs, Register dst, 547 Register tmp1, Register tmp2, 548 MacroAssembler::PreservationLevel preservation_level, Label *L_handle_null) { 549 // Register must not clash, except 'base' and 'dst'. 550 if (ind_or_offs.is_register()) { 551 if (base != noreg) { 552 assert_different_registers(tmp1, tmp2, base, ind_or_offs.register_or_noreg(), R0, noreg); 553 } 554 assert_different_registers(tmp1, tmp2, dst, ind_or_offs.register_or_noreg(), R0, noreg); 555 } else { 556 if (base == noreg) { 557 assert_different_registers(tmp1, tmp2, base, R0, noreg); 558 } 559 assert_different_registers(tmp1, tmp2, dst, R0, noreg); 560 } 561 562 /* ==== Apply load barrier, if required ==== */ 563 if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) { 564 assert(is_reference_type(type), "need_load_reference_barrier must check whether type is a reference type"); 565 566 // If 'dst' clashes with either 'base' or 'ind_or_offs', use an intermediate result register 567 // to keep the values of those alive until the load reference barrier is applied. 568 Register intermediate_dst = (dst == base || (ind_or_offs.is_register() && dst == ind_or_offs.as_register())) 569 ? tmp2 570 : dst; 571 572 BarrierSetAssembler::load_at(masm, decorators, type, 573 base, ind_or_offs, 574 intermediate_dst, 575 tmp1, noreg, 576 preservation_level, L_handle_null); 577 578 load_reference_barrier(masm, decorators, 579 base, ind_or_offs, 580 intermediate_dst, 581 tmp1, R0, 582 preservation_level); 583 584 __ mr_if_needed(dst, intermediate_dst); 585 } else { 586 BarrierSetAssembler::load_at(masm, decorators, type, 587 base, ind_or_offs, 588 dst, 589 tmp1, tmp2, 590 preservation_level, L_handle_null); 591 } 592 593 /* ==== Apply keep-alive barrier, if required (e.g., to inhibit weak reference resurrection) ==== */ 594 if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { 595 iu_barrier(masm, dst, tmp1, tmp2, preservation_level); 596 } 597 } 598 599 void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register base, RegisterOrConstant ind_or_offs, Register tmp) { 600 assert(ShenandoahCardBarrier, "Should have been checked by caller"); 601 602 ShenandoahBarrierSet* ctbs = ShenandoahBarrierSet::barrier_set(); 603 CardTable* ct = ctbs->card_table(); 604 assert_different_registers(base, tmp, R0); 605 606 if (ind_or_offs.is_constant()) { 607 __ add_const_optimized(base, base, ind_or_offs.as_constant(), tmp); 608 } else { 609 __ add(base, ind_or_offs.as_register(), base); 610 } 611 612 __ load_const_optimized(tmp, (address)ct->byte_map_base(), R0); 613 __ srdi(base, base, CardTable::card_shift()); 614 __ li(R0, CardTable::dirty_card_val()); 615 __ stbx(R0, tmp, base); 616 } 617 618 // base: Base register of the reference's address. 619 // ind_or_offs: Index or offset of the reference's address. 620 // val: To-be-stored value/reference's new value. 621 void ShenandoahBarrierSetAssembler::store_at(MacroAssembler *masm, DecoratorSet decorators, BasicType type, 622 Register base, RegisterOrConstant ind_or_offs, Register val, 623 Register tmp1, Register tmp2, Register tmp3, 624 MacroAssembler::PreservationLevel preservation_level) { 625 if (is_reference_type(type)) { 626 if (ShenandoahSATBBarrier) { 627 satb_write_barrier(masm, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); 628 } 629 630 if (ShenandoahIUBarrier && val != noreg) { 631 iu_barrier(masm, val, tmp1, tmp2, preservation_level, decorators); 632 } 633 } 634 635 BarrierSetAssembler::store_at(masm, decorators, type, 636 base, ind_or_offs, 637 val, 638 tmp1, tmp2, tmp3, 639 preservation_level); 640 641 // No need for post barrier if storing NULL 642 if (ShenandoahCardBarrier && is_reference_type(type) && val != noreg) { 643 store_check(masm, base, ind_or_offs, tmp1); 644 } 645 } 646 647 void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler *masm, 648 Register dst, Register jni_env, Register obj, 649 Register tmp, Label &slowpath) { 650 __ block_comment("try_resolve_jobject_in_native (shenandoahgc) {"); 651 652 assert_different_registers(jni_env, obj, tmp); 653 654 Label done; 655 656 // Fast path: Reference is null (JNI tags are zero for null pointers). 657 __ cmpdi(CCR0, obj, 0); 658 __ beq(CCR0, done); 659 660 // Resolve jobject using standard implementation. 661 BarrierSetAssembler::try_resolve_jobject_in_native(masm, dst, jni_env, obj, tmp, slowpath); 662 663 // Check whether heap is stable. 664 __ lbz(tmp, 665 in_bytes(ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset()), 666 jni_env); 667 668 __ andi_(tmp, tmp, ShenandoahHeap::EVACUATION | ShenandoahHeap::HAS_FORWARDED); 669 __ bne(CCR0, slowpath); 670 671 __ bind(done); 672 __ block_comment("} try_resolve_jobject_in_native (shenandoahgc)"); 673 } 674 675 // Special shenandoah CAS implementation that handles false negatives due 676 // to concurrent evacuation. That is, the CAS operation is intended to succeed in 677 // the following scenarios (success criteria): 678 // s1) The reference pointer ('base_addr') equals the expected ('expected') pointer. 679 // s2) The reference pointer refers to the from-space version of an already-evacuated 680 // object, whereas the expected pointer refers to the to-space version of the same object. 681 // Situations in which the reference pointer refers to the to-space version of an object 682 // and the expected pointer refers to the from-space version of the same object can not occur due to 683 // shenandoah's strong to-space invariant. This also implies that the reference stored in 'new_val' 684 // can not refer to the from-space version of an already-evacuated object. 685 // 686 // To guarantee correct behavior in concurrent environments, two races must be addressed: 687 // r1) A concurrent thread may heal the reference pointer (i.e., it is no longer referring to the 688 // from-space version but to the to-space version of the object in question). 689 // In this case, the CAS operation should succeed. 690 // r2) A concurrent thread may mutate the reference (i.e., the reference pointer refers to an entirely different object). 691 // In this case, the CAS operation should fail. 692 // 693 // By default, the value held in the 'result' register is zero to indicate failure of CAS, 694 // non-zero to indicate success. If 'is_cae' is set, the result is the most recently fetched 695 // value from 'base_addr' rather than a boolean success indicator. 696 void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler *masm, Register base_addr, 697 Register expected, Register new_val, Register tmp1, Register tmp2, 698 bool is_cae, Register result) { 699 __ block_comment("cmpxchg_oop (shenandoahgc) {"); 700 701 assert_different_registers(base_addr, new_val, tmp1, tmp2, result, R0); 702 assert_different_registers(base_addr, expected, tmp1, tmp2, result, R0); 703 704 // Potential clash of 'success_flag' and 'tmp' is being accounted for. 705 Register success_flag = is_cae ? noreg : result, 706 current_value = is_cae ? result : tmp1, 707 tmp = is_cae ? tmp1 : result, 708 initial_value = tmp2; 709 710 Label done, step_four; 711 712 __ bind(step_four); 713 714 /* ==== Step 1 ("Standard" CAS) ==== */ 715 // Fast path: The values stored in 'expected' and 'base_addr' are equal. 716 // Given that 'expected' must refer to the to-space object of an evacuated object (strong to-space invariant), 717 // no special processing is required. 718 if (UseCompressedOops) { 719 __ cmpxchgw(CCR0, current_value, expected, new_val, base_addr, MacroAssembler::MemBarNone, 720 false, success_flag, true); 721 } else { 722 __ cmpxchgd(CCR0, current_value, expected, new_val, base_addr, MacroAssembler::MemBarNone, 723 false, success_flag, nullptr, true); 724 } 725 726 // Skip the rest of the barrier if the CAS operation succeeds immediately. 727 // If it does not, the value stored at the address is either the from-space pointer of the 728 // referenced object (success criteria s2)) or simply another object. 729 __ beq(CCR0, done); 730 731 /* ==== Step 2 (Null check) ==== */ 732 // The success criteria s2) cannot be matched with a null pointer 733 // (null pointers cannot be subject to concurrent evacuation). The failure of the CAS operation is thus legitimate. 734 __ cmpdi(CCR0, current_value, 0); 735 __ beq(CCR0, done); 736 737 /* ==== Step 3 (reference pointer refers to from-space version; success criteria s2)) ==== */ 738 // To check whether the reference pointer refers to the from-space version, the forward 739 // pointer of the object referred to by the reference is resolved and compared against the expected pointer. 740 // If this check succeed, another CAS operation is issued with the from-space pointer being the expected pointer. 741 // 742 // Save the potential from-space pointer. 743 __ mr(initial_value, current_value); 744 745 // Resolve forward pointer. 746 if (UseCompressedOops) { __ decode_heap_oop_not_null(current_value); } 747 resolve_forward_pointer_not_null(masm, current_value, tmp); 748 if (UseCompressedOops) { __ encode_heap_oop_not_null(current_value); } 749 750 if (!is_cae) { 751 // 'success_flag' was overwritten by call to 'resovle_forward_pointer_not_null'. 752 // Load zero into register for the potential failure case. 753 __ li(success_flag, 0); 754 } 755 __ cmpd(CCR0, current_value, expected); 756 __ bne(CCR0, done); 757 758 // Discard fetched value as it might be a reference to the from-space version of an object. 759 if (UseCompressedOops) { 760 __ cmpxchgw(CCR0, R0, initial_value, new_val, base_addr, MacroAssembler::MemBarNone, 761 false, success_flag); 762 } else { 763 __ cmpxchgd(CCR0, R0, initial_value, new_val, base_addr, MacroAssembler::MemBarNone, 764 false, success_flag); 765 } 766 767 /* ==== Step 4 (Retry CAS with to-space pointer (success criteria s2) under race r1)) ==== */ 768 // The reference pointer could have been healed whilst the previous CAS operation was being performed. 769 // Another CAS operation must thus be issued with the to-space pointer being the expected pointer. 770 // If that CAS operation fails as well, race r2) must have occurred, indicating that 771 // the operation failure is legitimate. 772 // 773 // To keep the code's size small and thus improving cache (icache) performance, this highly 774 // unlikely case should be handled by the smallest possible code. Instead of emitting a third, 775 // explicit CAS operation, the code jumps back and reuses the first CAS operation (step 1) 776 // (passed arguments are identical). 777 // 778 // A failure of the CAS operation in step 1 would imply that the overall CAS operation is supposed 779 // to fail. Jumping back to step 1 requires, however, that step 2 and step 3 are re-executed as well. 780 // It is thus important to ensure that a re-execution of those steps does not put program correctness 781 // at risk: 782 // - Step 2: Either terminates in failure (desired result) or falls through to step 3. 783 // - Step 3: Terminates if the comparison between the forwarded, fetched pointer and the expected value 784 // fails. Unless the reference has been updated in the meanwhile once again, this is 785 // guaranteed to be the case. 786 // In case of a concurrent update, the CAS would be retried again. This is legitimate 787 // in terms of program correctness (even though it is not desired). 788 __ bne(CCR0, step_four); 789 790 __ bind(done); 791 __ block_comment("} cmpxchg_oop (shenandoahgc)"); 792 } 793 794 void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, 795 Register addr, Register count, Register preserve) { 796 assert(ShenandoahCardBarrier, "Should have been checked by caller"); 797 798 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); 799 CardTable* ct = bs->card_table(); 800 assert_different_registers(addr, count, R0); 801 802 Label L_skip_loop, L_store_loop; 803 804 __ sldi_(count, count, LogBytesPerHeapOop); 805 806 // Zero length? Skip. 807 __ beq(CCR0, L_skip_loop); 808 809 __ addi(count, count, -BytesPerHeapOop); 810 __ add(count, addr, count); 811 // Use two shifts to clear out those low order two bits! (Cannot opt. into 1.) 812 __ srdi(addr, addr, CardTable::card_shift()); 813 __ srdi(count, count, CardTable::card_shift()); 814 __ subf(count, addr, count); 815 __ add_const_optimized(addr, addr, (address)ct->byte_map_base(), R0); 816 __ addi(count, count, 1); 817 __ li(R0, 0); 818 __ mtctr(count); 819 820 // Byte store loop 821 __ bind(L_store_loop); 822 __ stb(R0, 0, addr); 823 __ addi(addr, addr, 1); 824 __ bdnz(L_store_loop); 825 __ bind(L_skip_loop); 826 } 827 828 #undef __ 829 830 #ifdef COMPILER1 831 832 #define __ ce->masm()-> 833 834 void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler *ce, ShenandoahPreBarrierStub *stub) { 835 __ block_comment("gen_pre_barrier_stub (shenandoahgc) {"); 836 837 ShenandoahBarrierSetC1 *bs = (ShenandoahBarrierSetC1*) BarrierSet::barrier_set()->barrier_set_c1(); 838 __ bind(*stub->entry()); 839 840 // GC status has already been verified by 'ShenandoahBarrierSetC1::pre_barrier'. 841 // This stub is the slowpath of that function. 842 843 assert(stub->pre_val()->is_register(), "pre_val must be a register"); 844 Register pre_val = stub->pre_val()->as_register(); 845 846 // If 'do_load()' returns false, the to-be-stored value is already available in 'stub->pre_val()' 847 // ("preloaded mode" of the store barrier). 848 if (stub->do_load()) { 849 ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false); 850 } 851 852 // Fast path: Reference is null. 853 __ cmpdi(CCR0, pre_val, 0); 854 __ bc_far_optimized(Assembler::bcondCRbiIs1_bhintNoHint, __ bi0(CCR0, Assembler::equal), *stub->continuation()); 855 856 // Argument passing via the stack. 857 __ std(pre_val, -8, R1_SP); 858 859 __ load_const_optimized(R0, bs->pre_barrier_c1_runtime_code_blob()->code_begin()); 860 __ call_stub(R0); 861 862 __ b(*stub->continuation()); 863 __ block_comment("} gen_pre_barrier_stub (shenandoahgc)"); 864 } 865 866 void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assembler *ce, 867 ShenandoahLoadReferenceBarrierStub *stub) { 868 __ block_comment("gen_load_reference_barrier_stub (shenandoahgc) {"); 869 870 ShenandoahBarrierSetC1 *bs = (ShenandoahBarrierSetC1*) BarrierSet::barrier_set()->barrier_set_c1(); 871 __ bind(*stub->entry()); 872 873 Register obj = stub->obj()->as_register(); 874 Register res = stub->result()->as_register(); 875 Register addr = stub->addr()->as_pointer_register(); 876 Register tmp1 = stub->tmp1()->as_register(); 877 Register tmp2 = stub->tmp2()->as_register(); 878 assert_different_registers(addr, res, tmp1, tmp2); 879 880 #ifdef ASSERT 881 // Ensure that 'res' is 'R3_ARG1' and contains the same value as 'obj' to reduce the number of required 882 // copy instructions. 883 assert(R3_RET == res, "res must be r3"); 884 __ cmpd(CCR0, res, obj); 885 __ asm_assert_eq("result register must contain the reference stored in obj"); 886 #endif 887 888 DecoratorSet decorators = stub->decorators(); 889 890 /* ==== Check whether region is in collection set ==== */ 891 // GC status (unstable) has already been verified by 'ShenandoahBarrierSetC1::load_reference_barrier_impl'. 892 // This stub is the slowpath of that function. 893 894 bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); 895 bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); 896 bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); 897 bool is_native = ShenandoahBarrierSet::is_native_access(decorators); 898 899 if (is_strong) { 900 // Check whether object is in collection set. 901 __ load_const_optimized(tmp2, ShenandoahHeap::in_cset_fast_test_addr(), tmp1); 902 __ srdi(tmp1, obj, ShenandoahHeapRegion::region_size_bytes_shift_jint()); 903 __ lbzx(tmp2, tmp1, tmp2); 904 905 __ andi_(tmp2, tmp2, 1); 906 __ bc_far_optimized(Assembler::bcondCRbiIs1_bhintNoHint, __ bi0(CCR0, Assembler::equal), *stub->continuation()); 907 } 908 909 address blob_addr = nullptr; 910 911 if (is_strong) { 912 if (is_native) { 913 blob_addr = bs->load_reference_barrier_strong_native_rt_code_blob()->code_begin(); 914 } else { 915 blob_addr = bs->load_reference_barrier_strong_rt_code_blob()->code_begin(); 916 } 917 } else if (is_weak) { 918 blob_addr = bs->load_reference_barrier_weak_rt_code_blob()->code_begin(); 919 } else { 920 assert(is_phantom, "only remaining strength"); 921 blob_addr = bs->load_reference_barrier_phantom_rt_code_blob()->code_begin(); 922 } 923 924 assert(blob_addr != nullptr, "code blob cannot be found"); 925 926 // Argument passing via the stack. 'obj' is passed implicitly (as asserted above). 927 __ std(addr, -8, R1_SP); 928 929 __ load_const_optimized(tmp1, blob_addr, tmp2); 930 __ call_stub(tmp1); 931 932 // 'res' is 'R3_RET'. The result is thus already in the correct register. 933 934 __ b(*stub->continuation()); 935 __ block_comment("} gen_load_reference_barrier_stub (shenandoahgc)"); 936 } 937 938 #undef __ 939 940 #define __ sasm-> 941 942 void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler *sasm) { 943 __ block_comment("generate_c1_pre_barrier_runtime_stub (shenandoahgc) {"); 944 945 Label runtime, skip_barrier; 946 BarrierSet *bs = BarrierSet::barrier_set(); 947 948 // Argument passing via the stack. 949 const int caller_stack_slots = 3; 950 951 Register R0_pre_val = R0; 952 __ ld(R0, -8, R1_SP); 953 Register R11_tmp1 = R11_scratch1; 954 __ std(R11_tmp1, -16, R1_SP); 955 Register R12_tmp2 = R12_scratch2; 956 __ std(R12_tmp2, -24, R1_SP); 957 958 /* ==== Check whether marking is active ==== */ 959 // Even though gc status was checked in 'ShenandoahBarrierSetAssembler::gen_pre_barrier_stub', 960 // another check is required as a safepoint might have been reached in the meantime (JDK-8140588). 961 __ lbz(R12_tmp2, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), R16_thread); 962 963 __ andi_(R12_tmp2, R12_tmp2, ShenandoahHeap::MARKING); 964 __ beq(CCR0, skip_barrier); 965 966 /* ==== Add previous value directly to thread-local SATB mark queue ==== */ 967 // Check queue's capacity. Jump to runtime if no free slot is available. 968 __ ld(R12_tmp2, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread); 969 __ cmpdi(CCR0, R12_tmp2, 0); 970 __ beq(CCR0, runtime); 971 972 // Capacity suffices. Decrement the queue's size by one slot (size of one oop). 973 __ addi(R12_tmp2, R12_tmp2, -wordSize); 974 __ std(R12_tmp2, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread); 975 976 // Enqueue the previous value and skip the runtime invocation. 977 __ ld(R11_tmp1, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()), R16_thread); 978 __ stdx(R0_pre_val, R11_tmp1, R12_tmp2); 979 __ b(skip_barrier); 980 981 __ bind(runtime); 982 983 /* ==== Invoke runtime to commit SATB mark queue to gc and allocate a new buffer ==== */ 984 // Save to-be-preserved registers. 985 const int nbytes_save = (MacroAssembler::num_volatile_regs + caller_stack_slots) * BytesPerWord; 986 __ save_volatile_gprs(R1_SP, -nbytes_save); 987 __ save_LR_CR(R11_tmp1); 988 __ push_frame_reg_args(nbytes_save, R11_tmp1); 989 990 // Invoke runtime. 991 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), R0_pre_val, R16_thread); 992 993 // Restore to-be-preserved registers. 994 __ pop_frame(); 995 __ restore_LR_CR(R11_tmp1); 996 __ restore_volatile_gprs(R1_SP, -nbytes_save); 997 998 __ bind(skip_barrier); 999 1000 // Restore spilled registers. 1001 __ ld(R11_tmp1, -16, R1_SP); 1002 __ ld(R12_tmp2, -24, R1_SP); 1003 1004 __ blr(); 1005 __ block_comment("} generate_c1_pre_barrier_runtime_stub (shenandoahgc)"); 1006 } 1007 1008 void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler *sasm, 1009 DecoratorSet decorators) { 1010 __ block_comment("generate_c1_load_reference_barrier_runtime_stub (shenandoahgc) {"); 1011 1012 // Argument passing via the stack. 1013 const int caller_stack_slots = 1; 1014 1015 // Save to-be-preserved registers. 1016 const int nbytes_save = (MacroAssembler::num_volatile_regs - 1 // 'R3_ARG1' is skipped 1017 + caller_stack_slots) * BytesPerWord; 1018 __ save_volatile_gprs(R1_SP, -nbytes_save, true, false); 1019 1020 // Load arguments from stack. 1021 // No load required, as assured by assertions in 'ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub'. 1022 Register R3_obj = R3_ARG1; 1023 Register R4_load_addr = R4_ARG2; 1024 __ ld(R4_load_addr, -8, R1_SP); 1025 1026 Register R11_tmp = R11_scratch1; 1027 1028 /* ==== Invoke runtime ==== */ 1029 bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); 1030 bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); 1031 bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); 1032 bool is_native = ShenandoahBarrierSet::is_native_access(decorators); 1033 1034 address jrt_address = nullptr; 1035 1036 if (is_strong) { 1037 if (is_native) { 1038 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); 1039 } else { 1040 if (UseCompressedOops) { 1041 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow); 1042 } else { 1043 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); 1044 } 1045 } 1046 } else if (is_weak) { 1047 assert(!is_native, "weak load reference barrier must not be called off-heap"); 1048 if (UseCompressedOops) { 1049 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow); 1050 } else { 1051 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak); 1052 } 1053 } else { 1054 assert(is_phantom, "reference type must be phantom"); 1055 assert(is_native, "phantom load reference barrier must be called off-heap"); 1056 jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom); 1057 } 1058 assert(jrt_address != nullptr, "load reference barrier runtime routine cannot be found"); 1059 1060 __ save_LR_CR(R11_tmp); 1061 __ push_frame_reg_args(nbytes_save, R11_tmp); 1062 1063 // Invoke runtime. Arguments are already stored in the corresponding registers. 1064 __ call_VM_leaf(jrt_address, R3_obj, R4_load_addr); 1065 1066 // Restore to-be-preserved registers. 1067 __ pop_frame(); 1068 __ restore_LR_CR(R11_tmp); 1069 __ restore_volatile_gprs(R1_SP, -nbytes_save, true, false); // Skip 'R3_RET' register. 1070 1071 __ blr(); 1072 __ block_comment("} generate_c1_load_reference_barrier_runtime_stub (shenandoahgc)"); 1073 } 1074 1075 #undef __ 1076 1077 #endif // COMPILER1