1 /*
  2  * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "precompiled.hpp"
 26 #include "classfile/javaClasses.hpp"
 27 #include "code/vmreg.inline.hpp"
 28 #include "gc/g1/c2/g1BarrierSetC2.hpp"
 29 #include "gc/g1/g1BarrierSet.hpp"
 30 #include "gc/g1/g1BarrierSetAssembler.hpp"
 31 #include "gc/g1/g1BarrierSetRuntime.hpp"
 32 #include "gc/g1/g1CardTable.hpp"
 33 #include "gc/g1/g1ThreadLocalData.hpp"
 34 #include "gc/g1/g1HeapRegion.hpp"
 35 #include "opto/arraycopynode.hpp"
 36 #include "opto/block.hpp"
 37 #include "opto/compile.hpp"
 38 #include "opto/escape.hpp"
 39 #include "opto/graphKit.hpp"
 40 #include "opto/idealKit.hpp"
 41 #include "opto/machnode.hpp"
 42 #include "opto/macro.hpp"
 43 #include "opto/memnode.hpp"
 44 #include "opto/node.hpp"
 45 #include "opto/output.hpp"
 46 #include "opto/regalloc.hpp"
 47 #include "opto/rootnode.hpp"
 48 #include "opto/runtime.hpp"
 49 #include "opto/type.hpp"
 50 #include "utilities/growableArray.hpp"
 51 #include "utilities/macros.hpp"
 52 
 53 /*
 54  * Determine if the G1 pre-barrier can be removed. The pre-barrier is
 55  * required by SATB to make sure all objects live at the start of the
 56  * marking are kept alive, all reference updates need to any previous
 57  * reference stored before writing.
 58  *
 59  * If the previous value is null there is no need to save the old value.
 60  * References that are null are filtered during runtime by the barrier
 61  * code to avoid unnecessary queuing.
 62  *
 63  * However in the case of newly allocated objects it might be possible to
 64  * prove that the reference about to be overwritten is null during compile
 65  * time and avoid adding the barrier code completely.
 66  *
 67  * The compiler needs to determine that the object in which a field is about
 68  * to be written is newly allocated, and that no prior store to the same field
 69  * has happened since the allocation.
 70  */
 71 bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit,
 72                                                PhaseValues* phase,
 73                                                Node* adr,
 74                                                BasicType bt,
 75                                                uint adr_idx) const {
 76   intptr_t offset = 0;
 77   Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset);
 78   AllocateNode* alloc = AllocateNode::Ideal_allocation(base);
 79 
 80   if (offset == Type::OffsetBot) {
 81     return false; // Cannot unalias unless there are precise offsets.
 82   }
 83   if (alloc == nullptr) {
 84     return false; // No allocation found.
 85   }
 86 
 87   intptr_t size_in_bytes = type2aelembytes(bt);
 88   Node* mem = kit->memory(adr_idx); // Start searching here.
 89 
 90   for (int cnt = 0; cnt < 50; cnt++) {
 91     if (mem->is_Store()) {
 92       Node* st_adr = mem->in(MemNode::Address);
 93       intptr_t st_offset = 0;
 94       Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, phase, st_offset);
 95 
 96       if (st_base == nullptr) {
 97         break; // Inscrutable pointer.
 98       }
 99       if (st_base == base && st_offset == offset) {
100         // We have found a store with same base and offset as ours.
101         break;
102       }
103       if (st_offset != offset && st_offset != Type::OffsetBot) {
104         const int MAX_STORE = BytesPerLong;
105         if (st_offset >= offset + size_in_bytes ||
106             st_offset <= offset - MAX_STORE ||
107             st_offset <= offset - mem->as_Store()->memory_size()) {
108           // Success:  The offsets are provably independent.
109           // (You may ask, why not just test st_offset != offset and be done?
110           // The answer is that stores of different sizes can co-exist
111           // in the same sequence of RawMem effects.  We sometimes initialize
112           // a whole 'tile' of array elements with a single jint or jlong.)
113           mem = mem->in(MemNode::Memory);
114           continue; // Advance through independent store memory.
115         }
116       }
117       if (st_base != base
118           && MemNode::detect_ptr_independence(base, alloc, st_base,
119                                               AllocateNode::Ideal_allocation(st_base),
120                                               phase)) {
121         // Success: the bases are provably independent.
122         mem = mem->in(MemNode::Memory);
123         continue; // Advance through independent store memory.
124       }
125     } else if (mem->is_Proj() && mem->in(0)->is_Initialize()) {
126       InitializeNode* st_init = mem->in(0)->as_Initialize();
127       AllocateNode* st_alloc = st_init->allocation();
128 
129       // Make sure that we are looking at the same allocation site.
130       // The alloc variable is guaranteed to not be null here from earlier check.
131       if (alloc == st_alloc) {
132         // Check that the initialization is storing null so that no previous store
133         // has been moved up and directly write a reference.
134         Node* captured_store = st_init->find_captured_store(offset,
135                                                             type2aelembytes(T_OBJECT),
136                                                             phase);
137         if (captured_store == nullptr || captured_store == st_init->zero_memory()) {
138           return true;
139         }
140       }
141     }
142     // Unless there is an explicit 'continue', we must bail out here,
143     // because 'mem' is an inscrutable memory state (e.g., a call).
144     break;
145   }
146   return false;
147 }
148 
149 /*
150  * G1, similar to any GC with a Young Generation, requires a way to keep track
151  * of references from Old Generation to Young Generation to make sure all live
152  * objects are found. G1 also requires to keep track of object references
153  * between different regions to enable evacuation of old regions, which is done
154  * as part of mixed collections. References are tracked in remembered sets,
155  * which are continuously updated as references are written to with the help of
156  * the post-barrier.
157  *
158  * To reduce the number of updates to the remembered set, the post-barrier
159  * filters out updates to fields in objects located in the Young Generation, the
160  * same region as the reference, when null is being written, or if the card is
161  * already marked as dirty by an earlier write.
162  *
163  * Under certain circumstances it is possible to avoid generating the
164  * post-barrier completely, if it is possible during compile time to prove the
165  * object is newly allocated and that no safepoint exists between the allocation
166  * and the store. This can be seen as a compile-time version of the
167  * above-mentioned Young Generation filter.
168  *
169  * In the case of a slow allocation, the allocation code must handle the barrier
170  * as part of the allocation if the allocated object is not located in the
171  * nursery; this would happen for humongous objects.
172  */
173 bool G1BarrierSetC2::g1_can_remove_post_barrier(GraphKit* kit,
174                                                 PhaseValues* phase, Node* store_ctrl,
175                                                 Node* adr) const {
176   intptr_t      offset = 0;
177   Node*         base   = AddPNode::Ideal_base_and_offset(adr, phase, offset);
178   AllocateNode* alloc  = AllocateNode::Ideal_allocation(base);
179 
180   if (offset == Type::OffsetBot) {
181     return false; // Cannot unalias unless there are precise offsets.
182   }
183   if (alloc == nullptr) {
184     return false; // No allocation found.
185   }
186 
187   Node* mem = store_ctrl;   // Start search from Store node.
188   if (mem->is_Proj() && mem->in(0)->is_Initialize()) {
189     InitializeNode* st_init = mem->in(0)->as_Initialize();
190     AllocateNode*  st_alloc = st_init->allocation();
191     // Make sure we are looking at the same allocation
192     if (alloc == st_alloc) {
193       return true;
194     }
195   }
196 
197   return false;
198 }
199 
200 Node* G1BarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const {
201   DecoratorSet decorators = access.decorators();
202   bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
203   bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
204   bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0;
205   // If we are reading the value of the referent field of a Reference object, we
206   // need to record the referent in an SATB log buffer using the pre-barrier
207   // mechanism. Also we need to add a memory barrier to prevent commoning reads
208   // from this field across safepoints, since GC can change its value.
209   bool need_read_barrier = ((on_weak || on_phantom) && !no_keepalive);
210   if (access.is_oop() && need_read_barrier) {
211     access.set_barrier_data(G1C2BarrierPre);
212   }
213   return CardTableBarrierSetC2::load_at_resolved(access, val_type);
214 }
215 
216 void G1BarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const {
217   eliminate_gc_barrier_data(node);
218 }
219 
220 void G1BarrierSetC2::eliminate_gc_barrier_data(Node* node) const {
221   if (node->is_LoadStore()) {
222     LoadStoreNode* loadstore = node->as_LoadStore();
223     loadstore->set_barrier_data(0);
224   } else if (node->is_Mem()) {
225     MemNode* mem = node->as_Mem();
226     mem->set_barrier_data(0);
227   }
228 }
229 
230 static void refine_barrier_by_new_val_type(const Node* n) {
231   if (n->Opcode() != Op_StoreP &&
232       n->Opcode() != Op_StoreN) {
233     return;
234   }
235   MemNode* store = n->as_Mem();
236   const Node* newval = n->in(MemNode::ValueIn);
237   assert(newval != nullptr, "");
238   const Type* newval_bottom = newval->bottom_type();
239   TypePtr::PTR newval_type = newval_bottom->make_ptr()->ptr();
240   uint8_t barrier_data = store->barrier_data();
241   if (!newval_bottom->isa_oopptr() &&
242       !newval_bottom->isa_narrowoop() &&
243       newval_type != TypePtr::Null) {
244     // newval is neither an OOP nor null, so there is no barrier to refine.
245     assert(barrier_data == 0, "non-OOP stores should have no barrier data");
246     return;
247   }
248   if (barrier_data == 0) {
249     // No barrier to refine.
250     return;
251   }
252   if (newval_type == TypePtr::Null) {
253     // Simply elide post-barrier if writing null.
254     barrier_data &= ~G1C2BarrierPost;
255     barrier_data &= ~G1C2BarrierPostNotNull;
256   } else if (((barrier_data & G1C2BarrierPost) != 0) &&
257              newval_type == TypePtr::NotNull) {
258     // If the post-barrier has not been elided yet (e.g. due to newval being
259     // freshly allocated), mark it as not-null (simplifies barrier tests and
260     // compressed OOPs logic).
261     barrier_data |= G1C2BarrierPostNotNull;
262   }
263   store->set_barrier_data(barrier_data);
264   return;
265 }
266 
267 // Refine (not really expand) G1 barriers by looking at the new value type
268 // (whether it is necessarily null or necessarily non-null).
269 bool G1BarrierSetC2::expand_barriers(Compile* C, PhaseIterGVN& igvn) const {
270   ResourceMark rm;
271   VectorSet visited;
272   Node_List worklist;
273   worklist.push(C->root());
274   while (worklist.size() > 0) {
275     Node* n = worklist.pop();
276     if (visited.test_set(n->_idx)) {
277       continue;
278     }
279     refine_barrier_by_new_val_type(n);
280     for (uint j = 0; j < n->req(); j++) {
281       Node* in = n->in(j);
282       if (in != nullptr) {
283         worklist.push(in);
284       }
285     }
286   }
287   return false;
288 }
289 
290 uint G1BarrierSetC2::estimated_barrier_size(const Node* node) const {
291   // These Ideal node counts are extracted from the pre-matching Ideal graph
292   // generated when compiling the following method with early barrier expansion:
293   //   static void write(MyObject obj1, Object o) {
294   //     obj1.o1 = o;
295   //   }
296   uint8_t barrier_data = MemNode::barrier_data(node);
297   uint nodes = 0;
298   if ((barrier_data & G1C2BarrierPre) != 0) {
299     nodes += 50;
300   }
301   if ((barrier_data & G1C2BarrierPost) != 0) {
302     nodes += 60;
303   }
304   return nodes;
305 }
306 
307 bool G1BarrierSetC2::can_initialize_object(const StoreNode* store) const {
308   assert(store->Opcode() == Op_StoreP || store->Opcode() == Op_StoreN, "OOP store expected");
309   // It is OK to move the store across the object initialization boundary only
310   // if it does not have any barrier, or if it has barriers that can be safely
311   // elided (because of the compensation steps taken on the allocation slow path
312   // when ReduceInitialCardMarks is enabled).
313   return (MemNode::barrier_data(store) == 0) || use_ReduceInitialCardMarks();
314 }
315 
316 void G1BarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const {
317   if (ac->is_clone_inst() && !use_ReduceInitialCardMarks()) {
318     clone_in_runtime(phase, ac, G1BarrierSetRuntime::clone_addr(), "G1BarrierSetRuntime::clone");
319     return;
320   }
321   BarrierSetC2::clone_at_expansion(phase, ac);
322 }
323 
324 Node* G1BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const {
325   DecoratorSet decorators = access.decorators();
326   bool anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
327   bool in_heap = (decorators & IN_HEAP) != 0;
328   bool tightly_coupled_alloc = (decorators & C2_TIGHTLY_COUPLED_ALLOC) != 0;
329   bool need_store_barrier = !(tightly_coupled_alloc && use_ReduceInitialCardMarks()) && (in_heap || anonymous);
330   bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0;
331   if (access.is_oop() && need_store_barrier) {
332     access.set_barrier_data(get_store_barrier(access));
333     if (tightly_coupled_alloc) {
334       assert(!use_ReduceInitialCardMarks(),
335              "post-barriers are only needed for tightly-coupled initialization stores when ReduceInitialCardMarks is disabled");
336       // Pre-barriers are unnecessary for tightly-coupled initialization stores.
337       access.set_barrier_data(access.barrier_data() & ~G1C2BarrierPre);
338     }
339   }
340   if (no_keepalive) {
341     // No keep-alive means no need for the pre-barrier.
342     access.set_barrier_data(access.barrier_data() & ~G1C2BarrierPre);
343   }
344   return BarrierSetC2::store_at_resolved(access, val);
345 }
346 
347 Node* G1BarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
348                                                      Node* new_val, const Type* value_type) const {
349   GraphKit* kit = access.kit();
350   if (!access.is_oop()) {
351     return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type);
352   }
353   access.set_barrier_data(G1C2BarrierPre | G1C2BarrierPost);
354   return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type);
355 }
356 
357 Node* G1BarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
358                                                       Node* new_val, const Type* value_type) const {
359   GraphKit* kit = access.kit();
360   if (!access.is_oop()) {
361     return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);
362   }
363   access.set_barrier_data(G1C2BarrierPre | G1C2BarrierPost);
364   return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);
365 }
366 
367 Node* G1BarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const {
368   GraphKit* kit = access.kit();
369   if (!access.is_oop()) {
370     return BarrierSetC2::atomic_xchg_at_resolved(access, new_val, value_type);
371   }
372   access.set_barrier_data(G1C2BarrierPre | G1C2BarrierPost);
373   return BarrierSetC2::atomic_xchg_at_resolved(access, new_val, value_type);
374 }
375 
376 class G1BarrierSetC2State : public BarrierSetC2State {
377 private:
378   GrowableArray<G1BarrierStubC2*>* _stubs;
379 
380 public:
381   G1BarrierSetC2State(Arena* arena)
382     : BarrierSetC2State(arena),
383       _stubs(new (arena) GrowableArray<G1BarrierStubC2*>(arena, 8,  0, nullptr)) {}
384 
385   GrowableArray<G1BarrierStubC2*>* stubs() {
386     return _stubs;
387   }
388 
389   bool needs_liveness_data(const MachNode* mach) const {
390     return G1PreBarrierStubC2::needs_barrier(mach) ||
391            G1PostBarrierStubC2::needs_barrier(mach);
392   }
393 
394   bool needs_livein_data() const {
395     return false;
396   }
397 };
398 
399 static G1BarrierSetC2State* barrier_set_state() {
400   return reinterpret_cast<G1BarrierSetC2State*>(Compile::current()->barrier_set_state());
401 }
402 
403 G1BarrierStubC2::G1BarrierStubC2(const MachNode* node) : BarrierStubC2(node) {}
404 
405 G1PreBarrierStubC2::G1PreBarrierStubC2(const MachNode* node) : G1BarrierStubC2(node) {}
406 
407 bool G1PreBarrierStubC2::needs_barrier(const MachNode* node) {
408   return (node->barrier_data() & G1C2BarrierPre) != 0;
409 }
410 
411 G1PreBarrierStubC2* G1PreBarrierStubC2::create(const MachNode* node) {
412   G1PreBarrierStubC2* const stub = new (Compile::current()->comp_arena()) G1PreBarrierStubC2(node);
413   if (!Compile::current()->output()->in_scratch_emit_size()) {
414     barrier_set_state()->stubs()->append(stub);
415   }
416   return stub;
417 }
418 
419 void G1PreBarrierStubC2::initialize_registers(Register obj, Register pre_val, Register thread, Register tmp1, Register tmp2) {
420   _obj = obj;
421   _pre_val = pre_val;
422   _thread = thread;
423   _tmp1 = tmp1;
424   _tmp2 = tmp2;
425 }
426 
427 Register G1PreBarrierStubC2::obj() const {
428   return _obj;
429 }
430 
431 Register G1PreBarrierStubC2::pre_val() const {
432   return _pre_val;
433 }
434 
435 Register G1PreBarrierStubC2::thread() const {
436   return _thread;
437 }
438 
439 Register G1PreBarrierStubC2::tmp1() const {
440   return _tmp1;
441 }
442 
443 Register G1PreBarrierStubC2::tmp2() const {
444   return _tmp2;
445 }
446 
447 void G1PreBarrierStubC2::emit_code(MacroAssembler& masm) {
448   G1BarrierSetAssembler* bs = static_cast<G1BarrierSetAssembler*>(BarrierSet::barrier_set()->barrier_set_assembler());
449   bs->generate_c2_pre_barrier_stub(&masm, this);
450 }
451 
452 G1PostBarrierStubC2::G1PostBarrierStubC2(const MachNode* node) : G1BarrierStubC2(node) {}
453 
454 bool G1PostBarrierStubC2::needs_barrier(const MachNode* node) {
455   return (node->barrier_data() & G1C2BarrierPost) != 0;
456 }
457 
458 G1PostBarrierStubC2* G1PostBarrierStubC2::create(const MachNode* node) {
459   G1PostBarrierStubC2* const stub = new (Compile::current()->comp_arena()) G1PostBarrierStubC2(node);
460   if (!Compile::current()->output()->in_scratch_emit_size()) {
461     barrier_set_state()->stubs()->append(stub);
462   }
463   return stub;
464 }
465 
466 void G1PostBarrierStubC2::initialize_registers(Register thread, Register tmp1, Register tmp2, Register tmp3) {
467   _thread = thread;
468   _tmp1 = tmp1;
469   _tmp2 = tmp2;
470   _tmp3 = tmp3;
471 }
472 
473 Register G1PostBarrierStubC2::thread() const {
474   return _thread;
475 }
476 
477 Register G1PostBarrierStubC2::tmp1() const {
478   return _tmp1;
479 }
480 
481 Register G1PostBarrierStubC2::tmp2() const {
482   return _tmp2;
483 }
484 
485 Register G1PostBarrierStubC2::tmp3() const {
486   return _tmp3;
487 }
488 
489 void G1PostBarrierStubC2::emit_code(MacroAssembler& masm) {
490   G1BarrierSetAssembler* bs = static_cast<G1BarrierSetAssembler*>(BarrierSet::barrier_set()->barrier_set_assembler());
491   bs->generate_c2_post_barrier_stub(&masm, this);
492 }
493 
494 void* G1BarrierSetC2::create_barrier_state(Arena* comp_arena) const {
495   return new (comp_arena) G1BarrierSetC2State(comp_arena);
496 }
497 
498 int G1BarrierSetC2::get_store_barrier(C2Access& access) const {
499   if (!access.is_parse_access()) {
500     // Only support for eliding barriers at parse time for now.
501     return G1C2BarrierPre | G1C2BarrierPost;
502   }
503   GraphKit* kit = (static_cast<C2ParseAccess&>(access)).kit();
504   Node* ctl = kit->control();
505   Node* adr = access.addr().node();
506   uint adr_idx = kit->C->get_alias_index(access.addr().type());
507   assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory");
508 
509   bool can_remove_pre_barrier = g1_can_remove_pre_barrier(kit, &kit->gvn(), adr, access.type(), adr_idx);
510 
511   // We can skip marks on a freshly-allocated object in Eden. Keep this code in
512   // sync with CardTableBarrierSet::on_slowpath_allocation_exit. That routine
513   // informs GC to take appropriate compensating steps, upon a slow-path
514   // allocation, so as to make this card-mark elision safe.
515   // The post-barrier can also be removed if null is written. This case is
516   // handled by G1BarrierSetC2::expand_barriers, which runs at the end of C2's
517   // platform-independent optimizations to exploit stronger type information.
518   bool can_remove_post_barrier = use_ReduceInitialCardMarks() &&
519     ((access.base() == kit->just_allocated_object(ctl)) ||
520      g1_can_remove_post_barrier(kit, &kit->gvn(), ctl, adr));
521 
522   int barriers = 0;
523   if (!can_remove_pre_barrier) {
524     barriers |= G1C2BarrierPre;
525   }
526   if (!can_remove_post_barrier) {
527     barriers |= G1C2BarrierPost;
528   }
529 
530   return barriers;
531 }
532 
533 void G1BarrierSetC2::late_barrier_analysis() const {
534   compute_liveness_at_stubs();
535 }
536 
537 void G1BarrierSetC2::emit_stubs(CodeBuffer& cb) const {
538   MacroAssembler masm(&cb);
539   GrowableArray<G1BarrierStubC2*>* const stubs = barrier_set_state()->stubs();
540   for (int i = 0; i < stubs->length(); i++) {
541     // Make sure there is enough space in the code buffer
542     if (cb.insts()->maybe_expand_to_ensure_remaining(PhaseOutput::MAX_inst_size) && cb.blob() == nullptr) {
543       ciEnv::current()->record_failure("CodeCache is full");
544       return;
545     }
546     stubs->at(i)->emit_code(masm);
547   }
548   masm.flush();
549 }
550 
551 #ifndef PRODUCT
552 void G1BarrierSetC2::dump_barrier_data(const MachNode* mach, outputStream* st) const {
553   if ((mach->barrier_data() & G1C2BarrierPre) != 0) {
554     st->print("pre ");
555   }
556   if ((mach->barrier_data() & G1C2BarrierPost) != 0) {
557     st->print("post ");
558   }
559   if ((mach->barrier_data() & G1C2BarrierPostNotNull) != 0) {
560     st->print("notnull ");
561   }
562 }
563 #endif // !PRODUCT