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 "interpreter/interp_masm.hpp" 33 #include "runtime/sharedRuntime.hpp" 34 #include "utilities/debug.hpp" 35 #include "utilities/macros.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) { 49 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; 50 51 if (!dest_uninitialized) { 52 Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); 53 #ifndef _LP64 54 __ push(thread); 55 __ get_thread(thread); 56 #endif 57 58 Label filtered; 59 Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); 60 // Is marking active? 61 if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { 62 __ cmpl(in_progress, 0); 63 } else { 64 assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); 65 __ cmpb(in_progress, 0); 66 } 67 68 NOT_LP64(__ pop(thread);) 69 70 __ jcc(Assembler::equal, filtered); 71 72 __ push_call_clobbered_registers(false /* save_fpu */); 73 #ifdef _LP64 74 if (count == c_rarg0) { 75 if (addr == c_rarg1) { 76 // exactly backwards!! 77 __ xchgptr(c_rarg1, c_rarg0); 78 } else { 79 __ movptr(c_rarg1, count); 80 __ movptr(c_rarg0, addr); 81 } 82 } else { 83 __ movptr(c_rarg0, addr); 84 __ movptr(c_rarg1, count); 85 } 86 if (UseCompressedOops) { 87 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_narrow_oop_entry), 2); 88 } else { 89 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), 2); 90 } 91 #else 92 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), 93 addr, count); 94 #endif 95 __ pop_call_clobbered_registers(false /* save_fpu */); 96 97 __ bind(filtered); 98 } 99 } 100 101 void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, 102 Register addr, Register count, Register tmp) { 103 __ push_call_clobbered_registers(false /* save_fpu */); 104 #ifdef _LP64 105 if (c_rarg0 == count) { // On win64 c_rarg0 == rcx 106 assert_different_registers(c_rarg1, addr); 107 __ mov(c_rarg1, count); 108 __ mov(c_rarg0, addr); 109 } else { 110 assert_different_registers(c_rarg0, count); 111 __ mov(c_rarg0, addr); 112 __ mov(c_rarg1, count); 113 } 114 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2); 115 #else 116 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 117 addr, count); 118 #endif 119 __ pop_call_clobbered_registers(false /* save_fpu */); 120 } 121 122 void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, 123 Register dst, Address src, Register tmp1, Register tmp_thread) { 124 bool on_oop = is_reference_type(type); 125 bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; 126 bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; 127 bool on_reference = on_weak || on_phantom; 128 ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); 129 if (on_oop && on_reference) { 130 Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread); 131 132 #ifndef _LP64 133 // Work around the x86_32 bug that only manifests with Loom for some reason. 134 // MacroAssembler::resolve_weak_handle calls this barrier with tmp_thread == noreg. 135 if (thread == noreg) { 136 if (dst != rcx && tmp1 != rcx) { 137 thread = rcx; 138 } else if (dst != rdx && tmp1 != rdx) { 139 thread = rdx; 140 } else if (dst != rdi && tmp1 != rdi) { 141 thread = rdi; 142 } 143 } 144 assert_different_registers(dst, tmp1, thread); 145 __ push(thread); 146 __ get_thread(thread); 147 #endif 148 149 // Generate the G1 pre-barrier code to log the value of 150 // the referent field in an SATB buffer. 151 g1_write_barrier_pre(masm /* masm */, 152 noreg /* obj */, 153 dst /* pre_val */, 154 thread /* thread */, 155 tmp1 /* tmp */, 156 true /* tosca_live */, 157 true /* expand_call */); 158 159 #ifndef _LP64 160 __ pop(thread); 161 #endif 162 } 163 } 164 165 static void generate_queue_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, 166 const Register thread, const Register value, const Register temp) { 167 // This code assumes that buffer index is pointer sized. 168 STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t)); 169 // Can we store a value in the given thread's buffer? 170 // (The index field is typed as size_t.) 171 __ movptr(temp, Address(thread, in_bytes(index_offset))); // temp := *(index address) 172 __ testptr(temp, temp); // index == 0? 173 __ jcc(Assembler::zero, runtime); // jump to runtime if index == 0 (full buffer) 174 // The buffer is not full, store value into it. 175 __ subptr(temp, wordSize); // temp := next index 176 __ movptr(Address(thread, in_bytes(index_offset)), temp); // *(index address) := next index 177 __ addptr(temp, Address(thread, in_bytes(buffer_offset))); // temp := buffer address + next index 178 __ movptr(Address(temp, 0), value); // *(buffer address + next index) := value 179 } 180 181 static void generate_pre_barrier_fast_path(MacroAssembler* masm, 182 const Register thread) { 183 Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); 184 // Is marking active? 185 if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { 186 __ cmpl(in_progress, 0); 187 } else { 188 assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); 189 __ cmpb(in_progress, 0); 190 } 191 } 192 193 static void generate_pre_barrier_slow_path(MacroAssembler* masm, 194 const Register obj, 195 const Register pre_val, 196 const Register thread, 197 const Register tmp, 198 Label& done, 199 Label& runtime) { 200 // Do we need to load the previous value? 201 if (obj != noreg) { 202 __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); 203 } 204 // Is the previous value null? 205 __ cmpptr(pre_val, NULL_WORD); 206 __ jcc(Assembler::equal, done); 207 generate_queue_insertion(masm, 208 G1ThreadLocalData::satb_mark_queue_index_offset(), 209 G1ThreadLocalData::satb_mark_queue_buffer_offset(), 210 runtime, 211 thread, pre_val, tmp); 212 __ jmp(done); 213 } 214 215 void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, 216 Register obj, 217 Register pre_val, 218 Register thread, 219 Register tmp, 220 bool tosca_live, 221 bool expand_call) { 222 // If expand_call is true then we expand the call_VM_leaf macro 223 // directly to skip generating the check by 224 // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. 225 226 #ifdef _LP64 227 assert(thread == r15_thread, "must be"); 228 #endif // _LP64 229 230 Label done; 231 Label runtime; 232 233 assert(pre_val != noreg, "check this code"); 234 235 if (obj != noreg) { 236 assert_different_registers(obj, pre_val, tmp); 237 assert(pre_val != rax, "check this code"); 238 } 239 240 generate_pre_barrier_fast_path(masm, thread); 241 // If marking is not active (*(mark queue active address) == 0), jump to done 242 __ jcc(Assembler::equal, done); 243 generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, done, runtime); 244 245 __ bind(runtime); 246 247 // Determine and save the live input values 248 __ push_call_clobbered_registers(); 249 250 // Calling the runtime using the regular call_VM_leaf mechanism generates 251 // code (generated by InterpreterMacroAssember::call_VM_leaf_base) 252 // that checks that the *(ebp+frame::interpreter_frame_last_sp) == nullptr. 253 // 254 // If we care generating the pre-barrier without a frame (e.g. in the 255 // intrinsified Reference.get() routine) then ebp might be pointing to 256 // the caller frame and so this check will most likely fail at runtime. 257 // 258 // Expanding the call directly bypasses the generation of the check. 259 // So when we do not have have a full interpreter frame on the stack 260 // expand_call should be passed true. 261 262 if (expand_call) { 263 LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); ) 264 #ifdef _LP64 265 if (c_rarg1 != thread) { 266 __ mov(c_rarg1, thread); 267 } 268 if (c_rarg0 != pre_val) { 269 __ mov(c_rarg0, pre_val); 270 } 271 #else 272 __ push(thread); 273 __ push(pre_val); 274 #endif 275 __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), 2); 276 } else { 277 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); 278 } 279 280 __ pop_call_clobbered_registers(); 281 282 __ bind(done); 283 } 284 285 static void generate_post_barrier_fast_path(MacroAssembler* masm, 286 const Register store_addr, 287 const Register new_val, 288 const Register tmp, 289 const Register tmp2, 290 Label& done, 291 bool new_val_may_be_null) { 292 CardTableBarrierSet* ct = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set()); 293 // Does store cross heap regions? 294 __ movptr(tmp, store_addr); // tmp := store address 295 __ xorptr(tmp, new_val); // tmp := store address ^ new value 296 __ shrptr(tmp, G1HeapRegion::LogOfHRGrainBytes); // ((store address ^ new value) >> LogOfHRGrainBytes) == 0? 297 __ jcc(Assembler::equal, done); 298 // Crosses regions, storing null? 299 if (new_val_may_be_null) { 300 __ cmpptr(new_val, NULL_WORD); // new value == null? 301 __ jcc(Assembler::equal, done); 302 } 303 // Storing region crossing non-null, is card young? 304 __ movptr(tmp, store_addr); // tmp := store address 305 __ shrptr(tmp, CardTable::card_shift()); // tmp := card address relative to card table base 306 // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT 307 // a valid address and therefore is not properly handled by the relocation code. 308 __ movptr(tmp2, (intptr_t)ct->card_table()->byte_map_base()); // tmp2 := card table base address 309 __ addptr(tmp, tmp2); // tmp := card address 310 __ cmpb(Address(tmp, 0), G1CardTable::g1_young_card_val()); // *(card address) == young_card_val? 311 } 312 313 static void generate_post_barrier_slow_path(MacroAssembler* masm, 314 const Register thread, 315 const Register tmp, 316 const Register tmp2, 317 Label& done, 318 Label& runtime) { 319 __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); // StoreLoad membar 320 __ cmpb(Address(tmp, 0), G1CardTable::dirty_card_val()); // *(card address) == dirty_card_val? 321 __ jcc(Assembler::equal, done); 322 // Storing a region crossing, non-null oop, card is clean. 323 // Dirty card and log. 324 __ movb(Address(tmp, 0), G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val 325 generate_queue_insertion(masm, 326 G1ThreadLocalData::dirty_card_queue_index_offset(), 327 G1ThreadLocalData::dirty_card_queue_buffer_offset(), 328 runtime, 329 thread, tmp, tmp2); 330 __ jmp(done); 331 } 332 333 void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, 334 Register store_addr, 335 Register new_val, 336 Register thread, 337 Register tmp, 338 Register tmp2) { 339 #ifdef _LP64 340 assert(thread == r15_thread, "must be"); 341 #endif // _LP64 342 343 Label done; 344 Label runtime; 345 346 generate_post_barrier_fast_path(masm, store_addr, new_val, tmp, tmp2, done, true /* new_val_may_be_null */); 347 // If card is young, jump to done 348 __ jcc(Assembler::equal, done); 349 generate_post_barrier_slow_path(masm, thread, tmp, tmp2, done, runtime); 350 351 __ bind(runtime); 352 // save the live input values 353 RegSet saved = RegSet::of(store_addr NOT_LP64(COMMA thread)); 354 __ push_set(saved); 355 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp, thread); 356 __ pop_set(saved); 357 358 __ bind(done); 359 } 360 361 #if defined(COMPILER2) 362 363 static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { 364 #ifdef _LP64 365 SaveLiveRegisters save_registers(masm, stub); 366 if (c_rarg0 != arg) { 367 __ mov(c_rarg0, arg); 368 } 369 __ mov(c_rarg1, r15_thread); 370 // rax is a caller-saved, non-argument-passing register, so it does not 371 // interfere with c_rarg0 or c_rarg1. If it contained any live value before 372 // entering this stub, it is saved at this point, and restored after the 373 // call. If it did not contain any live value, it is free to be used. In 374 // either case, it is safe to use it here as a call scratch register. 375 __ call(RuntimeAddress(runtime_path), rax); 376 #else 377 Unimplemented(); 378 #endif // _LP64 379 } 380 381 void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, 382 Register obj, 383 Register pre_val, 384 Register thread, 385 Register tmp, 386 G1PreBarrierStubC2* stub) { 387 #ifdef _LP64 388 assert(thread == r15_thread, "must be"); 389 #endif // _LP64 390 assert(pre_val != noreg, "check this code"); 391 if (obj != noreg) { 392 assert_different_registers(obj, pre_val, tmp); 393 } 394 395 stub->initialize_registers(obj, pre_val, thread, tmp); 396 397 generate_pre_barrier_fast_path(masm, thread); 398 // If marking is active (*(mark queue active address) != 0), jump to stub (slow path) 399 __ jcc(Assembler::notEqual, *stub->entry()); 400 401 __ bind(*stub->continuation()); 402 } 403 404 void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, 405 G1PreBarrierStubC2* stub) const { 406 Assembler::InlineSkippedInstructionsCounter skip_counter(masm); 407 Label runtime; 408 Register obj = stub->obj(); 409 Register pre_val = stub->pre_val(); 410 Register thread = stub->thread(); 411 Register tmp = stub->tmp1(); 412 assert(stub->tmp2() == noreg, "not needed in this platform"); 413 414 __ bind(*stub->entry()); 415 generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, *stub->continuation(), runtime); 416 417 __ bind(runtime); 418 generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); 419 __ jmp(*stub->continuation()); 420 } 421 422 void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, 423 Register store_addr, 424 Register new_val, 425 Register thread, 426 Register tmp, 427 Register tmp2, 428 G1PostBarrierStubC2* stub) { 429 #ifdef _LP64 430 assert(thread == r15_thread, "must be"); 431 #endif // _LP64 432 433 stub->initialize_registers(thread, tmp, tmp2); 434 435 bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; 436 generate_post_barrier_fast_path(masm, store_addr, new_val, tmp, tmp2, *stub->continuation(), new_val_may_be_null); 437 // If card is not young, jump to stub (slow path) 438 __ jcc(Assembler::notEqual, *stub->entry()); 439 440 __ bind(*stub->continuation()); 441 } 442 443 void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, 444 G1PostBarrierStubC2* stub) const { 445 Assembler::InlineSkippedInstructionsCounter skip_counter(masm); 446 Label runtime; 447 Register thread = stub->thread(); 448 Register tmp = stub->tmp1(); // tmp holds the card address. 449 Register tmp2 = stub->tmp2(); 450 assert(stub->tmp3() == noreg, "not needed in this platform"); 451 452 __ bind(*stub->entry()); 453 generate_post_barrier_slow_path(masm, thread, tmp, tmp2, *stub->continuation(), runtime); 454 455 __ bind(runtime); 456 generate_c2_barrier_runtime_call(masm, stub, tmp, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); 457 __ jmp(*stub->continuation()); 458 } 459 460 #endif // COMPILER2 461 462 void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, 463 Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { 464 bool in_heap = (decorators & IN_HEAP) != 0; 465 bool as_normal = (decorators & AS_NORMAL) != 0; 466 467 bool needs_pre_barrier = as_normal; 468 bool needs_post_barrier = val != noreg && in_heap; 469 470 Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); 471 // flatten object address if needed 472 // We do it regardless of precise because we need the registers 473 if (dst.index() == noreg && dst.disp() == 0) { 474 if (dst.base() != tmp1) { 475 __ movptr(tmp1, dst.base()); 476 } 477 } else { 478 __ lea(tmp1, dst); 479 } 480 481 #ifndef _LP64 482 InterpreterMacroAssembler *imasm = static_cast<InterpreterMacroAssembler*>(masm); 483 #endif 484 485 NOT_LP64(__ get_thread(rcx)); 486 NOT_LP64(imasm->save_bcp()); 487 488 if (needs_pre_barrier) { 489 g1_write_barrier_pre(masm /*masm*/, 490 tmp1 /* obj */, 491 tmp2 /* pre_val */, 492 rthread /* thread */, 493 tmp3 /* tmp */, 494 val != noreg /* tosca_live */, 495 false /* expand_call */); 496 } 497 if (val == noreg) { 498 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); 499 } else { 500 Register new_val = val; 501 if (needs_post_barrier) { 502 // G1 barrier needs uncompressed oop for region cross check. 503 if (UseCompressedOops) { 504 new_val = tmp2; 505 __ movptr(new_val, val); 506 } 507 } 508 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); 509 if (needs_post_barrier) { 510 g1_write_barrier_post(masm /*masm*/, 511 tmp1 /* store_adr */, 512 new_val /* new_val */, 513 rthread /* thread */, 514 tmp3 /* tmp */, 515 tmp2 /* tmp2 */); 516 } 517 } 518 NOT_LP64(imasm->restore_bcp()); 519 } 520 521 #ifdef COMPILER1 522 523 #undef __ 524 #define __ ce->masm()-> 525 526 void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) { 527 G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); 528 // At this point we know that marking is in progress. 529 // If do_load() is true then we have to emit the 530 // load of the previous value; otherwise it has already 531 // been loaded into _pre_val. 532 533 __ bind(*stub->entry()); 534 assert(stub->pre_val()->is_register(), "Precondition."); 535 536 Register pre_val_reg = stub->pre_val()->as_register(); 537 538 if (stub->do_load()) { 539 ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/); 540 } 541 542 __ cmpptr(pre_val_reg, NULL_WORD); 543 __ jcc(Assembler::equal, *stub->continuation()); 544 ce->store_parameter(stub->pre_val()->as_register(), 0); 545 __ call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin())); 546 __ jmp(*stub->continuation()); 547 548 } 549 550 void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { 551 G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); 552 __ bind(*stub->entry()); 553 assert(stub->addr()->is_register(), "Precondition."); 554 assert(stub->new_val()->is_register(), "Precondition."); 555 Register new_val_reg = stub->new_val()->as_register(); 556 __ cmpptr(new_val_reg, NULL_WORD); 557 __ jcc(Assembler::equal, *stub->continuation()); 558 ce->store_parameter(stub->addr()->as_pointer_register(), 0); 559 __ call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin())); 560 __ jmp(*stub->continuation()); 561 } 562 563 #undef __ 564 565 #define __ sasm-> 566 567 void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { 568 // Generated code assumes that buffer index is pointer sized. 569 STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t)); 570 571 __ prologue("g1_pre_barrier", false); 572 // arg0 : previous value of memory 573 574 __ push(rax); 575 __ push(rdx); 576 577 const Register pre_val = rax; 578 const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); 579 const Register tmp = rdx; 580 581 NOT_LP64(__ get_thread(thread);) 582 583 Address queue_active(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); 584 Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); 585 Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); 586 587 Label done; 588 Label runtime; 589 590 // Is marking still active? 591 if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { 592 __ cmpl(queue_active, 0); 593 } else { 594 assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); 595 __ cmpb(queue_active, 0); 596 } 597 __ jcc(Assembler::equal, done); 598 599 // Can we store original value in the thread's buffer? 600 601 __ movptr(tmp, queue_index); 602 __ testptr(tmp, tmp); 603 __ jcc(Assembler::zero, runtime); 604 __ subptr(tmp, wordSize); 605 __ movptr(queue_index, tmp); 606 __ addptr(tmp, buffer); 607 608 // prev_val (rax) 609 __ load_parameter(0, pre_val); 610 __ movptr(Address(tmp, 0), pre_val); 611 __ jmp(done); 612 613 __ bind(runtime); 614 615 __ push_call_clobbered_registers(); 616 617 // load the pre-value 618 __ load_parameter(0, rcx); 619 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), rcx, thread); 620 621 __ pop_call_clobbered_registers(); 622 623 __ bind(done); 624 625 __ pop(rdx); 626 __ pop(rax); 627 628 __ epilogue(); 629 } 630 631 void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { 632 __ prologue("g1_post_barrier", false); 633 634 CardTableBarrierSet* ct = 635 barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set()); 636 637 Label done; 638 Label enqueued; 639 Label runtime; 640 641 // At this point we know new_value is non-null and the new_value crosses regions. 642 // Must check to see if card is already dirty 643 644 const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); 645 646 Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); 647 Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); 648 649 __ push(rax); 650 __ push(rcx); 651 652 const Register cardtable = rax; 653 const Register card_addr = rcx; 654 655 __ load_parameter(0, card_addr); 656 __ shrptr(card_addr, CardTable::card_shift()); 657 // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT 658 // a valid address and therefore is not properly handled by the relocation code. 659 __ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base()); 660 __ addptr(card_addr, cardtable); 661 662 NOT_LP64(__ get_thread(thread);) 663 664 __ cmpb(Address(card_addr, 0), G1CardTable::g1_young_card_val()); 665 __ jcc(Assembler::equal, done); 666 667 __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); 668 __ cmpb(Address(card_addr, 0), CardTable::dirty_card_val()); 669 __ jcc(Assembler::equal, done); 670 671 // storing region crossing non-null, card is clean. 672 // dirty card and log. 673 674 __ movb(Address(card_addr, 0), CardTable::dirty_card_val()); 675 676 const Register tmp = rdx; 677 __ push(rdx); 678 679 __ movptr(tmp, queue_index); 680 __ testptr(tmp, tmp); 681 __ jcc(Assembler::zero, runtime); 682 __ subptr(tmp, wordSize); 683 __ movptr(queue_index, tmp); 684 __ addptr(tmp, buffer); 685 __ movptr(Address(tmp, 0), card_addr); 686 __ jmp(enqueued); 687 688 __ bind(runtime); 689 __ push_call_clobbered_registers(); 690 691 __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); 692 693 __ pop_call_clobbered_registers(); 694 695 __ bind(enqueued); 696 __ pop(rdx); 697 698 __ bind(done); 699 __ pop(rcx); 700 __ pop(rax); 701 702 __ epilogue(); 703 } 704 705 #undef __ 706 707 #endif // COMPILER1