1 /*
2 * Copyright (c) 2018, 2026, Red Hat, Inc. All rights reserved.
3 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #include "classfile/javaClasses.inline.hpp"
27 #include "gc/shared/barrierSet.hpp"
28 #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
29 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
30 #include "gc/shenandoah/shenandoahHeap.hpp"
31 #include "gc/shenandoah/shenandoahRuntime.hpp"
32 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
33 #include "opto/arraycopynode.hpp"
34 #include "opto/escape.hpp"
35 #include "opto/graphKit.hpp"
36 #include "opto/idealKit.hpp"
37 #include "opto/macro.hpp"
38 #include "opto/narrowptrnode.hpp"
39 #include "opto/output.hpp"
40 #include "opto/rootnode.hpp"
41 #include "opto/runtime.hpp"
42
43 ShenandoahBarrierSetC2State::ShenandoahBarrierSetC2State(Arena* comp_arena) :
44 BarrierSetC2State(comp_arena),
45 _stubs(new (comp_arena) GrowableArray<ShenandoahBarrierStubC2*>(comp_arena, 8, 0, nullptr)),
46 _trampoline_stubs_count(0),
47 _stubs_start_offset(0),
48 _stubs_current_total_size(0) {
49 }
50
51 static void set_barrier_data(C2Access& access, bool load, bool store) {
52 if (!access.is_oop()) {
53 return;
54 }
55
56 DecoratorSet decorators = access.decorators();
57 bool tightly_coupled = (decorators & C2_TIGHTLY_COUPLED_ALLOC) != 0;
58 bool in_heap = (decorators & IN_HEAP) != 0;
59 bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
60 bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
61
62 if (tightly_coupled) {
63 access.set_barrier_data(ShenandoahBitElided);
64 return;
65 }
66
67 uint8_t barrier_data = 0;
68
69 if (load) {
70 if (ShenandoahLoadRefBarrier) {
71 if (on_phantom) {
72 barrier_data |= ShenandoahBitPhantom;
73 } else if (on_weak) {
74 barrier_data |= ShenandoahBitWeak;
75 } else {
76 barrier_data |= ShenandoahBitStrong;
77 }
78 }
79 }
80
81 if (store) {
82 if (ShenandoahSATBBarrier) {
83 barrier_data |= ShenandoahBitKeepAlive;
84 }
85 if (ShenandoahCardBarrier && in_heap) {
86 barrier_data |= ShenandoahBitCardMark;
87 }
88 }
89
90 if (!in_heap) {
91 barrier_data |= ShenandoahBitNative;
92 }
93
94 access.set_barrier_data(barrier_data);
95 }
96
97 Node* ShenandoahBarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const {
98 // 1: Non-reference load, no additional barrier is needed
99 if (!access.is_oop()) {
100 return BarrierSetC2::load_at_resolved(access, val_type);
101 }
102
103 // 2. Set barrier data for load
104 set_barrier_data(access, /* load = */ true, /* store = */ false);
105
106 // 3. Correction: If we are reading the value of the referent field of
107 // a Reference object, we need to record the referent resurrection.
108 DecoratorSet decorators = access.decorators();
109 bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
110 bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
111 bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0;
112 bool needs_keepalive = ((on_weak || on_phantom) && !no_keepalive);
113 if (needs_keepalive) {
114 uint8_t barriers = access.barrier_data() | (ShenandoahSATBBarrier ? ShenandoahBitKeepAlive : 0);
115 access.set_barrier_data(barriers);
116 }
117
118 return BarrierSetC2::load_at_resolved(access, val_type);
119 }
120
121 Node* ShenandoahBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const {
122 // 1: Non-reference store, no additional barrier is needed
123 if (!access.is_oop()) {
124 return BarrierSetC2::store_at_resolved(access, val);
125 }
126
127 // 2. Set barrier data for store
128 set_barrier_data(access, /* load = */ false, /* store = */ true);
129
130 // 3. Correction: avoid keep-alive barriers that should not do keep-alive.
131 DecoratorSet decorators = access.decorators();
132 bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0;
133 if (no_keepalive) {
134 access.set_barrier_data(access.barrier_data() & ~ShenandoahBitKeepAlive);
135 }
136
137 return BarrierSetC2::store_at_resolved(access, val);
138 }
139
140 Node* ShenandoahBarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
141 Node* new_val, const Type* value_type) const {
142 set_barrier_data(access, /* load = */ true, /* store = */ true);
143 return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type);
144 }
145
146 Node* ShenandoahBarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
147 Node* new_val, const Type* value_type) const {
148 set_barrier_data(access, /* load = */ true, /* store = */ true);
149 return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);
150 }
151
152 Node* ShenandoahBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* val, const Type* value_type) const {
153 set_barrier_data(access, /* load = */ true, /* store = */ true);
154 return BarrierSetC2::atomic_xchg_at_resolved(access, val, value_type);
155 }
156
157 bool ShenandoahBarrierSetC2::is_Load(int opcode) {
158 switch (opcode) {
159 case Op_LoadN:
160 case Op_LoadP:
161 return true;
162 default:
163 return false;
164 }
165 }
166
167 bool ShenandoahBarrierSetC2::is_Store(int opcode) {
168 switch (opcode) {
169 case Op_StoreN:
170 case Op_StoreP:
171 return true;
172 default:
173 return false;
174 }
175 }
176
177 bool ShenandoahBarrierSetC2::is_LoadStore(int opcode) {
178 switch (opcode) {
179 case Op_CompareAndExchangeN:
180 case Op_CompareAndExchangeP:
181 case Op_WeakCompareAndSwapN:
182 case Op_WeakCompareAndSwapP:
183 case Op_CompareAndSwapN:
184 case Op_CompareAndSwapP:
185 case Op_GetAndSetP:
186 case Op_GetAndSetN:
187 return true;
188 default:
189 return false;
190 }
191 }
192
193 bool ShenandoahBarrierSetC2::can_remove_load_barrier(Node* root) {
194 // Check if all outs feed into nodes that do not expose the oops to the rest
195 // of the runtime system. In this case, we can elide the LRB barrier. We bail
196 // out with false at the first sight of trouble.
197
198 ResourceMark rm;
199 VectorSet visited;
200 Node_List worklist;
201 worklist.push(root);
202
203 while (worklist.size() > 0) {
204 Node* n = worklist.pop();
205 if (visited.test_set(n->_idx)) {
206 continue;
207 }
208
209 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
210 Node* out = n->fast_out(i);
211 switch (out->Opcode()) {
212 case Op_Phi:
213 case Op_EncodeP:
214 case Op_DecodeN:
215 case Op_CastPP:
216 case Op_CheckCastPP:
217 case Op_AddP: {
218 // Transitive node, check if any other outs are doing anything troublesome.
219 worklist.push(out);
220 break;
221 }
222
223 case Op_LoadRange: {
224 // Array length is the same in all copies.
225 break;
226 }
227
228 case Op_LoadKlass: {
229 // Klass is the same in all copies.
230 // We would have liked to assert -UCOH, but there are legitimate klass
231 // loads from native Klass* instances, which are also safe under +UCOH.
232 break;
233 }
234
235 case Op_LoadNKlass: {
236 // Similar to above, but LoadNKlass is only safe without +UCOH.
237 // With +UCOH, it loads from mark word, which clashes with forwarding pointers.
238 if (!UseCompactObjectHeaders) {
239 break;
240 }
241 return false;
242 }
243
244 case Op_CmpN: {
245 if (out->in(1) == n &&
246 out->in(2)->Opcode() == Op_ConN &&
247 out->in(2)->get_narrowcon() == 0) {
248 // Null check, no oop is exposed.
249 break;
250 }
251 if (out->in(2) == n &&
252 out->in(1)->Opcode() == Op_ConN &&
253 out->in(1)->get_narrowcon() == 0) {
254 // Null check, no oop is exposed.
255 break;
256 }
257 return false;
258 }
259
260 case Op_CmpP: {
261 if (out->in(1) == n &&
262 out->in(2)->Opcode() == Op_ConP &&
263 out->in(2)->get_ptr() == 0) {
264 // Null check, no oop is exposed.
265 break;
266 }
267 if (out->in(2) == n &&
268 out->in(1)->Opcode() == Op_ConP &&
269 out->in(1)->get_ptr() == 0) {
270 // Null check, no oop is exposed.
271 break;
272 }
273 return false;
274 }
275
276 case Op_CallStaticJava: {
277 if (out->as_CallStaticJava()->is_uncommon_trap()) {
278 // Local feeds into uncommon trap. Deopt machinery handles barriers itself.
279 break;
280 }
281 return false;
282 }
283
284 default: {
285 // Paranoidly distrust any other nodes.
286 return false;
287 }
288 }
289 }
290 }
291
292 // Nothing troublesome found.
293 return true;
294 }
295
296 uint8_t ShenandoahBarrierSetC2::refine_load(Node* n, uint8_t bd) {
297 assert(ShenandoahElideIdealBarriers, "Checked by caller");
298 assert(bd != 0, "Checked by caller");
299
300 // Do not touch weak loads at all: they are responsible for shielding from
301 // Reference.referent resurrection.
302 if ((bd & (ShenandoahBitWeak | ShenandoahBitPhantom)) != 0) {
303 return bd;
304 }
305
306 if (((bd & ShenandoahBitStrong) != 0) && can_remove_load_barrier(n)) {
307 bd &= ~ShenandoahBitStrong;
308 }
309
310 return bd;
311 }
312
313 uint8_t ShenandoahBarrierSetC2::refine_store(Node* n, uint8_t bd) {
314 assert(ShenandoahElideIdealBarriers, "Checked by caller");
315 assert(bd != 0, "Checked by caller");
316 assert(n->is_Mem() || n->is_LoadStore(), "Sanity");
317
318 const Node* newval = n->in(MemNode::ValueIn);
319 assert(newval != nullptr, "Should be present");
320
321 // Type system tells us something about nullity?
322 const Type* newval_bottom = newval->bottom_type();
323 assert(newval_bottom->isa_oopptr() || newval_bottom->isa_narrowoop() ||
324 newval_bottom == TypePtr::NULL_PTR, "Should be an oop store");
325 const TypePtr* newval_type = newval_bottom->make_ptr();
326 assert(newval_type != nullptr, "Should have been filtered before");
327 TypePtr::PTR newval_type_ptr = newval_type->ptr();
328 if (newval_type_ptr == TypePtr::Null) {
329 bd &= ~ShenandoahBitNotNull;
330 // Card table barrier is not needed if we store null.
331 bd &= ~ShenandoahBitCardMark;
332 } else if (newval_type_ptr == TypePtr::NotNull) {
333 // Definitely not null.
334 bd |= ShenandoahBitNotNull;
335 }
336
337 return bd;
338 }
339
340 void ShenandoahBarrierSetC2::final_refinement(Compile* compile) const {
341 ResourceMark rm;
342 Unique_Node_List wq;
343
344 RootNode* root = compile->root();
345 wq.push(root);
346
347 // Also seed the outs to capture nodes are not reachable from in()-s, e.g. endless loops.
348 for (DUIterator_Fast imax, i = root->fast_outs(imax); i < imax; i++) {
349 Node* m = root->fast_out(i);
350 wq.push(m);
351 }
352
353 for (uint next = 0; next < wq.size(); next++) {
354 Node* n = wq.at(next);
355
356 assert(!n->is_Mach(), "No Mach nodes here yet");
357
358 int opc = n->Opcode();
359 bool is_load = is_Load(opc);
360 bool is_store = is_Store(opc);
361 bool is_load_store = is_LoadStore(opc);
362
363 uint8_t orig_bd = 0;
364 if (is_load_store) {
365 orig_bd = n->as_LoadStore()->barrier_data();
366 } else if (is_load || is_store) {
367 orig_bd = n->as_Mem()->barrier_data();
368 }
369
370 uint8_t bd = orig_bd;
371 if (ShenandoahElideIdealBarriers && bd != 0) {
372 // Note: we cannot apply load optimizations to LoadStores,
373 // because their load barriers are needed for fixups.
374 if (is_load) {
375 bd = refine_load(n, bd);
376 }
377 if (is_store || is_load_store) {
378 bd = refine_store(n, bd);
379 }
380 }
381
382 // If there are no real barrier flags on the node, strip away additional fluff.
383 // Matcher does not care about this, and we would like to avoid invoking "barrier_data() != 0"
384 // rules when the only flags are the irrelevant fluff.
385 if ((bd != 0) && (bd & ShenandoahBitsReal) == 0) {
386 bd = 0;
387 }
388
389 if (bd != orig_bd) {
390 if (is_load_store) {
391 n->as_LoadStore()->set_barrier_data(bd);
392 } else {
393 n->as_Mem()->set_barrier_data(bd);
394 }
395 }
396
397 for (uint j = 0; j < n->req(); j++) {
398 Node* in = n->in(j);
399 if (in != nullptr) {
400 wq.push(in);
401 }
402 }
403 }
404 }
405
406 // Support for macro expanded GC barriers
407 void ShenandoahBarrierSetC2::eliminate_gc_barrier_data(Node* node) const {
408 if (node->is_LoadStore()) {
409 LoadStoreNode* loadstore = node->as_LoadStore();
410 loadstore->set_barrier_data(0);
411 } else if (node->is_Mem()) {
412 MemNode* mem = node->as_Mem();
413 mem->set_barrier_data(0);
414 }
415 }
416
417 void ShenandoahBarrierSetC2::eliminate_gc_barrier(PhaseIterGVN* macro, Node* node) const {
418 eliminate_gc_barrier_data(node);
419 }
420
421 void ShenandoahBarrierSetC2::elide_dominated_barrier(MachNode* node, MachNode* dominator) const {
422 uint8_t orig_bd = node->barrier_data();
423 if (orig_bd == 0) {
424 // Nothing to do.
425 return;
426 }
427
428 uint8_t bd = orig_bd;
429 int node_opcode = node->ideal_Opcode();
430
431 if (dominator == nullptr) {
432 // Must be allocation node.
433 if (is_Load(node_opcode) || is_LoadStore(node_opcode)) {
434 // Loads from recent allocations do not need LRBs.
435 bd &= ~ShenandoahBitStrong;
436 }
437 if (is_Store(node_opcode) || is_LoadStore(node_opcode)) {
438 // Stores to recent allocations do not need KA or CM.
439 bd &= ~ShenandoahBitKeepAlive;
440 bd &= ~ShenandoahBitCardMark;
441 }
442 } else {
443 // LoadStores do not get these optimizations, since their LRBs
444 // are required for fixups.
445 if (is_Load(node_opcode) || is_Store(node_opcode)) {
446 int dom_opcode = dominator->ideal_Opcode();
447 uint8_t dom_bd = dominator->barrier_data();
448
449 if (is_Load(dom_opcode) || is_LoadStore(dom_opcode)) {
450 // If dominating load is set up to perform LRB fixups, no further LRB is needed.
451 if ((dom_bd & ShenandoahBitStrong) != 0) {
452 bd &= ~ShenandoahBitStrong;
453 }
454 }
455 if (is_Store(dom_opcode)) {
456 // Dominating store has stored the good ref, no LRB is needed.
457 bd &= ~ShenandoahBitStrong;
458 }
459 }
460 }
461
462 if (orig_bd != bd) {
463 #ifdef ASSERT
464 PhaseRegAlloc* ra = Compile::current()->regalloc();
465 uint old_size = node->size(ra);
466 #endif
467 // We are already in final output. This means all nodes have already matched,
468 // and we are about to use Shenandoah match rules with stripped-down barriers.
469 // In this case, we must *not* strip non-real bits, because it would shift the
470 // encoding.
471 node->set_barrier_data(bd);
472 #ifdef ASSERT
473 uint new_size = node->size(ra);
474 assert(new_size <= old_size, "Node must not grow: %u -> %u", old_size, new_size);
475 #endif
476 }
477 }
478
479 void ShenandoahBarrierSetC2::analyze_dominating_barriers() const {
480 if (!ShenandoahElideMachBarriers) {
481 return;
482 }
483
484 ResourceMark rm;
485 Node_List accesses, dominators;
486
487 PhaseCFG* const cfg = Compile::current()->cfg();
488 for (uint i = 0; i < cfg->number_of_blocks(); ++i) {
489 const Block* const block = cfg->get_block(i);
490 for (uint j = 0; j < block->number_of_nodes(); ++j) {
491 Node* const node = block->get_node(j);
492
493 // Everything that happens in allocations does not need barriers.
494 // Record them for dominance analysis.
495 if (node->is_Phi() && is_allocation(node)) {
496 dominators.push(node);
497 continue;
498 }
499
500 if (!node->is_Mach()) {
501 continue;
502 }
503
504 MachNode* const mach = node->as_Mach();
505 int opcode = mach->ideal_Opcode();
506 if (is_Load(opcode) || is_Store(opcode) || is_LoadStore(opcode)) {
507 if ((mach->barrier_data() & ShenandoahBitsReal) != 0) {
508 accesses.push(mach);
509 dominators.push(mach);
510 }
511 }
512 }
513 }
514
515 elide_dominated_barriers(accesses, dominators);
516 }
517
518 uint ShenandoahBarrierSetC2::estimated_barrier_size(const Node* node) const {
519 // Barrier impact on fast-path is driven by GC state checks emitted very late.
520 // These checks are tight load-test-branch sequences, with no impact on C2 graph
521 // size. Limiting unrolling in presence of GC barriers might turn some loops
522 // tighter than with default unrolling, which may benefit performance due to denser
523 // code. Testing shows it is still counter-productive.
524 // Therefore, we report zero barrier size to let C2 do its normal thing.
525 return 0;
526 }
527
528 bool ShenandoahBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, bool is_clone_instance, ArrayCopyPhase phase) const {
529 bool is_oop = is_reference_type(type);
530 if (!is_oop) {
531 return false;
532 }
533 if (ShenandoahSATBBarrier && tightly_coupled_alloc) {
534 if (phase == Optimization) {
535 return false;
536 }
537 return !is_clone;
538 }
539 return true;
540 }
541
542 bool ShenandoahBarrierSetC2::clone_needs_barrier(const TypeOopPtr* src_type, bool& is_oop_array) {
543 if (!ShenandoahCloneBarrier) {
544 return false;
545 }
546
547 if (src_type->isa_instptr() != nullptr) {
548 // Instance: need barrier only if there is a possibility of having an oop anywhere in it.
549 ciInstanceKlass* ik = src_type->is_instptr()->instance_klass();
550 if ((src_type->klass_is_exact() || !ik->has_subklass()) &&
551 !ik->has_injected_fields() && !ik->has_object_fields()) {
552 if (!src_type->klass_is_exact()) {
553 // Class is *currently* the leaf in the hierarchy.
554 // Record the dependency so that we deopt if this does not hold in future.
555 Compile::current()->dependencies()->assert_leaf_type(ik);
556 }
557 return false;
558 }
559 } else if (src_type->isa_aryptr() != nullptr) {
560 // Array: need barrier only if array is oop-bearing.
561 BasicType src_elem = src_type->isa_aryptr()->elem()->array_element_basic_type();
562 if (is_reference_type(src_elem, true) && src_type->is_not_flat()) {
563 is_oop_array = true;
564 } else if (!src_type->is_not_flat()) {
565 // Maybe flat, assume the worst.
566 } else {
567 return false;
568 }
569 }
570
571 // Assume the worst.
572 return true;
573 }
574
575 void ShenandoahBarrierSetC2::clone(GraphKit* kit, Node* src_base, Node* dst_base, Node* size, bool is_array) const {
576 const TypeOopPtr* src_type = kit->gvn().type(src_base)->is_oopptr();
577
578 bool is_oop_array = false;
579 if (!clone_needs_barrier(src_type, is_oop_array)) {
580 // No barrier is needed? Just do what common BarrierSetC2 wants with it.
581 BarrierSetC2::clone(kit, src_base, dst_base, size, is_array);
582 return;
583 }
584
585 if (ShenandoahCloneRuntime || !is_array || !is_oop_array) {
586 // Looks like an instance? Prepare the instance clone. This would either
587 // be exploded into individual accesses or be left as runtime call.
588 // Common BarrierSetC2 prepares everything for both cases.
589 BarrierSetC2::clone(kit, src_base, dst_base, size, is_array);
590 return;
591 }
592
593 // We are cloning the oop array. Prepare to call the normal arraycopy stub
594 // after the expansion. Normal stub takes the number of actual type-sized
595 // elements to copy after the base, compute the count here.
596 Node* offset = kit->MakeConX(arrayOopDesc::base_offset_in_bytes(UseCompressedOops ? T_NARROWOOP : T_OBJECT));
597 size = kit->gvn().transform(new SubXNode(size, offset));
598 size = kit->gvn().transform(new URShiftXNode(size, kit->intcon(LogBytesPerHeapOop)));
599 ArrayCopyNode* ac = ArrayCopyNode::make(kit, false, src_base, offset, dst_base, offset, size, true, false);
600 ac->set_clone_array();
601 Node* n = kit->gvn().transform(ac);
602 if (n == ac) {
603 ac->set_adr_type(TypeRawPtr::BOTTOM);
604 kit->set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), TypeRawPtr::BOTTOM);
605 } else {
606 kit->set_all_memory(n);
607 }
608 }
609
610 void ShenandoahBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const {
611 Node* const ctrl = ac->in(TypeFunc::Control);
612 Node* const mem = ac->in(TypeFunc::Memory);
613 Node* const src = ac->in(ArrayCopyNode::Src);
614 Node* const src_offset = ac->in(ArrayCopyNode::SrcPos);
615 Node* const dest = ac->in(ArrayCopyNode::Dest);
616 Node* const dest_offset = ac->in(ArrayCopyNode::DestPos);
617 Node* length = ac->in(ArrayCopyNode::Length);
618
619 const TypeOopPtr* src_type = phase->igvn().type(src)->is_oopptr();
620
621 bool is_oop_array = false;
622 if (!clone_needs_barrier(src_type, is_oop_array)) {
623 // No barrier is needed? Expand to normal HeapWord-sized arraycopy.
624 BarrierSetC2::clone_at_expansion(phase, ac);
625 return;
626 }
627
628 if (ShenandoahCloneRuntime || !ac->is_clone_array() || !is_oop_array) {
629 // Still looks like an instance? Likely a large instance or reflective
630 // clone with unknown length. Go to runtime and handle it there.
631 clone_in_runtime(phase, ac, ShenandoahRuntime::clone_addr(), "ShenandoahRuntime::clone");
632 return;
633 }
634
635 // We are cloning the oop array. Call into normal oop array copy stubs.
636 // Those stubs would call BarrierSetAssembler to handle GC barriers.
637
638 // This is the full clone, so offsets should equal each other and be at array base.
639 assert(src_offset == dest_offset, "should be equal");
640 const jlong offset = src_offset->get_long();
641 const TypeAryPtr* const ary_ptr = src->get_ptr_type()->isa_aryptr();
642 BasicType bt = ary_ptr->elem()->array_element_basic_type();
643 if (offset != arrayOopDesc::base_offset_in_bytes(bt)) {
644 // Something is off with flat arrays. Go to runtime instead.
645 // TODO: Figure this out.
646 clone_in_runtime(phase, ac, ShenandoahRuntime::clone_addr(), "ShenandoahRuntime::clone");
647 return;
648 }
649 assert(offset == arrayOopDesc::base_offset_in_bytes(bt), "should match");
650
651 const char* copyfunc_name = "arraycopy";
652 const address copyfunc_addr = phase->basictype2arraycopy(T_OBJECT, nullptr, nullptr, true, copyfunc_name, true);
653
654 Node* const call = phase->make_leaf_call(ctrl, mem,
655 OptoRuntime::fast_arraycopy_Type(),
656 copyfunc_addr, copyfunc_name,
657 TypeRawPtr::BOTTOM,
658 phase->basic_plus_adr(src, src_offset),
659 phase->basic_plus_adr(dest, dest_offset),
660 length,
661 phase->top()
662 );
663 phase->transform_later(call);
664
665 phase->igvn().replace_node(ac, call);
666 }
667
668 void* ShenandoahBarrierSetC2::create_barrier_state(Arena* comp_arena) const {
669 return new(comp_arena) ShenandoahBarrierSetC2State(comp_arena);
670 }
671
672 void ShenandoahBarrierSetC2::print_barrier_data(outputStream* os, uint8_t data) {
673 os->print(" Node barriers: ");
674 if ((data & ShenandoahBitStrong) != 0) {
675 data &= ~ShenandoahBitStrong;
676 os->print("strong ");
677 }
678
679 if ((data & ShenandoahBitWeak) != 0) {
680 data &= ~ShenandoahBitWeak;
681 os->print("weak ");
682 }
683
684 if ((data & ShenandoahBitPhantom) != 0) {
685 data &= ~ShenandoahBitPhantom;
686 os->print("phantom ");
687 }
688
689 if ((data & ShenandoahBitKeepAlive) != 0) {
690 data &= ~ShenandoahBitKeepAlive;
691 os->print("keepalive ");
692 }
693
694 if ((data & ShenandoahBitCardMark) != 0) {
695 data &= ~ShenandoahBitCardMark;
696 os->print("cardmark ");
697 }
698
699 if ((data & ShenandoahBitNative) != 0) {
700 data &= ~ShenandoahBitNative;
701 os->print("native ");
702 }
703
704 if ((data & ShenandoahBitNotNull) != 0) {
705 data &= ~ShenandoahBitNotNull;
706 os->print("not-null ");
707 }
708
709 if ((data & ShenandoahBitElided) != 0) {
710 data &= ~ShenandoahBitElided;
711 os->print("elided ");
712 }
713
714 os->cr();
715
716 if (data > 0) {
717 fatal("Unknown bit!");
718 }
719
720 os->print_cr(" GC configuration: %sLRB %sSATB %sClone %sCard",
721 (ShenandoahLoadRefBarrier ? "+" : "-"),
722 (ShenandoahSATBBarrier ? "+" : "-"),
723 (ShenandoahCloneBarrier ? "+" : "-"),
724 (ShenandoahCardBarrier ? "+" : "-")
725 );
726 }
727
728
729 #ifdef ASSERT
730 void ShenandoahBarrierSetC2::verify_gc_barrier_assert(bool cond, const char* msg, uint8_t bd, Node* n) {
731 if (!cond) {
732 stringStream ss;
733 ss.print_cr("%s", msg);
734 ss.print_cr("-----------------");
735 print_barrier_data(&ss, bd);
736 ss.print_cr("-----------------");
737 n->dump_bfs(1, nullptr, "", &ss);
738 report_vm_error(__FILE__, __LINE__, ss.as_string());
739 }
740 }
741
742 void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase phase) const {
743 if (!ShenandoahVerifyOptoBarriers) {
744 return;
745 }
746
747 // Verify depending on the barriers actually enabled, allowing verification in passive mode.
748 // Normally, we have _some_ bits set on all accesses. Optimizations may drop some bits,
749 // but only the last optimization step eliminates all remaining metadata flags. Only then
750 // the access data can be completely blank.
751 bool final_phase = (phase == BeforeCodeGen);
752 bool expect_load_barriers = !final_phase && ShenandoahLoadRefBarrier;
753 bool expect_store_barriers = !final_phase && (ShenandoahSATBBarrier || ShenandoahCardBarrier);
754 bool expect_load_store_barriers = expect_load_barriers || expect_store_barriers;
755 bool expect_some_real = final_phase;
756
757 Unique_Node_List wq;
758
759 RootNode* root = compile->root();
760 wq.push(root);
761
762 // Also seed the outs to capture nodes are not reachable from in()-s, e.g. endless loops.
763 for (DUIterator_Fast imax, i = root->fast_outs(imax); i < imax; i++) {
764 Node* m = root->fast_out(i);
765 wq.push(m);
766 }
767
768 for (uint next = 0; next < wq.size(); next++) {
769 Node *n = wq.at(next);
770 assert(!n->is_Mach(), "No Mach nodes here yet");
771
772 int opc = n->Opcode();
773
774 uint8_t bd = 0;
775 const TypePtr* adr_type = nullptr;
776 if (is_Load(opc)) {
777 bd = n->as_Load()->barrier_data();
778 adr_type = n->as_Load()->adr_type();
779 } else if (is_Store(opc)) {
780 bd = n->as_Store()->barrier_data();
781 adr_type = n->as_Store()->adr_type();
782 } else if (is_LoadStore(opc)) {
783 bd = n->as_LoadStore()->barrier_data();
784 adr_type = n->as_LoadStore()->adr_type();
785 } else if (n->is_Mem()) {
786 bd = MemNode::barrier_data(n);
787 verify_gc_barrier_assert(bd == 0, "Other mem nodes should have no barrier data", bd, n);
788 }
789
790 bool is_weak = (bd & (ShenandoahBitWeak | ShenandoahBitPhantom)) != 0;
791 bool is_native = (bd & ShenandoahBitNative) != 0;
792
793 bool is_referent = adr_type != nullptr &&
794 adr_type->isa_instptr() &&
795 adr_type->is_instptr()->instance_klass()->is_subtype_of(Compile::current()->env()->Reference_klass()) &&
796 adr_type->is_instptr()->offset() == java_lang_ref_Reference::referent_offset();
797
798 bool is_oop_addr = (adr_type != nullptr) && (adr_type->isa_oopptr() || adr_type->isa_narrowoop());
799 bool is_raw_addr = (adr_type != nullptr) && (adr_type->isa_rawptr() || adr_type->isa_klassptr());
800
801 verify_gc_barrier_assert(!expect_some_real || (bd == 0) || (bd & ShenandoahBitsReal) != 0, "Without real barriers, metadata should be stripped at this point", bd, n);
802
803 if (is_oop_addr) {
804 if (is_Load(opc)) {
805 verify_gc_barrier_assert(!expect_load_barriers || (bd != 0), "Oop load should have barrier data", bd, n);
806 verify_gc_barrier_assert(!is_weak || is_referent, "Weak load only for Reference.referent", bd, n);
807 } else if (is_Store(opc)) {
808 // Reference.referent stores can be without barriers.
809 verify_gc_barrier_assert(!expect_store_barriers || is_referent || (bd != 0), "Oop store should have barrier data", bd, n);
810 } else if (is_LoadStore(opc)) {
811 verify_gc_barrier_assert(!expect_load_store_barriers || (bd != 0), "Oop load-store should have barrier data", bd, n);
812 }
813 } else if (is_raw_addr) {
814 if (is_native) {
815 if (is_Load(opc)) {
816 verify_gc_barrier_assert(!expect_load_barriers || (bd != 0), "Native oop load should have barrier data", bd, n);
817 }
818 if (is_Store(opc)) {
819 verify_gc_barrier_assert(!expect_store_barriers || (bd != 0), "Native oop store should have barrier data", bd, n);
820 }
821 if (is_LoadStore(opc)) {
822 verify_gc_barrier_assert(!expect_load_store_barriers || (bd != 0), "Native oop load-store should have barrier data", bd, n);
823 }
824 } else {
825 // Some Load/Stores are used for T_ADDRESS and/or raw stores, which are supposed not to have barriers.
826 // Some other Load/Stores are emitted for real oops, but on raw addresses via Unsafe.
827 // The distinction on this level is lost, so we cannot really verify this.
828 }
829 } else {
830 if (is_Load(opc) || is_Store(opc) || is_LoadStore(opc)) {
831 verify_gc_barrier_assert(false, "Unclassified access type", bd, n);
832 }
833 }
834
835 for (uint j = 0; j < n->req(); j++) {
836 Node* in = n->in(j);
837 if (in != nullptr) {
838 wq.push(in);
839 }
840 }
841 }
842 }
843 #endif
844
845 static ShenandoahBarrierSetC2State* barrier_set_state() {
846 return reinterpret_cast<ShenandoahBarrierSetC2State*>(Compile::current()->barrier_set_state());
847 }
848
849 int ShenandoahBarrierSetC2::estimate_stub_size() const {
850 GrowableArray<ShenandoahBarrierStubC2*>* const stubs = barrier_set_state()->stubs();
851 assert(stubs->is_empty(), "Lifecycle: no stubs were yet created");
852 return 0;
853 }
854
855 void ShenandoahBarrierSetC2::emit_stubs(CodeBuffer& cb) const {
856 MacroAssembler masm(&cb);
857
858 PhaseOutput* const output = Compile::current()->output();
859 assert(masm.offset() <= output->buffer_sizing_data()->_code,
860 "Stubs are assumed to be emitted directly after code and code_size is a hard limit on where it can start");
861 barrier_set_state()->set_stubs_start_offset(masm.offset());
862
863 // Stub generation counts all stubs as skipped for the sake of inlining policy.
864 // This is critical for performance, check it.
865 #ifdef ASSERT
866 int offset_before = masm.offset();
867 int skipped_before = cb.total_skipped_instructions_size();
868 #endif
869
870 GrowableArray<ShenandoahBarrierStubC2*>* const stubs = barrier_set_state()->stubs();
871 for (int i = 0; i < stubs->length(); i++) {
872 // Make sure there is enough space in the code buffer
873 if (cb.insts()->maybe_expand_to_ensure_remaining(PhaseOutput::MAX_inst_size) && cb.blob() == nullptr) {
874 ciEnv::current()->record_failure("CodeCache is full");
875 return;
876 }
877 stubs->at(i)->emit_code(masm);
878 }
879
880 #ifdef ASSERT
881 int offset_after = masm.offset();
882 int skipped_after = cb.total_skipped_instructions_size();
883 assert(offset_after - offset_before == skipped_after - skipped_before,
884 "All stubs are counted as skipped. masm: %d - %d = %d, cb: %d - %d = %d",
885 offset_after, offset_before, offset_after - offset_before,
886 skipped_after, skipped_before, skipped_after - skipped_before);
887 #endif
888
889 // Code will be copied. No ICache sync required.
890 }
891
892 void ShenandoahBarrierStubC2::register_stub(ShenandoahBarrierStubC2* stub) {
893 if (!Compile::current()->output()->in_scratch_emit_size()) {
894 barrier_set_state()->stubs()->append(stub);
895 }
896 }
897
898 ShenandoahBarrierStubC2* ShenandoahBarrierStubC2::create(const MachNode* node, Register obj, Address addr, Register tmp1, Register tmp2, bool narrow, bool do_load) {
899 auto* stub = new (Compile::current()->comp_arena()) ShenandoahBarrierStubC2(node, obj, addr, tmp1, tmp2, narrow, do_load);
900 register_stub(stub);
901 return stub;
902 }
903
904 void ShenandoahBarrierStubC2::load_post(MacroAssembler* masm, const MachNode* node, Register obj, Address addr, Register tmp1, Register tmp2, bool narrow) {
905 // Load post-barrier:
906 // a. Satisfies the need for LRB for normal loads
907 // b. Passes a weak load through LRB-weak
908 // c. Keep-alives a weak load
909 if (needs_slow_barrier(node)) {
910 ShenandoahBarrierStubC2* const stub = create(node, obj, addr, tmp1, tmp2, narrow, /* do_load = */ false);
911 char check = 0;
912 check |= needs_keep_alive_barrier(node) ? ShenandoahHeap::MARKING : 0;
913 check |= needs_load_ref_barrier(node) ? ShenandoahHeap::HAS_FORWARDED : 0;
914 check |= needs_load_ref_barrier_weak(node) ? ShenandoahHeap::WEAK_ROOTS : 0;
915 stub->enter_if_gc_state(*masm, check, tmp1);
916 }
917 }
918
919 void ShenandoahBarrierStubC2::store_pre(MacroAssembler* masm, const MachNode* node, Address addr, Register tmp1, Register tmp2, Register tmp3, bool narrow) {
920 // Store pre-barrier: SATB, keep-alive the current memory value.
921 if (needs_slow_barrier(node)) {
922 assert(!needs_load_ref_barrier(node), "Should not be required for stores");
923 ShenandoahBarrierStubC2* const stub = create(node, tmp1, addr, tmp2, tmp3, narrow, /* do_load = */ true);
924 stub->enter_if_gc_state(*masm, ShenandoahHeap::MARKING, tmp1);
925 }
926 }
927
928 void ShenandoahBarrierStubC2::load_store_pre(MacroAssembler* masm, const MachNode* node, Address addr, Register tmp1, Register tmp2, Register tmp3, bool narrow) {
929 // Load/Store pre-barrier:
930 // a. Avoids false positives from CAS encountering to-space memory values.
931 // b. Satisfies the need for LRB for the CAE result.
932 // c. Records old value for the sake of SATB.
933 //
934 // (a) and (b) are covered because load barrier does memory location fixup.
935 // (c) is covered by KA on the current memory value.
936 if (needs_slow_barrier(node)) {
937 ShenandoahBarrierStubC2* const stub = create(node, tmp1, addr, tmp2, tmp3, narrow, /* do_load = */ true);
938 char check = 0;
939 check |= needs_keep_alive_barrier(node) ? ShenandoahHeap::MARKING : 0;
940 check |= needs_load_ref_barrier(node) ? ShenandoahHeap::HAS_FORWARDED : 0;
941 assert(!needs_load_ref_barrier_weak(node), "Not supported for Load/Stores");
942 stub->enter_if_gc_state(*masm, check, tmp1);
943 }
944 }
945
946 void ShenandoahBarrierStubC2::store_post(MacroAssembler* masm, const MachNode* node, Address addr, Register tmp1, Register tmp2) {
947 if (needs_card_barrier(node)) {
948 cardtable(*masm, addr, tmp1, tmp2);
949 }
950 }
951
952 void ShenandoahBarrierStubC2::load_store_post(MacroAssembler* masm, const MachNode* node, Address addr, Register tmp1, Register tmp2) {
953 store_post(masm, node, addr, tmp1, tmp2);
954 }
955
956 bool ShenandoahBarrierStubC2::is_live_register(Register reg) {
957 return preserve_set().member(OptoReg::as_OptoReg(reg->as_VMReg()));
958 }
959
960 Register ShenandoahBarrierStubC2::select_temp_register(bool& selected_live, Register skip_reg1, Register skip_reg2) {
961 Register tmp = noreg;
962 Register fallback_live = noreg;
963
964 // Try to select non-live first:
965 for (int i = 0; i < available_gp_registers(); i++) {
966 Register r = as_Register(i);
967 if (r != _obj && r != _addr.base() && r != _addr.index() &&
968 r != skip_reg1 && r != skip_reg2 && !is_special_register(r)) {
969 if (!is_live_register(r)) {
970 tmp = r;
971 break;
972 } else if (fallback_live == noreg) {
973 fallback_live = r;
974 }
975 }
976 }
977
978 // If we could not find a non-live register, select the live fallback:
979 if (tmp == noreg) {
980 tmp = fallback_live;
981 selected_live = true;
982 } else {
983 selected_live = false;
984 }
985
986 assert(tmp != noreg, "successfully selected");
987 assert_different_registers(tmp, skip_reg1);
988 assert_different_registers(tmp, skip_reg2);
989 assert_different_registers(tmp, _obj);
990 assert_different_registers(tmp, _addr.base());
991 assert_different_registers(tmp, _addr.index());
992 return tmp;
993 }
994
995 address ShenandoahBarrierStubC2::keepalive_runtime_entry_addr() {
996 if (_narrow) {
997 return CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre_narrow);
998 } else {
999 return CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre);
1000 }
1001 }
1002
1003 address ShenandoahBarrierStubC2::lrb_runtime_entry_addr() {
1004 bool is_strong = (_node->barrier_data() & ShenandoahBitStrong) != 0;
1005 bool is_weak = (_node->barrier_data() & ShenandoahBitWeak) != 0;
1006 bool is_phantom = (_node->barrier_data() & ShenandoahBitPhantom) != 0;
1007
1008 if (_narrow) {
1009 if (is_strong) {
1010 return CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow_narrow);
1011 } else if (is_weak) {
1012 return CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow_narrow);
1013 } else if (is_phantom) {
1014 return CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom_narrow_narrow);
1015 }
1016 } else {
1017 if (is_strong) {
1018 return CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong);
1019 } else if (is_weak) {
1020 return CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak);
1021 } else if (is_phantom) {
1022 return CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom);
1023 }
1024 }
1025
1026 ShouldNotReachHere();
1027 return nullptr;
1028 }
1029
1030 bool ShenandoahBarrierSetC2State::needs_liveness_data(const MachNode* mach) const {
1031 // Nodes that require slow-path stubs need liveness data.
1032 return ShenandoahBarrierStubC2::needs_slow_barrier(mach);
1033 }
1034
1035 bool ShenandoahBarrierSetC2State::needs_livein_data() const {
1036 return true;
1037 }