1 /* 2 * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "asm/macroAssembler.inline.hpp" 26 #include "gc/g1/g1BarrierSet.hpp" 27 #include "gc/g1/g1BarrierSetAssembler.hpp" 28 #include "gc/g1/g1BarrierSetRuntime.hpp" 29 #include "gc/g1/g1CardTable.hpp" 30 #include "gc/g1/g1HeapRegion.hpp" 31 #include "gc/g1/g1ThreadLocalData.hpp" 32 #include "gc/shared/collectedHeap.hpp" 33 #include "interpreter/interp_masm.hpp" 34 #include "runtime/javaThread.hpp" 35 #include "runtime/sharedRuntime.hpp" 36 #ifdef COMPILER1 37 #include "c1/c1_LIRAssembler.hpp" 38 #include "c1/c1_MacroAssembler.hpp" 39 #include "gc/g1/c1/g1BarrierSetC1.hpp" 40 #endif // COMPILER1 41 #ifdef COMPILER2 42 #include "gc/g1/c2/g1BarrierSetC2.hpp" 43 #endif // COMPILER2 44 45 #define __ masm-> 46 47 void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, 48 Register addr, Register count, RegSet saved_regs) { 49 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; 50 if (!dest_uninitialized) { 51 Label done; 52 Address in_progress(rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); 53 54 // Is marking active? 55 if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { 56 __ ldrw(rscratch1, in_progress); 57 } else { 58 assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); 59 __ ldrb(rscratch1, in_progress); 60 } 61 __ cbzw(rscratch1, done); 62 63 __ push(saved_regs, sp); 64 if (count == c_rarg0) { 65 if (addr == c_rarg1) { 66 // exactly backwards!! 67 __ mov(rscratch1, c_rarg0); 68 __ mov(c_rarg0, c_rarg1); 69 __ mov(c_rarg1, rscratch1); 70 } else { 71 __ mov(c_rarg1, count); 72 __ mov(c_rarg0, addr); 73 } 74 } else { 75 __ mov(c_rarg0, addr); 76 __ mov(c_rarg1, count); 77 } 78 if (UseCompressedOops) { 79 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_narrow_oop_entry), 2); 80 } else { 81 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), 2); 82 } 83 __ pop(saved_regs, sp); 84 85 __ bind(done); 86 } 87 } 88 89 void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, 90 Register start, Register count, Register scratch, RegSet saved_regs) { 91 __ push(saved_regs, sp); 92 assert_different_registers(start, count, scratch); 93 assert_different_registers(c_rarg0, count); 94 __ mov(c_rarg0, start); 95 __ mov(c_rarg1, count); 96 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2); 97 __ pop(saved_regs, sp); 98 } 99 100 static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, 101 const Register thread, const Register value, const Register temp1, const Register temp2) { 102 // Can we store a value in the given thread's buffer? 103 // (The index field is typed as size_t.) 104 __ ldr(temp1, Address(thread, in_bytes(index_offset))); // temp1 := *(index address) 105 __ cbz(temp1, runtime); // jump to runtime if index == 0 (full buffer) 106 // The buffer is not full, store value into it. 107 __ sub(temp1, temp1, wordSize); // temp1 := next index 108 __ str(temp1, Address(thread, in_bytes(index_offset))); // *(index address) := next index 109 __ ldr(temp2, Address(thread, in_bytes(buffer_offset))); // temp2 := buffer address 110 __ str(value, Address(temp2, temp1)); // *(buffer address + next index) := value 111 } 112 113 static void generate_pre_barrier_fast_path(MacroAssembler* masm, 114 const Register thread, 115 const Register tmp1) { 116 Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); 117 // Is marking active? 118 if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { 119 __ ldrw(tmp1, in_progress); 120 } else { 121 assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); 122 __ ldrb(tmp1, in_progress); 123 } 124 } 125 126 static void generate_pre_barrier_slow_path(MacroAssembler* masm, 127 const Register obj, 128 const Register pre_val, 129 const Register thread, 130 const Register tmp1, 131 const Register tmp2, 132 Label& done, 133 Label& runtime) { 134 // Do we need to load the previous value? 135 if (obj != noreg) { 136 __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); 137 } 138 // Is the previous value null? 139 __ cbz(pre_val, done); 140 generate_queue_test_and_insertion(masm, 141 G1ThreadLocalData::satb_mark_queue_index_offset(), 142 G1ThreadLocalData::satb_mark_queue_buffer_offset(), 143 runtime, 144 thread, pre_val, tmp1, tmp2); 145 __ b(done); 146 } 147 148 void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, 149 Register obj, 150 Register pre_val, 151 Register thread, 152 Register tmp1, 153 Register tmp2, 154 bool tosca_live, 155 bool expand_call) { 156 // If expand_call is true then we expand the call_VM_leaf macro 157 // directly to skip generating the check by 158 // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. 159 160 assert(thread == rthread, "must be"); 161 162 Label done; 163 Label runtime; 164 165 assert_different_registers(obj, pre_val, tmp1, tmp2); 166 assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); 167 168 generate_pre_barrier_fast_path(masm, thread, tmp1); 169 // If marking is not active (*(mark queue active address) == 0), jump to done 170 __ cbzw(tmp1, done); 171 generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, done, runtime); 172 173 __ bind(runtime); 174 175 // save the live input values 176 RegSet saved = RegSet::of(pre_val); 177 FloatRegSet fsaved; 178 179 // Barriers might be emitted when converting between (scalarized) calling 180 // conventions for inline types. Save all argument registers before calling 181 // into the runtime. 182 if (EnableValhalla && InlineTypePassFieldsAsArgs) { 183 if (tosca_live) saved += RegSet::of(r0); 184 if (obj != noreg) saved += RegSet::of(obj); 185 saved += RegSet::of(j_rarg0, j_rarg1, j_rarg2, j_rarg3); 186 saved += RegSet::of(j_rarg4, j_rarg5, j_rarg6, j_rarg7); 187 188 fsaved += FloatRegSet::of(j_farg0, j_farg1, j_farg2, j_farg3); 189 fsaved += FloatRegSet::of(j_farg4, j_farg5, j_farg6, j_farg7); 190 191 __ push(saved, sp); 192 __ push_fp(fsaved, sp); 193 } else { 194 __ push_call_clobbered_registers(); 195 } 196 197 // Calling the runtime using the regular call_VM_leaf mechanism generates 198 // code (generated by InterpreterMacroAssember::call_VM_leaf_base) 199 // that checks that the *(rfp+frame::interpreter_frame_last_sp) == nullptr. 200 // 201 // If we care generating the pre-barrier without a frame (e.g. in the 202 // intrinsified Reference.get() routine) then rfp might be pointing to 203 // the caller frame and so this check will most likely fail at runtime. 204 // 205 // Expanding the call directly bypasses the generation of the check. 206 // So when we do not have have a full interpreter frame on the stack 207 // expand_call should be passed true. 208 209 if (expand_call) { 210 assert(pre_val != c_rarg1, "smashed arg"); 211 __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); 212 } else { 213 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); 214 } 215 216 if (EnableValhalla && InlineTypePassFieldsAsArgs) { 217 __ pop_fp(fsaved, sp); 218 __ pop(saved, sp); 219 } else { 220 __ pop_call_clobbered_registers(); 221 } 222 223 __ bind(done); 224 225 } 226 227 static void generate_post_barrier_fast_path(MacroAssembler* masm, 228 const Register store_addr, 229 const Register new_val, 230 const Register tmp1, 231 const Register tmp2, 232 Label& done, 233 bool new_val_may_be_null) { 234 // Does store cross heap regions? 235 __ eor(tmp1, store_addr, new_val); // tmp1 := store address ^ new value 236 __ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes) 237 __ cbz(tmp1, done); 238 // Crosses regions, storing null? 239 if (new_val_may_be_null) { 240 __ cbz(new_val, done); 241 } 242 // Storing region crossing non-null, is card young? 243 __ lsr(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base 244 __ load_byte_map_base(tmp2); // tmp2 := card table base address 245 __ add(tmp1, tmp1, tmp2); // tmp1 := card address 246 __ ldrb(tmp2, Address(tmp1)); // tmp2 := card 247 __ cmpw(tmp2, (int)G1CardTable::g1_young_card_val()); // tmp2 := card == young_card_val? 248 } 249 250 static void generate_post_barrier_slow_path(MacroAssembler* masm, 251 const Register thread, 252 const Register tmp1, 253 const Register tmp2, 254 Label& done, 255 Label& runtime) { 256 __ membar(Assembler::StoreLoad); // StoreLoad membar 257 __ ldrb(tmp2, Address(tmp1)); // tmp2 := card 258 __ cbzw(tmp2, done); 259 // Storing a region crossing, non-null oop, card is clean. 260 // Dirty card and log. 261 STATIC_ASSERT(CardTable::dirty_card_val() == 0); 262 __ strb(zr, Address(tmp1)); // *(card address) := dirty_card_val 263 generate_queue_test_and_insertion(masm, 264 G1ThreadLocalData::dirty_card_queue_index_offset(), 265 G1ThreadLocalData::dirty_card_queue_buffer_offset(), 266 runtime, 267 thread, tmp1, tmp2, rscratch1); 268 __ b(done); 269 } 270 271 void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, 272 Register store_addr, 273 Register new_val, 274 Register thread, 275 Register tmp1, 276 Register tmp2) { 277 assert(thread == rthread, "must be"); 278 assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, 279 rscratch1); 280 assert(store_addr != noreg && new_val != noreg && tmp1 != noreg 281 && tmp2 != noreg, "expecting a register"); 282 283 Label done; 284 Label runtime; 285 286 generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */); 287 // If card is young, jump to done 288 __ br(Assembler::EQ, done); 289 generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime); 290 291 __ bind(runtime); 292 293 // save the live input values 294 RegSet saved = RegSet::of(store_addr); 295 FloatRegSet fsaved; 296 297 // Barriers might be emitted when converting between (scalarized) calling 298 // conventions for inline types. Save all argument registers before calling 299 // into the runtime. 300 if (EnableValhalla && InlineTypePassFieldsAsArgs) { 301 saved += RegSet::of(j_rarg0, j_rarg1, j_rarg2, j_rarg3); 302 saved += RegSet::of(j_rarg4, j_rarg5, j_rarg6, j_rarg7); 303 304 fsaved += FloatRegSet::of(j_farg0, j_farg1, j_farg2, j_farg3); 305 fsaved += FloatRegSet::of(j_farg4, j_farg5, j_farg6, j_farg7); 306 } 307 308 __ push(saved, sp); 309 __ push_fp(fsaved, sp); 310 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread); 311 __ pop_fp(fsaved, sp); 312 __ pop(saved, sp); 313 314 __ bind(done); 315 } 316 317 #if defined(COMPILER2) 318 319 static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { 320 SaveLiveRegisters save_registers(masm, stub); 321 if (c_rarg0 != arg) { 322 __ mov(c_rarg0, arg); 323 } 324 __ mov(c_rarg1, rthread); 325 __ mov(rscratch1, runtime_path); 326 __ blr(rscratch1); 327 } 328 329 void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, 330 Register obj, 331 Register pre_val, 332 Register thread, 333 Register tmp1, 334 Register tmp2, 335 G1PreBarrierStubC2* stub) { 336 assert(thread == rthread, "must be"); 337 assert_different_registers(obj, pre_val, tmp1, tmp2); 338 assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); 339 340 stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2); 341 342 generate_pre_barrier_fast_path(masm, thread, tmp1); 343 // If marking is active (*(mark queue active address) != 0), jump to stub (slow path) 344 __ cbnzw(tmp1, *stub->entry()); 345 346 __ bind(*stub->continuation()); 347 } 348 349 void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, 350 G1PreBarrierStubC2* stub) const { 351 Assembler::InlineSkippedInstructionsCounter skip_counter(masm); 352 Label runtime; 353 Register obj = stub->obj(); 354 Register pre_val = stub->pre_val(); 355 Register thread = stub->thread(); 356 Register tmp1 = stub->tmp1(); 357 Register tmp2 = stub->tmp2(); 358 359 __ bind(*stub->entry()); 360 generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, *stub->continuation(), runtime); 361 362 __ bind(runtime); 363 generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); 364 __ b(*stub->continuation()); 365 } 366 367 void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, 368 Register store_addr, 369 Register new_val, 370 Register thread, 371 Register tmp1, 372 Register tmp2, 373 G1PostBarrierStubC2* stub) { 374 assert(thread == rthread, "must be"); 375 assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, 376 rscratch1); 377 assert(store_addr != noreg && new_val != noreg && tmp1 != noreg 378 && tmp2 != noreg, "expecting a register"); 379 380 stub->initialize_registers(thread, tmp1, tmp2); 381 382 bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; 383 generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null); 384 // If card is not young, jump to stub (slow path) 385 __ br(Assembler::NE, *stub->entry()); 386 387 __ bind(*stub->continuation()); 388 } 389 390 void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, 391 G1PostBarrierStubC2* stub) const { 392 Assembler::InlineSkippedInstructionsCounter skip_counter(masm); 393 Label runtime; 394 Register thread = stub->thread(); 395 Register tmp1 = stub->tmp1(); // tmp1 holds the card address. 396 Register tmp2 = stub->tmp2(); 397 assert(stub->tmp3() == noreg, "not needed in this platform"); 398 399 __ bind(*stub->entry()); 400 generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime); 401 402 __ bind(runtime); 403 generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); 404 __ b(*stub->continuation()); 405 } 406 407 #endif // COMPILER2 408 409 void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, 410 Register dst, Address src, Register tmp1, Register tmp2) { 411 bool on_oop = is_reference_type(type); 412 bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; 413 bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; 414 bool on_reference = on_weak || on_phantom; 415 ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2); 416 if (on_oop && on_reference) { 417 // LR is live. It must be saved around calls. 418 __ enter(/*strip_ret_addr*/true); // barrier may call runtime 419 // Generate the G1 pre-barrier code to log the value of 420 // the referent field in an SATB buffer. 421 g1_write_barrier_pre(masm /* masm */, 422 noreg /* obj */, 423 dst /* pre_val */, 424 rthread /* thread */, 425 tmp1 /* tmp1 */, 426 tmp2 /* tmp2 */, 427 true /* tosca_live */, 428 true /* expand_call */); 429 __ leave(); 430 } 431 } 432 433 void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, 434 Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { 435 436 bool in_heap = (decorators & IN_HEAP) != 0; 437 bool as_normal = (decorators & AS_NORMAL) != 0; 438 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; 439 440 bool needs_pre_barrier = as_normal && !dest_uninitialized; 441 bool needs_post_barrier = (val != noreg && in_heap); 442 443 assert_different_registers(val, tmp1, tmp2, tmp3); 444 445 // flatten object address if needed 446 if (dst.index() == noreg && dst.offset() == 0) { 447 if (dst.base() != tmp3) { 448 __ mov(tmp3, dst.base()); 449 } 450 } else { 451 __ lea(tmp3, dst); 452 } 453 454 if (needs_pre_barrier) { 455 g1_write_barrier_pre(masm, 456 tmp3 /* obj */, 457 tmp2 /* pre_val */, 458 rthread /* thread */, 459 tmp1 /* tmp1 */, 460 rscratch2 /* tmp2 */, 461 val != noreg /* tosca_live */, 462 false /* expand_call */); 463 } 464 465 if (val == noreg) { 466 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), noreg, noreg, noreg, noreg); 467 } else { 468 // G1 barrier needs uncompressed oop for region cross check. 469 Register new_val = val; 470 if (needs_post_barrier) { 471 if (UseCompressedOops) { 472 new_val = rscratch2; 473 __ mov(new_val, val); 474 } 475 } 476 477 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg); 478 if (needs_post_barrier) { 479 g1_write_barrier_post(masm, 480 tmp3 /* store_adr */, 481 new_val /* new_val */, 482 rthread /* thread */, 483 tmp1 /* tmp1 */, 484 tmp2 /* tmp2 */); 485 } 486 } 487 488 } 489 490 #ifdef COMPILER1 491 492 #undef __ 493 #define __ ce->masm()-> 494 495 void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) { 496 G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); 497 // At this point we know that marking is in progress. 498 // If do_load() is true then we have to emit the 499 // load of the previous value; otherwise it has already 500 // been loaded into _pre_val. 501 502 __ bind(*stub->entry()); 503 504 assert(stub->pre_val()->is_register(), "Precondition."); 505 506 Register pre_val_reg = stub->pre_val()->as_register(); 507 508 if (stub->do_load()) { 509 ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/); 510 } 511 __ cbz(pre_val_reg, *stub->continuation()); 512 ce->store_parameter(stub->pre_val()->as_register(), 0); 513 __ far_call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin())); 514 __ b(*stub->continuation()); 515 } 516 517 void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { 518 G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); 519 __ bind(*stub->entry()); 520 assert(stub->addr()->is_register(), "Precondition."); 521 assert(stub->new_val()->is_register(), "Precondition."); 522 Register new_val_reg = stub->new_val()->as_register(); 523 __ cbz(new_val_reg, *stub->continuation()); 524 ce->store_parameter(stub->addr()->as_pointer_register(), 0); 525 __ far_call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin())); 526 __ b(*stub->continuation()); 527 } 528 529 #undef __ 530 531 #define __ sasm-> 532 533 void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { 534 __ prologue("g1_pre_barrier", false); 535 536 // arg0 : previous value of memory 537 538 BarrierSet* bs = BarrierSet::barrier_set(); 539 540 const Register pre_val = r0; 541 const Register thread = rthread; 542 const Register tmp = rscratch1; 543 544 Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); 545 Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); 546 Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); 547 548 Label done; 549 Label runtime; 550 551 // Is marking still active? 552 if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { 553 __ ldrw(tmp, in_progress); 554 } else { 555 assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); 556 __ ldrb(tmp, in_progress); 557 } 558 __ cbzw(tmp, done); 559 560 // Can we store original value in the thread's buffer? 561 __ ldr(tmp, queue_index); 562 __ cbz(tmp, runtime); 563 564 __ sub(tmp, tmp, wordSize); 565 __ str(tmp, queue_index); 566 __ ldr(rscratch2, buffer); 567 __ add(tmp, tmp, rscratch2); 568 __ load_parameter(0, rscratch2); 569 __ str(rscratch2, Address(tmp, 0)); 570 __ b(done); 571 572 __ bind(runtime); 573 __ push_call_clobbered_registers(); 574 __ load_parameter(0, pre_val); 575 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); 576 __ pop_call_clobbered_registers(); 577 __ bind(done); 578 579 __ epilogue(); 580 } 581 582 void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { 583 __ prologue("g1_post_barrier", false); 584 585 // arg0: store_address 586 Address store_addr(rfp, 2*BytesPerWord); 587 588 BarrierSet* bs = BarrierSet::barrier_set(); 589 CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs); 590 CardTable* ct = ctbs->card_table(); 591 592 Label done; 593 Label runtime; 594 595 // At this point we know new_value is non-null and the new_value crosses regions. 596 // Must check to see if card is already dirty 597 598 const Register thread = rthread; 599 600 Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); 601 Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); 602 603 const Register card_offset = rscratch2; 604 // LR is free here, so we can use it to hold the byte_map_base. 605 const Register byte_map_base = lr; 606 607 assert_different_registers(card_offset, byte_map_base, rscratch1); 608 609 __ load_parameter(0, card_offset); 610 __ lsr(card_offset, card_offset, CardTable::card_shift()); 611 __ load_byte_map_base(byte_map_base); 612 __ ldrb(rscratch1, Address(byte_map_base, card_offset)); 613 __ cmpw(rscratch1, (int)G1CardTable::g1_young_card_val()); 614 __ br(Assembler::EQ, done); 615 616 assert((int)CardTable::dirty_card_val() == 0, "must be 0"); 617 618 __ membar(Assembler::StoreLoad); 619 __ ldrb(rscratch1, Address(byte_map_base, card_offset)); 620 __ cbzw(rscratch1, done); 621 622 // storing region crossing non-null, card is clean. 623 // dirty card and log. 624 __ strb(zr, Address(byte_map_base, card_offset)); 625 626 // Convert card offset into an address in card_addr 627 Register card_addr = card_offset; 628 __ add(card_addr, byte_map_base, card_addr); 629 630 __ ldr(rscratch1, queue_index); 631 __ cbz(rscratch1, runtime); 632 __ sub(rscratch1, rscratch1, wordSize); 633 __ str(rscratch1, queue_index); 634 635 // Reuse LR to hold buffer_addr 636 const Register buffer_addr = lr; 637 638 __ ldr(buffer_addr, buffer); 639 __ str(card_addr, Address(buffer_addr, rscratch1)); 640 __ b(done); 641 642 __ bind(runtime); 643 __ push_call_clobbered_registers(); 644 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); 645 __ pop_call_clobbered_registers(); 646 __ bind(done); 647 __ epilogue(); 648 } 649 650 #undef __ 651 652 #endif // COMPILER1