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