1 // 2 // Copyright (c) 2024, 2026, 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 source_hpp %{ 25 26 #include "gc/g1/c2/g1BarrierSetC2.hpp" 27 #include "gc/shared/gc_globals.hpp" 28 29 %} 30 31 source %{ 32 33 #include "gc/g1/g1BarrierSetAssembler_x86.hpp" 34 #include "gc/g1/g1BarrierSetRuntime.hpp" 35 36 static void write_barrier_pre(MacroAssembler* masm, 37 const MachNode* node, 38 Register obj, 39 Register pre_val, 40 Register tmp, 41 RegSet preserve = RegSet(), 42 RegSet no_preserve = RegSet()) { 43 if (!G1PreBarrierStubC2::needs_barrier(node)) { 44 return; 45 } 46 Assembler::InlineSkippedInstructionsCounter skip_counter(masm); 47 G1BarrierSetAssembler* g1_asm = static_cast<G1BarrierSetAssembler*>(BarrierSet::barrier_set()->barrier_set_assembler()); 48 G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); 49 for (RegSetIterator<Register> reg = preserve.begin(); *reg != noreg; ++reg) { 50 stub->preserve(*reg); 51 } 52 for (RegSetIterator<Register> reg = no_preserve.begin(); *reg != noreg; ++reg) { 53 stub->dont_preserve(*reg); 54 } 55 g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, tmp, stub); 56 } 57 58 static void write_barrier_post(MacroAssembler* masm, 59 const MachNode* node, 60 Register store_addr, 61 Register new_val, 62 Register tmp1) { 63 if (!G1BarrierStubC2::needs_post_barrier(node)) { 64 return; 65 } 66 Assembler::InlineSkippedInstructionsCounter skip_counter(masm); 67 G1BarrierSetAssembler* g1_asm = static_cast<G1BarrierSetAssembler*>(BarrierSet::barrier_set()->barrier_set_assembler()); 68 bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node); 69 g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, new_val_may_be_null); 70 } 71 72 %} 73 74 instruct g1StoreP(memory mem, any_RegP src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) 75 %{ 76 predicate(UseG1GC && n->as_Store()->barrier_data() != 0); 77 match(Set mem (StoreP mem src)); 78 effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); 79 ins_cost(125); // XXX 80 format %{ "movq $mem, $src\t# ptr" %} 81 ins_encode %{ 82 // Materialize the store address internally (as opposed to defining 'mem' as 83 // an indirect memory operand) to reduce the overhead of LCM when processing 84 // large basic blocks with many stores. Such basic blocks arise, for 85 // instance, from static initializations of large String arrays. 86 // The same holds for g1StoreN and g1EncodePAndStoreN. 87 __ lea($tmp1$$Register, $mem$$Address); 88 write_barrier_pre(masm, this, 89 $tmp1$$Register /* obj */, 90 $tmp2$$Register /* pre_val */, 91 $tmp3$$Register /* tmp */, 92 RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); 93 __ movq(Address($tmp1$$Register, 0), $src$$Register); 94 write_barrier_post(masm, this, 95 $tmp1$$Register /* store_addr */, 96 $src$$Register /* new_val */, 97 $tmp3$$Register /* tmp1 */); 98 %} 99 ins_pipe(ialu_mem_reg); 100 %} 101 102 // TODO 8350865 (same applies to g1StoreLSpecialTwoOops) 103 // - Do no set/overwrite barrier data here, also handle G1C2BarrierPostNotNull 104 instruct g1StoreLSpecialOneOopOff0(memory mem, rRegL src, immI_0 off, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) 105 %{ 106 predicate(UseG1GC); 107 match(Set mem (StoreLSpecial mem (Binary src off))); 108 effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); 109 format %{ "movq $mem, $src\t# g1StoreLSpecialOneOopOff0" %} 110 ins_encode %{ 111 ((MachNode*)this)->set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); 112 113 __ lea($tmp1$$Register, $mem$$Address); 114 write_barrier_pre(masm, this, 115 $tmp1$$Register /* obj */, 116 $tmp2$$Register /* pre_val */, 117 $tmp3$$Register /* tmp */, 118 RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); 119 120 __ movq(Address($tmp1$$Register, 0), $src$$Register); 121 122 // Extract the narrow oop field value 123 __ movl($tmp2$$Register, $src$$Register); 124 __ decode_heap_oop($tmp2$$Register); 125 write_barrier_post(masm, this, 126 $tmp1$$Register /* store_addr */, 127 $tmp2$$Register /* new_val */, 128 $tmp3$$Register /* tmp1 */); 129 %} 130 ins_pipe(ialu_mem_reg); 131 %} 132 133 instruct g1StoreLSpecialOneOopOff4(memory mem, rRegL src, immI_4 off, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) 134 %{ 135 predicate(UseG1GC); 136 match(Set mem (StoreLSpecial mem (Binary src off))); 137 effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); 138 format %{ "movq $mem, $src\t# g1StoreLSpecialOneOopOff4" %} 139 ins_encode %{ 140 ((MachNode*)this)->set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); 141 142 // Adjust address to point to narrow oop 143 Address dst = $mem$$Address; 144 __ lea($tmp1$$Register, dst.plus_disp(4)); 145 write_barrier_pre(masm, this, 146 $tmp1$$Register /* obj */, 147 $tmp2$$Register /* pre_val */, 148 $tmp3$$Register /* tmp */, 149 RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); 150 151 // The address of the oop is the address of the store plus the offset of the oop 152 __ movq(Address($tmp1$$Register, -4), $src$$Register); 153 154 // Shift long value to extract the narrow oop field value 155 __ movq($tmp2$$Register, $src$$Register); 156 __ shrq($tmp2$$Register, 32); 157 __ decode_heap_oop($tmp2$$Register); 158 write_barrier_post(masm, this, 159 $tmp1$$Register /* store_addr */, 160 $src$$Register /* new_val */, 161 $tmp3$$Register /* tmp1 */); 162 %} 163 ins_pipe(ialu_mem_reg); 164 %} 165 166 instruct g1StoreLSpecialTwoOops(memory mem, rRegL src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) 167 %{ 168 predicate(UseG1GC); 169 match(Set mem (StoreLSpecial mem src)); 170 effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); 171 format %{ "movq $mem, $src\t# g1StoreLSpecialTwoOops" %} 172 ins_encode %{ 173 ((MachNode*)this)->set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); 174 175 __ lea($tmp1$$Register, $mem$$Address); 176 write_barrier_pre(masm, this, 177 $tmp1$$Register /* obj */, 178 $tmp2$$Register /* pre_val */, 179 $tmp3$$Register /* tmp */, 180 RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); 181 // Adjust address to point to the second narrow oop in the long value 182 __ addq($tmp1$$Register, 4); 183 write_barrier_pre(masm, this, 184 $tmp1$$Register /* obj */, 185 $tmp2$$Register /* pre_val */, 186 $tmp3$$Register /* tmp */, 187 RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); 188 189 // The address of the second oop is the address of the store plus the offset of the second oop 190 __ movq(Address($tmp1$$Register, -4), $src$$Register); 191 192 // Do the post-barrier of the second oop first since we have its address in tmp1 193 __ movq($tmp2$$Register, $src$$Register); 194 __ shrq($tmp2$$Register, 32); 195 __ decode_heap_oop($tmp2$$Register); 196 write_barrier_post(masm, this, 197 $tmp1$$Register /* store_addr */, 198 $tmp2$$Register /* new_val */, 199 $tmp3$$Register /* tmp1 */); 200 201 // Retrieve the address of the first narrow oop 202 __ addq($tmp1$$Register, -4); 203 // Extract the first narrow oop 204 __ movl($tmp2$$Register, $src$$Register); 205 __ decode_heap_oop($tmp2$$Register); 206 write_barrier_post(masm, this, 207 $tmp1$$Register /* store_addr */, 208 $tmp2$$Register /* new_val */, 209 $tmp3$$Register /* tmp1 */); 210 %} 211 ins_pipe(ialu_mem_reg); 212 %} 213 214 instruct g1StoreN(memory mem, rRegN src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) 215 %{ 216 predicate(UseG1GC && n->as_Store()->barrier_data() != 0); 217 match(Set mem (StoreN mem src)); 218 effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); 219 ins_cost(125); // XXX 220 format %{ "movl $mem, $src\t# ptr" %} 221 ins_encode %{ 222 __ lea($tmp1$$Register, $mem$$Address); 223 write_barrier_pre(masm, this, 224 $tmp1$$Register /* obj */, 225 $tmp2$$Register /* pre_val */, 226 $tmp3$$Register /* tmp */, 227 RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); 228 __ movl(Address($tmp1$$Register, 0), $src$$Register); 229 if ((barrier_data() & G1C2BarrierPost) != 0) { 230 __ movl($tmp2$$Register, $src$$Register); 231 if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { 232 __ decode_heap_oop($tmp2$$Register); 233 } else { 234 __ decode_heap_oop_not_null($tmp2$$Register); 235 } 236 } 237 write_barrier_post(masm, this, 238 $tmp1$$Register /* store_addr */, 239 $tmp2$$Register /* new_val */, 240 $tmp3$$Register /* tmp1 */); 241 %} 242 ins_pipe(ialu_mem_reg); 243 %} 244 245 instruct g1EncodePAndStoreN(memory mem, any_RegP src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) 246 %{ 247 predicate(UseG1GC && n->as_Store()->barrier_data() != 0); 248 match(Set mem (StoreN mem (EncodeP src))); 249 effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); 250 ins_cost(125); // XXX 251 format %{ "encode_heap_oop $src\n\t" 252 "movl $mem, $src\t# ptr" %} 253 ins_encode %{ 254 __ lea($tmp1$$Register, $mem$$Address); 255 write_barrier_pre(masm, this, 256 $tmp1$$Register /* obj */, 257 $tmp2$$Register /* pre_val */, 258 $tmp3$$Register /* tmp */, 259 RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); 260 __ movq($tmp2$$Register, $src$$Register); 261 if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { 262 __ encode_heap_oop($tmp2$$Register); 263 } else { 264 __ encode_heap_oop_not_null($tmp2$$Register); 265 } 266 __ movl(Address($tmp1$$Register, 0), $tmp2$$Register); 267 write_barrier_post(masm, this, 268 $tmp1$$Register /* store_addr */, 269 $src$$Register /* new_val */, 270 $tmp3$$Register /* tmp1 */); 271 %} 272 ins_pipe(ialu_mem_reg); 273 %} 274 275 instruct g1CompareAndExchangeP(indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegP oldval, rFlagsReg cr) 276 %{ 277 predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); 278 match(Set oldval (CompareAndExchangeP mem (Binary oldval newval))); 279 effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); 280 format %{ "lock\n\t" 281 "cmpxchgq $newval, $mem" %} 282 ins_encode %{ 283 assert_different_registers($oldval$$Register, $mem$$Register); 284 // Pass $oldval to the pre-barrier (instead of loading from $mem), because 285 // $oldval is the only value that can be overwritten. 286 // The same holds for g1CompareAndSwapP. 287 write_barrier_pre(masm, this, 288 noreg /* obj */, 289 $oldval$$Register /* pre_val */, 290 $tmp3$$Register /* tmp */, 291 RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */); 292 __ movq($tmp1$$Register, $newval$$Register); 293 __ lock(); 294 __ cmpxchgq($tmp1$$Register, Address($mem$$Register, 0)); 295 write_barrier_post(masm, this, 296 $mem$$Register /* store_addr */, 297 $tmp1$$Register /* new_val */, 298 $tmp2$$Register /* tmp1 */); 299 %} 300 ins_pipe(pipe_cmpxchg); 301 %} 302 303 instruct g1CompareAndExchangeN(indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegN oldval, rFlagsReg cr) 304 %{ 305 predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); 306 match(Set oldval (CompareAndExchangeN mem (Binary oldval newval))); 307 effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); 308 format %{ "lock\n\t" 309 "cmpxchgq $newval, $mem" %} 310 ins_encode %{ 311 assert_different_registers($oldval$$Register, $mem$$Register); 312 write_barrier_pre(masm, this, 313 $mem$$Register /* obj */, 314 $tmp2$$Register /* pre_val */, 315 $tmp3$$Register /* tmp */, 316 RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */); 317 __ movl($tmp1$$Register, $newval$$Register); 318 __ lock(); 319 __ cmpxchgl($tmp1$$Register, Address($mem$$Register, 0)); 320 __ decode_heap_oop($tmp1$$Register); 321 write_barrier_post(masm, this, 322 $mem$$Register /* store_addr */, 323 $tmp1$$Register /* new_val */, 324 $tmp2$$Register /* tmp1 */); 325 %} 326 ins_pipe(pipe_cmpxchg); 327 %} 328 329 instruct g1CompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegP oldval, rFlagsReg cr) 330 %{ 331 predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); 332 match(Set res (CompareAndSwapP mem (Binary oldval newval))); 333 match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); 334 effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL oldval, KILL cr); 335 format %{ "lock\n\t" 336 "cmpxchgq $newval, $mem\n\t" 337 "sete $res\n\t" 338 "movzbl $res, $res" %} 339 ins_encode %{ 340 assert_different_registers($oldval$$Register, $mem$$Register); 341 write_barrier_pre(masm, this, 342 noreg /* obj */, 343 $oldval$$Register /* pre_val */, 344 $tmp3$$Register /* tmp */, 345 RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */, 346 RegSet::of($res$$Register) /* no_preserve */); 347 __ movq($tmp1$$Register, $newval$$Register); 348 __ lock(); 349 __ cmpxchgq($tmp1$$Register, Address($mem$$Register, 0)); 350 __ setb(Assembler::equal, $res$$Register); 351 __ movzbl($res$$Register, $res$$Register); 352 write_barrier_post(masm, this, 353 $mem$$Register /* store_addr */, 354 $tmp1$$Register /* new_val */, 355 $tmp2$$Register /* tmp1 */); 356 %} 357 ins_pipe(pipe_cmpxchg); 358 %} 359 360 instruct g1CompareAndSwapN(rRegI res, indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegN oldval, rFlagsReg cr) 361 %{ 362 predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); 363 match(Set res (CompareAndSwapN mem (Binary oldval newval))); 364 match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); 365 effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL oldval, KILL cr); 366 format %{ "lock\n\t" 367 "cmpxchgq $newval, $mem\n\t" 368 "sete $res\n\t" 369 "movzbl $res, $res" %} 370 ins_encode %{ 371 assert_different_registers($oldval$$Register, $mem$$Register); 372 write_barrier_pre(masm, this, 373 $mem$$Register /* obj */, 374 $tmp2$$Register /* pre_val */, 375 $tmp3$$Register /* tmp */, 376 RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */, 377 RegSet::of($res$$Register) /* no_preserve */); 378 __ movl($tmp1$$Register, $newval$$Register); 379 __ lock(); 380 __ cmpxchgl($tmp1$$Register, Address($mem$$Register, 0)); 381 __ setb(Assembler::equal, $res$$Register); 382 __ movzbl($res$$Register, $res$$Register); 383 __ decode_heap_oop($tmp1$$Register); 384 write_barrier_post(masm, this, 385 $mem$$Register /* store_addr */, 386 $tmp1$$Register /* new_val */, 387 $tmp2$$Register /* tmp1 */); 388 %} 389 ins_pipe(pipe_cmpxchg); 390 %} 391 392 instruct g1GetAndSetP(indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) 393 %{ 394 predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); 395 match(Set newval (GetAndSetP mem newval)); 396 effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); 397 format %{ "xchgq $newval, $mem" %} 398 ins_encode %{ 399 assert_different_registers($mem$$Register, $newval$$Register); 400 write_barrier_pre(masm, this, 401 $mem$$Register /* obj */, 402 $tmp2$$Register /* pre_val */, 403 $tmp3$$Register /* tmp */, 404 RegSet::of($mem$$Register, $newval$$Register) /* preserve */); 405 __ movq($tmp1$$Register, $newval$$Register); 406 __ xchgq($newval$$Register, Address($mem$$Register, 0)); 407 write_barrier_post(masm, this, 408 $mem$$Register /* store_addr */, 409 $tmp1$$Register /* new_val */, 410 $tmp2$$Register /* tmp1 */); 411 %} 412 ins_pipe(pipe_cmpxchg); 413 %} 414 415 instruct g1GetAndSetN(indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) 416 %{ 417 predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); 418 match(Set newval (GetAndSetN mem newval)); 419 effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); 420 format %{ "xchgq $newval, $mem" %} 421 ins_encode %{ 422 assert_different_registers($mem$$Register, $newval$$Register); 423 write_barrier_pre(masm, this, 424 $mem$$Register /* obj */, 425 $tmp2$$Register /* pre_val */, 426 $tmp3$$Register /* tmp */, 427 RegSet::of($mem$$Register, $newval$$Register) /* preserve */); 428 __ movl($tmp1$$Register, $newval$$Register); 429 __ decode_heap_oop($tmp1$$Register); 430 __ xchgl($newval$$Register, Address($mem$$Register, 0)); 431 write_barrier_post(masm, this, 432 $mem$$Register /* store_addr */, 433 $tmp1$$Register /* new_val */, 434 $tmp2$$Register /* tmp1 */); 435 %} 436 ins_pipe(pipe_cmpxchg); 437 %} 438 439 instruct g1LoadP(rRegP dst, memory mem, rRegP tmp, rFlagsReg cr) 440 %{ 441 predicate(UseG1GC && n->as_Load()->barrier_data() != 0); 442 match(Set dst (LoadP mem)); 443 effect(TEMP dst, TEMP tmp, KILL cr); 444 ins_cost(125); // XXX 445 format %{ "movq $dst, $mem\t# ptr" %} 446 ins_encode %{ 447 __ movq($dst$$Register, $mem$$Address); 448 write_barrier_pre(masm, this, 449 noreg /* obj */, 450 $dst$$Register /* pre_val */, 451 $tmp$$Register /* tmp */); 452 %} 453 ins_pipe(ialu_reg_mem); // XXX 454 %} 455 456 instruct g1LoadN(rRegN dst, memory mem, rRegP tmp1, rRegP tmp2, rFlagsReg cr) 457 %{ 458 predicate(UseG1GC && n->as_Load()->barrier_data() != 0); 459 match(Set dst (LoadN mem)); 460 effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); 461 ins_cost(125); // XXX 462 format %{ "movl $dst, $mem\t# compressed ptr" %} 463 ins_encode %{ 464 __ movl($dst$$Register, $mem$$Address); 465 __ movl($tmp1$$Register, $dst$$Register); 466 __ decode_heap_oop($tmp1$$Register); 467 write_barrier_pre(masm, this, 468 noreg /* obj */, 469 $tmp1$$Register /* pre_val */, 470 $tmp2$$Register /* tmp */); 471 %} 472 ins_pipe(ialu_reg_mem); // XXX 473 %} --- EOF ---