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