1 /* 2 * Copyright (c) 2015, 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 #include "asm/macroAssembler.hpp" 25 #include "classfile/javaClasses.hpp" 26 #include "gc/z/c2/zBarrierSetC2.hpp" 27 #include "gc/z/zBarrierSet.hpp" 28 #include "gc/z/zBarrierSetAssembler.hpp" 29 #include "gc/z/zBarrierSetRuntime.hpp" 30 #include "opto/arraycopynode.hpp" 31 #include "opto/addnode.hpp" 32 #include "opto/block.hpp" 33 #include "opto/compile.hpp" 34 #include "opto/graphKit.hpp" 35 #include "opto/machnode.hpp" 36 #include "opto/macro.hpp" 37 #include "opto/memnode.hpp" 38 #include "opto/node.hpp" 39 #include "opto/output.hpp" 40 #include "opto/regalloc.hpp" 41 #include "opto/rootnode.hpp" 42 #include "opto/runtime.hpp" 43 #include "opto/type.hpp" 44 #include "utilities/debug.hpp" 45 #include "utilities/growableArray.hpp" 46 #include "utilities/macros.hpp" 47 48 template<typename K, typename V, size_t TableSize> 49 class ZArenaHashtable : public ResourceObj { 50 class ZArenaHashtableEntry : public ResourceObj { 51 public: 52 ZArenaHashtableEntry* _next; 53 K _key; 54 V _value; 55 }; 56 57 static const size_t TableMask = TableSize - 1; 58 59 Arena* _arena; 60 ZArenaHashtableEntry* _table[TableSize]; 61 62 public: 63 class Iterator { 64 ZArenaHashtable* _table; 65 ZArenaHashtableEntry* _current_entry; 66 size_t _current_index; 67 68 public: 69 Iterator(ZArenaHashtable* table) 70 : _table(table), 71 _current_entry(table->_table[0]), 72 _current_index(0) { 73 if (_current_entry == nullptr) { 74 next(); 75 } 76 } 77 78 bool has_next() { return _current_entry != nullptr; } 79 K key() { return _current_entry->_key; } 80 V value() { return _current_entry->_value; } 81 82 void next() { 83 if (_current_entry != nullptr) { 84 _current_entry = _current_entry->_next; 85 } 86 while (_current_entry == nullptr && ++_current_index < TableSize) { 87 _current_entry = _table->_table[_current_index]; 88 } 89 } 90 }; 91 92 ZArenaHashtable(Arena* arena) 93 : _arena(arena), 94 _table() { 95 Copy::zero_to_bytes(&_table, sizeof(_table)); 96 } 97 98 void add(K key, V value) { 99 ZArenaHashtableEntry* entry = new (_arena) ZArenaHashtableEntry(); 100 entry->_key = key; 101 entry->_value = value; 102 entry->_next = _table[key & TableMask]; 103 _table[key & TableMask] = entry; 104 } 105 106 V* get(K key) const { 107 for (ZArenaHashtableEntry* e = _table[key & TableMask]; e != nullptr; e = e->_next) { 108 if (e->_key == key) { 109 return &(e->_value); 110 } 111 } 112 return nullptr; 113 } 114 115 Iterator iterator() { 116 return Iterator(this); 117 } 118 }; 119 120 typedef ZArenaHashtable<intptr_t, bool, 4> ZOffsetTable; 121 122 class ZBarrierSetC2State : public BarrierSetC2State { 123 private: 124 GrowableArray<ZBarrierStubC2*>* _stubs; 125 int _trampoline_stubs_count; 126 int _stubs_start_offset; 127 128 public: 129 ZBarrierSetC2State(Arena* arena) 130 : BarrierSetC2State(arena), 131 _stubs(new (arena) GrowableArray<ZBarrierStubC2*>(arena, 8, 0, nullptr)), 132 _trampoline_stubs_count(0), 133 _stubs_start_offset(0) {} 134 135 GrowableArray<ZBarrierStubC2*>* stubs() { 136 return _stubs; 137 } 138 139 bool needs_liveness_data(const MachNode* mach) const { 140 // Don't need liveness data for nodes without barriers 141 return mach->barrier_data() != ZBarrierElided; 142 } 143 144 bool needs_livein_data() const { 145 return true; 146 } 147 148 void inc_trampoline_stubs_count() { 149 assert(_trampoline_stubs_count != INT_MAX, "Overflow"); 150 ++_trampoline_stubs_count; 151 } 152 153 int trampoline_stubs_count() { 154 return _trampoline_stubs_count; 155 } 156 157 void set_stubs_start_offset(int offset) { 158 _stubs_start_offset = offset; 159 } 160 161 int stubs_start_offset() { 162 return _stubs_start_offset; 163 } 164 }; 165 166 static ZBarrierSetC2State* barrier_set_state() { 167 return reinterpret_cast<ZBarrierSetC2State*>(Compile::current()->barrier_set_state()); 168 } 169 170 void ZBarrierStubC2::register_stub(ZBarrierStubC2* stub) { 171 if (!Compile::current()->output()->in_scratch_emit_size()) { 172 barrier_set_state()->stubs()->append(stub); 173 } 174 } 175 176 void ZBarrierStubC2::inc_trampoline_stubs_count() { 177 if (!Compile::current()->output()->in_scratch_emit_size()) { 178 barrier_set_state()->inc_trampoline_stubs_count(); 179 } 180 } 181 182 int ZBarrierStubC2::trampoline_stubs_count() { 183 return barrier_set_state()->trampoline_stubs_count(); 184 } 185 186 int ZBarrierStubC2::stubs_start_offset() { 187 return barrier_set_state()->stubs_start_offset(); 188 } 189 190 ZBarrierStubC2::ZBarrierStubC2(const MachNode* node) : BarrierStubC2(node) {} 191 192 ZLoadBarrierStubC2* ZLoadBarrierStubC2::create(const MachNode* node, Address ref_addr, Register ref) { 193 AARCH64_ONLY(fatal("Should use ZLoadBarrierStubC2Aarch64::create")); 194 ZLoadBarrierStubC2* const stub = new (Compile::current()->comp_arena()) ZLoadBarrierStubC2(node, ref_addr, ref); 195 register_stub(stub); 196 197 return stub; 198 } 199 200 ZLoadBarrierStubC2::ZLoadBarrierStubC2(const MachNode* node, Address ref_addr, Register ref) 201 : ZBarrierStubC2(node), 202 _ref_addr(ref_addr), 203 _ref(ref) { 204 assert_different_registers(ref, ref_addr.base()); 205 assert_different_registers(ref, ref_addr.index()); 206 // The runtime call updates the value of ref, so we should not spill and 207 // reload its outdated value. 208 dont_preserve(ref); 209 } 210 211 Address ZLoadBarrierStubC2::ref_addr() const { 212 return _ref_addr; 213 } 214 215 Register ZLoadBarrierStubC2::ref() const { 216 return _ref; 217 } 218 219 address ZLoadBarrierStubC2::slow_path() const { 220 const uint8_t barrier_data = _node->barrier_data(); 221 DecoratorSet decorators = DECORATORS_NONE; 222 if (barrier_data & ZBarrierStrong) { 223 decorators |= ON_STRONG_OOP_REF; 224 } 225 if (barrier_data & ZBarrierWeak) { 226 decorators |= ON_WEAK_OOP_REF; 227 } 228 if (barrier_data & ZBarrierPhantom) { 229 decorators |= ON_PHANTOM_OOP_REF; 230 } 231 if (barrier_data & ZBarrierNoKeepalive) { 232 decorators |= AS_NO_KEEPALIVE; 233 } 234 return ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators); 235 } 236 237 void ZLoadBarrierStubC2::emit_code(MacroAssembler& masm) { 238 ZBarrierSet::assembler()->generate_c2_load_barrier_stub(&masm, static_cast<ZLoadBarrierStubC2*>(this)); 239 } 240 241 ZStoreBarrierStubC2* ZStoreBarrierStubC2::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive) { 242 AARCH64_ONLY(fatal("Should use ZStoreBarrierStubC2Aarch64::create")); 243 ZStoreBarrierStubC2* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic, is_nokeepalive); 244 register_stub(stub); 245 246 return stub; 247 } 248 249 ZStoreBarrierStubC2::ZStoreBarrierStubC2(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, 250 bool is_native, bool is_atomic, bool is_nokeepalive) 251 : ZBarrierStubC2(node), 252 _ref_addr(ref_addr), 253 _new_zaddress(new_zaddress), 254 _new_zpointer(new_zpointer), 255 _is_native(is_native), 256 _is_atomic(is_atomic), 257 _is_nokeepalive(is_nokeepalive) {} 258 259 Address ZStoreBarrierStubC2::ref_addr() const { 260 return _ref_addr; 261 } 262 263 Register ZStoreBarrierStubC2::new_zaddress() const { 264 return _new_zaddress; 265 } 266 267 Register ZStoreBarrierStubC2::new_zpointer() const { 268 return _new_zpointer; 269 } 270 271 bool ZStoreBarrierStubC2::is_native() const { 272 return _is_native; 273 } 274 275 bool ZStoreBarrierStubC2::is_atomic() const { 276 return _is_atomic; 277 } 278 279 bool ZStoreBarrierStubC2::is_nokeepalive() const { 280 return _is_nokeepalive; 281 } 282 283 void ZStoreBarrierStubC2::emit_code(MacroAssembler& masm) { 284 ZBarrierSet::assembler()->generate_c2_store_barrier_stub(&masm, static_cast<ZStoreBarrierStubC2*>(this)); 285 } 286 287 uint ZBarrierSetC2::estimated_barrier_size(const Node* node) const { 288 uint8_t barrier_data = MemNode::barrier_data(node); 289 assert(barrier_data != 0, "should be a barrier node"); 290 uint uncolor_or_color_size = node->is_Load() ? 1 : 2; 291 if ((barrier_data & ZBarrierElided) != 0) { 292 return uncolor_or_color_size; 293 } 294 // A compare and branch corresponds to approximately four fast-path Ideal 295 // nodes (Cmp, Bool, If, If projection). The slow path (If projection and 296 // runtime call) is excluded since the corresponding code is laid out 297 // separately and does not directly affect performance. 298 return uncolor_or_color_size + 4; 299 } 300 301 void* ZBarrierSetC2::create_barrier_state(Arena* comp_arena) const { 302 return new (comp_arena) ZBarrierSetC2State(comp_arena); 303 } 304 305 void ZBarrierSetC2::late_barrier_analysis() const { 306 compute_liveness_at_stubs(); 307 analyze_dominating_barriers(); 308 } 309 310 void ZBarrierSetC2::emit_stubs(CodeBuffer& cb) const { 311 MacroAssembler masm(&cb); 312 GrowableArray<ZBarrierStubC2*>* const stubs = barrier_set_state()->stubs(); 313 barrier_set_state()->set_stubs_start_offset(masm.offset()); 314 315 for (int i = 0; i < stubs->length(); i++) { 316 // Make sure there is enough space in the code buffer 317 if (cb.insts()->maybe_expand_to_ensure_remaining(PhaseOutput::max_inst_gcstub_size()) && cb.blob() == nullptr) { 318 ciEnv::current()->record_failure("CodeCache is full"); 319 return; 320 } 321 322 stubs->at(i)->emit_code(masm); 323 } 324 325 masm.flush(); 326 } 327 328 int ZBarrierSetC2::estimate_stub_size() const { 329 Compile* const C = Compile::current(); 330 BufferBlob* const blob = C->output()->scratch_buffer_blob(); 331 GrowableArray<ZBarrierStubC2*>* const stubs = barrier_set_state()->stubs(); 332 int size = 0; 333 334 for (int i = 0; i < stubs->length(); i++) { 335 CodeBuffer cb(blob->content_begin(), checked_cast<CodeBuffer::csize_t>((address)C->output()->scratch_locs_memory() - blob->content_begin())); 336 MacroAssembler masm(&cb); 337 stubs->at(i)->emit_code(masm); 338 size += cb.insts_size(); 339 } 340 341 return size; 342 } 343 344 static void set_barrier_data(C2Access& access) { 345 if (!ZBarrierSet::barrier_needed(access.decorators(), access.type())) { 346 return; 347 } 348 349 if (access.decorators() & C2_TIGHTLY_COUPLED_ALLOC) { 350 access.set_barrier_data(ZBarrierElided); 351 return; 352 } 353 354 uint8_t barrier_data = 0; 355 356 if (access.decorators() & ON_PHANTOM_OOP_REF) { 357 barrier_data |= ZBarrierPhantom; 358 } else if (access.decorators() & ON_WEAK_OOP_REF) { 359 barrier_data |= ZBarrierWeak; 360 } else { 361 barrier_data |= ZBarrierStrong; 362 } 363 364 if (access.decorators() & IN_NATIVE) { 365 barrier_data |= ZBarrierNative; 366 } 367 368 if (access.decorators() & AS_NO_KEEPALIVE) { 369 barrier_data |= ZBarrierNoKeepalive; 370 } 371 372 access.set_barrier_data(barrier_data); 373 } 374 375 Node* ZBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const { 376 set_barrier_data(access); 377 return BarrierSetC2::store_at_resolved(access, val); 378 } 379 380 Node* ZBarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const { 381 set_barrier_data(access); 382 return BarrierSetC2::load_at_resolved(access, val_type); 383 } 384 385 Node* ZBarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val, 386 Node* new_val, const Type* val_type) const { 387 set_barrier_data(access); 388 return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, val_type); 389 } 390 391 Node* ZBarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val, 392 Node* new_val, const Type* value_type) const { 393 set_barrier_data(access); 394 return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type); 395 } 396 397 Node* ZBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* val_type) const { 398 set_barrier_data(access); 399 return BarrierSetC2::atomic_xchg_at_resolved(access, new_val, val_type); 400 } 401 402 bool ZBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, 403 bool is_clone, bool is_clone_instance, 404 ArrayCopyPhase phase) const { 405 if (phase == ArrayCopyPhase::Parsing) { 406 return false; 407 } 408 if (phase == ArrayCopyPhase::Optimization) { 409 return is_clone_instance; 410 } 411 // else ArrayCopyPhase::Expansion 412 return type == T_OBJECT || type == T_ARRAY; 413 } 414 415 #define XTOP LP64_ONLY(COMMA phase->top()) 416 417 void ZBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const { 418 Node* const src = ac->in(ArrayCopyNode::Src); 419 const TypeAryPtr* const ary_ptr = src->get_ptr_type()->isa_aryptr(); 420 421 if (ac->is_clone_array() && ary_ptr != nullptr) { 422 BasicType bt = ary_ptr->elem()->array_element_basic_type(); 423 if (is_reference_type(bt)) { 424 // Clone object array 425 bt = T_OBJECT; 426 } else { 427 // Clone primitive array 428 bt = T_LONG; 429 } 430 431 Node* const ctrl = ac->in(TypeFunc::Control); 432 Node* const mem = ac->in(TypeFunc::Memory); 433 Node* const src = ac->in(ArrayCopyNode::Src); 434 Node* src_offset = ac->in(ArrayCopyNode::SrcPos); 435 Node* const dest = ac->in(ArrayCopyNode::Dest); 436 Node* dest_offset = ac->in(ArrayCopyNode::DestPos); 437 Node* length = ac->in(ArrayCopyNode::Length); 438 439 if (bt == T_OBJECT) { 440 // BarrierSetC2::clone sets the offsets via BarrierSetC2::arraycopy_payload_base_offset 441 // which 8-byte aligns them to allow for word size copies. Make sure the offsets point 442 // to the first element in the array when cloning object arrays. Otherwise, load 443 // barriers are applied to parts of the header. Also adjust the length accordingly. 444 assert(src_offset == dest_offset, "should be equal"); 445 const jlong offset = src_offset->get_long(); 446 if (offset != arrayOopDesc::base_offset_in_bytes(T_OBJECT)) { 447 assert(!UseCompressedClassPointers || UseCompactObjectHeaders, "should only happen without compressed class pointers"); 448 assert((arrayOopDesc::base_offset_in_bytes(T_OBJECT) - offset) == BytesPerLong, "unexpected offset"); 449 length = phase->transform_later(new SubLNode(length, phase->longcon(1))); // Size is in longs 450 src_offset = phase->longcon(arrayOopDesc::base_offset_in_bytes(T_OBJECT)); 451 dest_offset = src_offset; 452 } 453 } 454 Node* const payload_src = phase->basic_plus_adr(src, src_offset); 455 Node* const payload_dst = phase->basic_plus_adr(dest, dest_offset); 456 457 const char* copyfunc_name = "arraycopy"; 458 const address copyfunc_addr = phase->basictype2arraycopy(bt, nullptr, nullptr, true, copyfunc_name, true); 459 460 const TypePtr* const raw_adr_type = TypeRawPtr::BOTTOM; 461 const TypeFunc* const call_type = OptoRuntime::fast_arraycopy_Type(); 462 463 Node* const call = phase->make_leaf_call(ctrl, mem, call_type, copyfunc_addr, copyfunc_name, raw_adr_type, payload_src, payload_dst, length XTOP); 464 phase->transform_later(call); 465 466 phase->igvn().replace_node(ac, call); 467 return; 468 } 469 470 // Clone instance or array where 'src' is only known to be an object (ary_ptr 471 // is null). This can happen in bytecode generated dynamically to implement 472 // reflective array clones. 473 clone_in_runtime(phase, ac, ZBarrierSetRuntime::clone_addr(), "ZBarrierSetRuntime::clone"); 474 } 475 476 #undef XTOP 477 478 // == Dominating barrier elision == 479 480 static bool block_has_safepoint(const Block* block, uint from, uint to) { 481 for (uint i = from; i < to; i++) { 482 if (block->get_node(i)->is_MachSafePoint()) { 483 // Safepoint found 484 return true; 485 } 486 } 487 488 // Safepoint not found 489 return false; 490 } 491 492 static bool block_has_safepoint(const Block* block) { 493 return block_has_safepoint(block, 0, block->number_of_nodes()); 494 } 495 496 static uint block_index(const Block* block, const Node* node) { 497 for (uint j = 0; j < block->number_of_nodes(); ++j) { 498 if (block->get_node(j) == node) { 499 return j; 500 } 501 } 502 ShouldNotReachHere(); 503 return 0; 504 } 505 506 // Look through various node aliases 507 static const Node* look_through_node(const Node* node) { 508 while (node != nullptr) { 509 const Node* new_node = node; 510 if (node->is_Mach()) { 511 const MachNode* const node_mach = node->as_Mach(); 512 if (node_mach->ideal_Opcode() == Op_CheckCastPP) { 513 new_node = node->in(1); 514 } 515 if (node_mach->is_SpillCopy()) { 516 new_node = node->in(1); 517 } 518 } 519 if (new_node == node || new_node == nullptr) { 520 break; 521 } else { 522 node = new_node; 523 } 524 } 525 526 return node; 527 } 528 529 // Whether the given offset is undefined. 530 static bool is_undefined(intptr_t offset) { 531 return offset == Type::OffsetTop; 532 } 533 534 // Whether the given offset is unknown. 535 static bool is_unknown(intptr_t offset) { 536 return offset == Type::OffsetBot; 537 } 538 539 // Whether the given offset is concrete (defined and compile-time known). 540 static bool is_concrete(intptr_t offset) { 541 return !is_undefined(offset) && !is_unknown(offset); 542 } 543 544 // Compute base + offset components of the memory address accessed by mach. 545 // Return a node representing the base address, or null if the base cannot be 546 // found or the offset is undefined or a concrete negative value. If a non-null 547 // base is returned, the offset is a concrete, nonnegative value or unknown. 548 static const Node* get_base_and_offset(const MachNode* mach, intptr_t& offset) { 549 const TypePtr* adr_type = nullptr; 550 offset = 0; 551 const Node* base = mach->get_base_and_disp(offset, adr_type); 552 553 if (base == nullptr || base == NodeSentinel) { 554 return nullptr; 555 } 556 557 if (offset == 0 && base->is_Mach() && base->as_Mach()->ideal_Opcode() == Op_AddP) { 558 // The memory address is computed by 'base' and fed to 'mach' via an 559 // indirect memory operand (indicated by offset == 0). The ultimate base and 560 // offset can be fetched directly from the inputs and Ideal type of 'base'. 561 const TypeOopPtr* oopptr = base->bottom_type()->isa_oopptr(); 562 if (oopptr == nullptr) return nullptr; 563 offset = oopptr->offset(); 564 // Even if 'base' is not an Ideal AddP node anymore, Matcher::ReduceInst() 565 // guarantees that the base address is still available at the same slot. 566 base = base->in(AddPNode::Base); 567 assert(base != nullptr, ""); 568 } 569 570 if (is_undefined(offset) || (is_concrete(offset) && offset < 0)) { 571 return nullptr; 572 } 573 574 return look_through_node(base); 575 } 576 577 // Whether a phi node corresponds to an array allocation. 578 // This test is incomplete: in some edge cases, it might return false even 579 // though the node does correspond to an array allocation. 580 static bool is_array_allocation(const Node* phi) { 581 precond(phi->is_Phi()); 582 // Check whether phi has a successor cast (CheckCastPP) to Java array pointer, 583 // possibly below spill copies and other cast nodes. Limit the exploration to 584 // a single path from the phi node consisting of these node types. 585 const Node* current = phi; 586 while (true) { 587 const Node* next = nullptr; 588 for (DUIterator_Fast imax, i = current->fast_outs(imax); i < imax; i++) { 589 if (!current->fast_out(i)->isa_Mach()) { 590 continue; 591 } 592 const MachNode* succ = current->fast_out(i)->as_Mach(); 593 if (succ->ideal_Opcode() == Op_CheckCastPP) { 594 if (succ->get_ptr_type()->isa_aryptr()) { 595 // Cast to Java array pointer: phi corresponds to an array allocation. 596 return true; 597 } 598 // Other cast: record as candidate for further exploration. 599 next = succ; 600 } else if (succ->is_SpillCopy() && next == nullptr) { 601 // Spill copy, and no better candidate found: record as candidate. 602 next = succ; 603 } 604 } 605 if (next == nullptr) { 606 // No evidence found that phi corresponds to an array allocation, and no 607 // candidates available to continue exploring. 608 return false; 609 } 610 // Continue exploring from the best candidate found. 611 current = next; 612 } 613 ShouldNotReachHere(); 614 } 615 616 // Match the phi node that connects a TLAB allocation fast path with its slowpath 617 static bool is_allocation(const Node* node) { 618 if (node->req() != 3) { 619 return false; 620 } 621 const Node* const fast_node = node->in(2); 622 if (!fast_node->is_Mach()) { 623 return false; 624 } 625 const MachNode* const fast_mach = fast_node->as_Mach(); 626 if (fast_mach->ideal_Opcode() != Op_LoadP) { 627 return false; 628 } 629 const TypePtr* const adr_type = nullptr; 630 intptr_t offset; 631 const Node* const base = get_base_and_offset(fast_mach, offset); 632 if (base == nullptr || !base->is_Mach() || !is_concrete(offset)) { 633 return false; 634 } 635 const MachNode* const base_mach = base->as_Mach(); 636 if (base_mach->ideal_Opcode() != Op_ThreadLocal) { 637 return false; 638 } 639 return offset == in_bytes(Thread::tlab_top_offset()); 640 } 641 642 static void elide_mach_barrier(MachNode* mach) { 643 mach->set_barrier_data(ZBarrierElided); 644 } 645 646 void ZBarrierSetC2::analyze_dominating_barriers_impl(Node_List& accesses, Node_List& access_dominators) const { 647 Compile* const C = Compile::current(); 648 PhaseCFG* const cfg = C->cfg(); 649 650 for (uint i = 0; i < accesses.size(); i++) { 651 MachNode* const access = accesses.at(i)->as_Mach(); 652 intptr_t access_offset; 653 const Node* const access_obj = get_base_and_offset(access, access_offset); 654 Block* const access_block = cfg->get_block_for_node(access); 655 const uint access_index = block_index(access_block, access); 656 657 if (access_obj == nullptr) { 658 // No information available 659 continue; 660 } 661 662 for (uint j = 0; j < access_dominators.size(); j++) { 663 const Node* const mem = access_dominators.at(j); 664 if (mem->is_Phi()) { 665 // Allocation node 666 if (mem != access_obj) { 667 continue; 668 } 669 if (is_unknown(access_offset) && !is_array_allocation(mem)) { 670 // The accessed address has an unknown offset, but the allocated 671 // object cannot be determined to be an array. Avoid eliding in this 672 // case, to be on the safe side. 673 continue; 674 } 675 assert((is_concrete(access_offset) && access_offset >= 0) || (is_unknown(access_offset) && is_array_allocation(mem)), 676 "candidate allocation-dominated access offsets must be either concrete and nonnegative, or unknown (for array allocations only)"); 677 } else { 678 // Access node 679 const MachNode* const mem_mach = mem->as_Mach(); 680 intptr_t mem_offset; 681 const Node* const mem_obj = get_base_and_offset(mem_mach, mem_offset); 682 683 if (mem_obj == nullptr || 684 !is_concrete(access_offset) || 685 !is_concrete(mem_offset)) { 686 // No information available 687 continue; 688 } 689 690 if (mem_obj != access_obj || mem_offset != access_offset) { 691 // Not the same addresses, not a candidate 692 continue; 693 } 694 assert(is_concrete(access_offset) && access_offset >= 0, 695 "candidate non-allocation-dominated access offsets must be concrete and nonnegative"); 696 } 697 698 Block* mem_block = cfg->get_block_for_node(mem); 699 const uint mem_index = block_index(mem_block, mem); 700 701 if (access_block == mem_block) { 702 // Earlier accesses in the same block 703 if (mem_index < access_index && !block_has_safepoint(mem_block, mem_index + 1, access_index)) { 704 elide_mach_barrier(access); 705 } 706 } else if (mem_block->dominates(access_block)) { 707 // Dominating block? Look around for safepoints 708 ResourceMark rm; 709 Block_List stack; 710 VectorSet visited; 711 stack.push(access_block); 712 bool safepoint_found = block_has_safepoint(access_block); 713 while (!safepoint_found && stack.size() > 0) { 714 const Block* const block = stack.pop(); 715 if (visited.test_set(block->_pre_order)) { 716 continue; 717 } 718 if (block_has_safepoint(block)) { 719 safepoint_found = true; 720 break; 721 } 722 if (block == mem_block) { 723 continue; 724 } 725 726 // Push predecessor blocks 727 for (uint p = 1; p < block->num_preds(); ++p) { 728 Block* const pred = cfg->get_block_for_node(block->pred(p)); 729 stack.push(pred); 730 } 731 } 732 733 if (!safepoint_found) { 734 elide_mach_barrier(access); 735 } 736 } 737 } 738 } 739 } 740 741 void ZBarrierSetC2::analyze_dominating_barriers() const { 742 ResourceMark rm; 743 Compile* const C = Compile::current(); 744 PhaseCFG* const cfg = C->cfg(); 745 746 Node_List loads; 747 Node_List load_dominators; 748 749 Node_List stores; 750 Node_List store_dominators; 751 752 Node_List atomics; 753 Node_List atomic_dominators; 754 755 // Step 1 - Find accesses and allocations, and track them in lists 756 for (uint i = 0; i < cfg->number_of_blocks(); ++i) { 757 const Block* const block = cfg->get_block(i); 758 for (uint j = 0; j < block->number_of_nodes(); ++j) { 759 Node* const node = block->get_node(j); 760 if (node->is_Phi()) { 761 if (is_allocation(node)) { 762 load_dominators.push(node); 763 store_dominators.push(node); 764 // An allocation can't be considered to "dominate" an atomic operation. 765 // For example a CAS requires the memory location to be store-good. 766 // When you have a dominating store or atomic instruction, that is 767 // indeed ensured to be the case. However, as for allocations, the 768 // initialized memory location could be raw null, which isn't store-good. 769 } 770 continue; 771 } else if (!node->is_Mach()) { 772 continue; 773 } 774 775 MachNode* const mach = node->as_Mach(); 776 switch (mach->ideal_Opcode()) { 777 case Op_LoadP: 778 if ((mach->barrier_data() & ZBarrierStrong) != 0 && 779 (mach->barrier_data() & ZBarrierNoKeepalive) == 0) { 780 loads.push(mach); 781 load_dominators.push(mach); 782 } 783 break; 784 case Op_StoreP: 785 if (mach->barrier_data() != 0) { 786 stores.push(mach); 787 load_dominators.push(mach); 788 store_dominators.push(mach); 789 atomic_dominators.push(mach); 790 } 791 break; 792 case Op_CompareAndExchangeP: 793 case Op_CompareAndSwapP: 794 case Op_GetAndSetP: 795 if (mach->barrier_data() != 0) { 796 atomics.push(mach); 797 load_dominators.push(mach); 798 store_dominators.push(mach); 799 atomic_dominators.push(mach); 800 } 801 break; 802 803 default: 804 break; 805 } 806 } 807 } 808 809 // Step 2 - Find dominating accesses or allocations for each access 810 analyze_dominating_barriers_impl(loads, load_dominators); 811 analyze_dominating_barriers_impl(stores, store_dominators); 812 analyze_dominating_barriers_impl(atomics, atomic_dominators); 813 } 814 815 void ZBarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const { 816 eliminate_gc_barrier_data(node); 817 } 818 819 void ZBarrierSetC2::eliminate_gc_barrier_data(Node* node) const { 820 if (node->is_LoadStore()) { 821 LoadStoreNode* loadstore = node->as_LoadStore(); 822 loadstore->set_barrier_data(ZBarrierElided); 823 } else if (node->is_Mem()) { 824 MemNode* mem = node->as_Mem(); 825 mem->set_barrier_data(ZBarrierElided); 826 } 827 } 828 829 #ifndef PRODUCT 830 void ZBarrierSetC2::dump_barrier_data(const MachNode* mach, outputStream* st) const { 831 if ((mach->barrier_data() & ZBarrierStrong) != 0) { 832 st->print("strong "); 833 } 834 if ((mach->barrier_data() & ZBarrierWeak) != 0) { 835 st->print("weak "); 836 } 837 if ((mach->barrier_data() & ZBarrierPhantom) != 0) { 838 st->print("phantom "); 839 } 840 if ((mach->barrier_data() & ZBarrierNoKeepalive) != 0) { 841 st->print("nokeepalive "); 842 } 843 if ((mach->barrier_data() & ZBarrierNative) != 0) { 844 st->print("native "); 845 } 846 if ((mach->barrier_data() & ZBarrierElided) != 0) { 847 st->print("elided "); 848 } 849 } 850 #endif // !PRODUCT