26 #include "gc/shenandoah/shenandoahHeap.hpp"
27 #include "gc/shenandoah/shenandoahHeuristics.hpp"
28 #include "gc/shenandoah/shenandoahRuntime.hpp"
29 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
30 #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
31 #include "gc/shenandoah/c2/shenandoahSupport.hpp"
32 #include "opto/arraycopynode.hpp"
33 #include "opto/escape.hpp"
34 #include "opto/graphKit.hpp"
35 #include "opto/idealKit.hpp"
36 #include "opto/macro.hpp"
37 #include "opto/movenode.hpp"
38 #include "opto/narrowptrnode.hpp"
39 #include "opto/rootnode.hpp"
40
41 ShenandoahBarrierSetC2* ShenandoahBarrierSetC2::bsc2() {
42 return reinterpret_cast<ShenandoahBarrierSetC2*>(BarrierSet::barrier_set()->barrier_set_c2());
43 }
44
45 ShenandoahBarrierSetC2State::ShenandoahBarrierSetC2State(Arena* comp_arena)
46 : _shenandoah_barriers(new (comp_arena) GrowableArray<ShenandoahWriteBarrierNode*>(comp_arena, 8, 0, NULL)) {
47 }
48
49 int ShenandoahBarrierSetC2State::shenandoah_barriers_count() const {
50 return _shenandoah_barriers->length();
51 }
52
53 ShenandoahWriteBarrierNode* ShenandoahBarrierSetC2State::shenandoah_barrier(int idx) const {
54 return _shenandoah_barriers->at(idx);
55 }
56
57 void ShenandoahBarrierSetC2State::add_shenandoah_barrier(ShenandoahWriteBarrierNode * n) {
58 assert(!_shenandoah_barriers->contains(n), "duplicate entry in barrier list");
59 _shenandoah_barriers->append(n);
60 }
61
62 void ShenandoahBarrierSetC2State::remove_shenandoah_barrier(ShenandoahWriteBarrierNode * n) {
63 if (_shenandoah_barriers->contains(n)) {
64 _shenandoah_barriers->remove(n);
65 }
66 }
67
68 #define __ kit->
69
70 Node* ShenandoahBarrierSetC2::shenandoah_read_barrier(GraphKit* kit, Node* obj) const {
71 if (ShenandoahReadBarrier) {
72 obj = shenandoah_read_barrier_impl(kit, obj, false, true, true);
73 }
74 return obj;
75 }
76
77 Node* ShenandoahBarrierSetC2::shenandoah_storeval_barrier(GraphKit* kit, Node* obj) const {
78 if (ShenandoahStoreValEnqueueBarrier) {
79 obj = shenandoah_write_barrier(kit, obj);
80 obj = shenandoah_enqueue_barrier(kit, obj);
81 }
82 if (ShenandoahStoreValReadBarrier) {
83 obj = shenandoah_read_barrier_impl(kit, obj, true, false, false);
84 }
85 return obj;
86 }
87
88 Node* ShenandoahBarrierSetC2::shenandoah_read_barrier_impl(GraphKit* kit, Node* obj, bool use_ctrl, bool use_mem, bool allow_fromspace) const {
89 const Type* obj_type = obj->bottom_type();
90 if (obj_type->higher_equal(TypePtr::NULL_PTR)) {
91 return obj;
92 }
93 const TypePtr* adr_type = ShenandoahBarrierNode::brooks_pointer_type(obj_type);
94 Node* mem = use_mem ? __ memory(adr_type) : __ immutable_memory();
95
96 if (! ShenandoahBarrierNode::needs_barrier(&__ gvn(), NULL, obj, mem, allow_fromspace)) {
97 // We know it is null, no barrier needed.
98 return obj;
99 }
100
101 if (obj_type->meet(TypePtr::NULL_PTR) == obj_type->remove_speculative()) {
102
103 // We don't know if it's null or not. Need null-check.
104 enum { _not_null_path = 1, _null_path, PATH_LIMIT };
105 RegionNode* region = new RegionNode(PATH_LIMIT);
106 Node* phi = new PhiNode(region, obj_type);
107 Node* null_ctrl = __ top();
108 Node* not_null_obj = __ null_check_oop(obj, &null_ctrl);
109
110 region->init_req(_null_path, null_ctrl);
111 phi ->init_req(_null_path, __ zerocon(T_OBJECT));
112
113 Node* ctrl = use_ctrl ? __ control() : NULL;
114 ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, not_null_obj, allow_fromspace);
115 Node* n = __ gvn().transform(rb);
116
117 region->init_req(_not_null_path, __ control());
118 phi ->init_req(_not_null_path, n);
119
120 __ set_control(__ gvn().transform(region));
121 __ record_for_igvn(region);
122 return __ gvn().transform(phi);
123
124 } else {
125 // We know it is not null. Simple barrier is sufficient.
126 Node* ctrl = use_ctrl ? __ control() : NULL;
127 ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, obj, allow_fromspace);
128 Node* n = __ gvn().transform(rb);
129 __ record_for_igvn(n);
130 return n;
131 }
132 }
133
134 Node* ShenandoahBarrierSetC2::shenandoah_write_barrier_helper(GraphKit* kit, Node* obj, const TypePtr* adr_type) const {
135 ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(kit->C, kit->control(), kit->memory(adr_type), obj);
136 Node* n = __ gvn().transform(wb);
137 if (n == wb) { // New barrier needs memory projection.
138 Node* proj = __ gvn().transform(new ShenandoahWBMemProjNode(n));
139 __ set_memory(proj, adr_type);
140 }
141 return n;
142 }
143
144 Node* ShenandoahBarrierSetC2::shenandoah_write_barrier(GraphKit* kit, Node* obj) const {
145 if (ShenandoahWriteBarrier) {
146 obj = shenandoah_write_barrier_impl(kit, obj);
147 }
148 return obj;
149 }
150
151 Node* ShenandoahBarrierSetC2::shenandoah_write_barrier_impl(GraphKit* kit, Node* obj) const {
152 if (! ShenandoahBarrierNode::needs_barrier(&__ gvn(), NULL, obj, NULL, true)) {
153 return obj;
154 }
155 const Type* obj_type = obj->bottom_type();
156 const TypePtr* adr_type = ShenandoahBarrierNode::brooks_pointer_type(obj_type);
157 Node* n = shenandoah_write_barrier_helper(kit, obj, adr_type);
158 __ record_for_igvn(n);
159 return n;
160 }
161
162 bool ShenandoahBarrierSetC2::satb_can_remove_pre_barrier(GraphKit* kit, PhaseTransform* phase, Node* adr,
163 BasicType bt, uint adr_idx) const {
164 intptr_t offset = 0;
165 Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset);
166 AllocateNode* alloc = AllocateNode::Ideal_allocation(base, phase);
167
168 if (offset == Type::OffsetBot) {
169 return false; // cannot unalias unless there are precise offsets
170 }
171
172 if (alloc == NULL) {
173 return false; // No allocation found
174 }
175
176 intptr_t size_in_bytes = type2aelembytes(bt);
177
178 Node* mem = __ memory(adr_idx); // start searching here...
179
180 for (int cnt = 0; cnt < 50; cnt++) {
287 Node* no_base = __ top();
288 Node* zero = __ ConI(0);
289 Node* zeroX = __ ConX(0);
290
291 float likely = PROB_LIKELY(0.999);
292 float unlikely = PROB_UNLIKELY(0.999);
293
294 // Offsets into the thread
295 const int index_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset());
296 const int buffer_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset());
297
298 // Now the actual pointers into the thread
299 Node* buffer_adr = __ AddP(no_base, tls, __ ConX(buffer_offset));
300 Node* index_adr = __ AddP(no_base, tls, __ ConX(index_offset));
301
302 // Now some of the values
303 Node* marking;
304 Node* gc_state = __ AddP(no_base, tls, __ ConX(in_bytes(ShenandoahThreadLocalData::gc_state_offset())));
305 Node* ld = __ load(__ ctrl(), gc_state, TypeInt::BYTE, T_BYTE, Compile::AliasIdxRaw);
306 marking = __ AndI(ld, __ ConI(ShenandoahHeap::MARKING));
307 assert(ShenandoahWriteBarrierNode::is_gc_state_load(ld), "Should match the shape");
308
309 // if (!marking)
310 __ if_then(marking, BoolTest::ne, zero, unlikely); {
311 BasicType index_bt = TypeX_X->basic_type();
312 assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 SATBMarkQueue::_index with wrong size.");
313 Node* index = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw);
314
315 if (do_load) {
316 // load original value
317 // alias_idx correct??
318 pre_val = __ load(__ ctrl(), adr, val_type, bt, alias_idx);
319 }
320
321 // if (pre_val != NULL)
322 __ if_then(pre_val, BoolTest::ne, kit->null()); {
323 Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw);
324
325 // is the queue for this thread full?
326 __ if_then(index, BoolTest::ne, zeroX, likely); {
327
344 } __ end_if(); // (!marking)
345
346 // Final sync IdealKit and GraphKit.
347 kit->final_sync(ideal);
348
349 if (ShenandoahSATBBarrier && adr != NULL) {
350 Node* c = kit->control();
351 Node* call = c->in(1)->in(1)->in(1)->in(0);
352 assert(is_shenandoah_wb_pre_call(call), "shenandoah_wb_pre call expected");
353 call->add_req(adr);
354 }
355 }
356
357 bool ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(Node* call) {
358 return call->is_CallLeaf() &&
359 call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry);
360 }
361
362 bool ShenandoahBarrierSetC2::is_shenandoah_wb_call(Node* call) {
363 return call->is_CallLeaf() &&
364 call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_JRT);
365 }
366
367 bool ShenandoahBarrierSetC2::is_shenandoah_marking_if(PhaseTransform *phase, Node* n) {
368 if (n->Opcode() != Op_If) {
369 return false;
370 }
371
372 Node* bol = n->in(1);
373 assert(bol->is_Bool(), "");
374 Node* cmpx = bol->in(1);
375 if (bol->as_Bool()->_test._test == BoolTest::ne &&
376 cmpx->is_Cmp() && cmpx->in(2) == phase->intcon(0) &&
377 is_shenandoah_state_load(cmpx->in(1)->in(1)) &&
378 cmpx->in(1)->in(2)->is_Con() &&
379 cmpx->in(1)->in(2) == phase->intcon(ShenandoahHeap::MARKING)) {
380 return true;
381 }
382
383 return false;
384 }
532 // create result type (range)
533 fields = TypeTuple::fields(0);
534 const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields);
535
536 return TypeFunc::make(domain, range);
537 }
538
539 const TypeFunc* ShenandoahBarrierSetC2::shenandoah_write_barrier_Type() {
540 const Type **fields = TypeTuple::fields(1);
541 fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value
542 const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields);
543
544 // create result type (range)
545 fields = TypeTuple::fields(1);
546 fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL;
547 const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+1, fields);
548
549 return TypeFunc::make(domain, range);
550 }
551
552 void ShenandoahBarrierSetC2::resolve_address(C2Access& access) const {
553 const TypePtr* adr_type = access.addr().type();
554
555 if ((access.decorators() & IN_NATIVE) == 0 && (adr_type->isa_instptr() || adr_type->isa_aryptr())) {
556 int off = adr_type->is_ptr()->offset();
557 int base_off = adr_type->isa_instptr() ? instanceOopDesc::base_offset_in_bytes() :
558 arrayOopDesc::base_offset_in_bytes(adr_type->is_aryptr()->elem()->array_element_basic_type());
559 assert(off != Type::OffsetTop, "unexpected offset");
560 if (off == Type::OffsetBot || off >= base_off) {
561 DecoratorSet decorators = access.decorators();
562 bool is_write = (decorators & C2_WRITE_ACCESS) != 0;
563 GraphKit* kit = NULL;
564 if (access.is_parse_access()) {
565 C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);
566 kit = parse_access.kit();
567 }
568 Node* adr = access.addr().node();
569 assert(adr->is_AddP(), "unexpected address shape");
570 Node* base = adr->in(AddPNode::Base);
571
572 if (is_write) {
573 if (kit != NULL) {
574 base = shenandoah_write_barrier(kit, base);
575 } else {
576 assert(access.is_opt_access(), "either parse or opt access");
577 assert((access.decorators() & C2_ARRAY_COPY) != 0, "can be skipped for clone");
578 }
579 } else {
580 if (adr_type->isa_instptr()) {
581 Compile* C = access.gvn().C;
582 ciField* field = C->alias_type(adr_type)->field();
583
584 // Insert read barrier for Shenandoah.
585 if (field != NULL &&
586 ((ShenandoahOptimizeStaticFinals && field->is_static() && field->is_final()) ||
587 (ShenandoahOptimizeInstanceFinals && !field->is_static() && field->is_final()) ||
588 (ShenandoahOptimizeStableFinals && field->is_stable()))) {
589 // Skip the barrier for special fields
590 } else {
591 if (kit != NULL) {
592 base = shenandoah_read_barrier(kit, base);
593 } else {
594 assert(access.is_opt_access(), "either parse or opt access");
595 assert((access.decorators() & C2_ARRAY_COPY) != 0, "can be skipped for arraycopy");
596 }
597 }
598 } else {
599 if (kit != NULL) {
600 base = shenandoah_read_barrier(kit, base);
601 } else {
602 assert(access.is_opt_access(), "either parse or opt access");
603 assert((access.decorators() & C2_ARRAY_COPY) != 0, "can be skipped for arraycopy");
604 }
605 }
606 }
607 if (base != adr->in(AddPNode::Base)) {
608 assert(kit != NULL, "no barrier should have been added");
609
610 Node* address = adr->in(AddPNode::Address);
611
612 if (address->is_AddP()) {
613 assert(address->in(AddPNode::Base) == adr->in(AddPNode::Base), "unexpected address shape");
614 assert(!address->in(AddPNode::Address)->is_AddP(), "unexpected address shape");
615 assert(address->in(AddPNode::Address) == adr->in(AddPNode::Base), "unexpected address shape");
616 address = address->clone();
617 address->set_req(AddPNode::Base, base);
618 address->set_req(AddPNode::Address, base);
619 address = kit->gvn().transform(address);
620 } else {
621 assert(address == adr->in(AddPNode::Base), "unexpected address shape");
622 address = base;
623 }
624 adr = adr->clone();
625 adr->set_req(AddPNode::Base, base);
626 adr->set_req(AddPNode::Address, address);
627 adr = kit->gvn().transform(adr);
628 access.addr().set_node(adr);
629 }
630 }
631 }
632 }
633
634 Node* ShenandoahBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const {
635 DecoratorSet decorators = access.decorators();
636
637 const TypePtr* adr_type = access.addr().type();
638 Node* adr = access.addr().node();
639
640 bool anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
641 bool on_heap = (decorators & IN_HEAP) != 0;
642
643 if (!access.is_oop() || (!on_heap && !anonymous)) {
644 return BarrierSetC2::store_at_resolved(access, val);
645 }
646
647 if (access.is_parse_access()) {
648 C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);
649 GraphKit* kit = parse_access.kit();
650
651 uint adr_idx = kit->C->get_alias_index(adr_type);
652 assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" );
653 Node* value = val.node();
654 value = shenandoah_storeval_barrier(kit, value);
655 val.set_node(value);
656 shenandoah_write_barrier_pre(kit, true /* do_load */, /*kit->control(),*/ access.base(), adr, adr_idx, val.node(),
657 static_cast<const TypeOopPtr*>(val.type()), NULL /* pre_val */, access.type());
658 } else {
659 assert(access.is_opt_access(), "only for optimization passes");
660 assert(((decorators & C2_TIGHTLY_COUPLED_ALLOC) != 0 || !ShenandoahSATBBarrier) && (decorators & C2_ARRAY_COPY) != 0, "unexpected caller of this code");
661 C2OptAccess& opt_access = static_cast<C2OptAccess&>(access);
662 PhaseGVN& gvn = opt_access.gvn();
663 MergeMemNode* mm = opt_access.mem();
664
665 if (ShenandoahStoreValReadBarrier) {
666 RegionNode* region = new RegionNode(3);
667 const Type* v_t = gvn.type(val.node());
668 Node* phi = new PhiNode(region, v_t->isa_oopptr() ? v_t->is_oopptr()->cast_to_nonconst() : v_t);
669 Node* cmp = gvn.transform(new CmpPNode(val.node(), gvn.zerocon(T_OBJECT)));
670 Node* bol = gvn.transform(new BoolNode(cmp, BoolTest::ne));
671 IfNode* iff = new IfNode(opt_access.ctl(), bol, PROB_LIKELY_MAG(3), COUNT_UNKNOWN);
672
673 gvn.transform(iff);
674 if (gvn.is_IterGVN()) {
675 gvn.is_IterGVN()->_worklist.push(iff);
676 } else {
677 gvn.record_for_igvn(iff);
678 }
679
680 Node* null_true = gvn.transform(new IfFalseNode(iff));
681 Node* null_false = gvn.transform(new IfTrueNode(iff));
682 region->init_req(1, null_true);
683 region->init_req(2, null_false);
684 phi->init_req(1, gvn.zerocon(T_OBJECT));
685 Node* cast = new CastPPNode(val.node(), gvn.type(val.node())->join_speculative(TypePtr::NOTNULL));
686 cast->set_req(0, null_false);
687 cast = gvn.transform(cast);
688 Node* rb = gvn.transform(new ShenandoahReadBarrierNode(null_false, gvn.C->immutable_memory(), cast, false));
689 phi->init_req(2, rb);
690 opt_access.set_ctl(gvn.transform(region));
691 val.set_node(gvn.transform(phi));
692 }
693 if (ShenandoahStoreValEnqueueBarrier) {
694 const TypePtr* adr_type = ShenandoahBarrierNode::brooks_pointer_type(gvn.type(val.node()));
695 int alias = gvn.C->get_alias_index(adr_type);
696 Node* wb = new ShenandoahWriteBarrierNode(gvn.C, opt_access.ctl(), mm->memory_at(alias), val.node());
697 Node* wb_transformed = gvn.transform(wb);
698 Node* enqueue = gvn.transform(new ShenandoahEnqueueBarrierNode(wb_transformed));
699 if (wb_transformed == wb) {
700 Node* proj = gvn.transform(new ShenandoahWBMemProjNode(wb));
701 mm->set_memory_at(alias, proj);
702 }
703 val.set_node(enqueue);
704 }
705 }
706 return BarrierSetC2::store_at_resolved(access, val);
707 }
708
709 Node* ShenandoahBarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const {
710 DecoratorSet decorators = access.decorators();
711
712 Node* adr = access.addr().node();
713 Node* obj = access.base();
714
715 bool mismatched = (decorators & C2_MISMATCHED) != 0;
716 bool unknown = (decorators & ON_UNKNOWN_OOP_REF) != 0;
717 bool on_heap = (decorators & IN_HEAP) != 0;
718 bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
719 bool is_unordered = (decorators & MO_UNORDERED) != 0;
720 bool need_cpu_mem_bar = !is_unordered || mismatched || !on_heap;
721
722 Node* top = Compile::current()->top();
723
724 Node* offset = adr->is_AddP() ? adr->in(AddPNode::Offset) : top;
725 Node* load = BarrierSetC2::load_at_resolved(access, val_type);
726
727 // If we are reading the value of the referent field of a Reference
728 // object (either by using Unsafe directly or through reflection)
729 // then, if SATB is enabled, we need to record the referent in an
730 // SATB log buffer using the pre-barrier mechanism.
731 // Also we need to add memory barrier to prevent commoning reads
732 // from this field across safepoint since GC can change its value.
733 bool need_read_barrier = ShenandoahKeepAliveBarrier &&
734 (on_heap && (on_weak || (unknown && offset != top && obj != top)));
735
736 if (!access.is_oop() || !need_read_barrier) {
737 return load;
738 }
739
740 assert(access.is_parse_access(), "entry not supported at optimization time");
741 C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);
742 GraphKit* kit = parse_access.kit();
743
744 if (on_weak) {
745 // Use the pre-barrier to record the value in the referent field
746 satb_write_barrier_pre(kit, false /* do_load */,
780 if (ShenandoahCASBarrier) {
781 load_store = kit->gvn().transform(new ShenandoahCompareAndExchangeNNode(kit->control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo));
782 } else {
783 load_store = kit->gvn().transform(new CompareAndExchangeNNode(kit->control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo));
784 }
785 } else
786 #endif
787 {
788 if (ShenandoahCASBarrier) {
789 load_store = kit->gvn().transform(new ShenandoahCompareAndExchangePNode(kit->control(), mem, adr, new_val, expected_val, adr_type, value_type->is_oopptr(), mo));
790 } else {
791 load_store = kit->gvn().transform(new CompareAndExchangePNode(kit->control(), mem, adr, new_val, expected_val, adr_type, value_type->is_oopptr(), mo));
792 }
793 }
794
795 access.set_raw_access(load_store);
796 pin_atomic_op(access);
797
798 #ifdef _LP64
799 if (adr->bottom_type()->is_ptr_to_narrowoop()) {
800 return kit->gvn().transform(new DecodeNNode(load_store, load_store->get_ptr_type()));
801 }
802 #endif
803 return load_store;
804 }
805 return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type);
806 }
807
808 Node* ShenandoahBarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
809 Node* new_val, const Type* value_type) const {
810 GraphKit* kit = access.kit();
811 if (access.is_oop()) {
812 new_val = shenandoah_storeval_barrier(kit, new_val);
813 shenandoah_write_barrier_pre(kit, false /* do_load */,
814 NULL, NULL, max_juint, NULL, NULL,
815 expected_val /* pre_val */, T_OBJECT);
816 DecoratorSet decorators = access.decorators();
817 MemNode::MemOrd mo = access.mem_node_mo();
818 Node* mem = access.memory();
819 bool is_weak_cas = (decorators & C2_WEAK_CMPXCHG) != 0;
820 Node* load_store = NULL;
821 Node* adr = access.addr().node();
822 #ifdef _LP64
850 load_store = kit->gvn().transform(new WeakCompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo));
851 } else {
852 load_store = kit->gvn().transform(new CompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo));
853 }
854 }
855 }
856 access.set_raw_access(load_store);
857 pin_atomic_op(access);
858 return load_store;
859 }
860 return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);
861 }
862
863 Node* ShenandoahBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* val, const Type* value_type) const {
864 GraphKit* kit = access.kit();
865 if (access.is_oop()) {
866 val = shenandoah_storeval_barrier(kit, val);
867 }
868 Node* result = BarrierSetC2::atomic_xchg_at_resolved(access, val, value_type);
869 if (access.is_oop()) {
870 shenandoah_write_barrier_pre(kit, false /* do_load */,
871 NULL, NULL, max_juint, NULL, NULL,
872 result /* pre_val */, T_OBJECT);
873 }
874 return result;
875 }
876
877 void ShenandoahBarrierSetC2::clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const {
878 assert(!src->is_AddP(), "unexpected input");
879 src = shenandoah_read_barrier(kit, src);
880 BarrierSetC2::clone(kit, src, dst, size, is_array);
881 }
882
883 Node* ShenandoahBarrierSetC2::resolve(GraphKit* kit, Node* n, DecoratorSet decorators) const {
884 bool is_write = decorators & ACCESS_WRITE;
885 if (is_write) {
886 return shenandoah_write_barrier(kit, n);
887 } else {
888 return shenandoah_read_barrier(kit, n);
889 }
890 }
891
892 Node* ShenandoahBarrierSetC2::obj_allocate(PhaseMacroExpand* macro, Node* ctrl, Node* mem, Node* toobig_false, Node* size_in_bytes,
893 Node*& i_o, Node*& needgc_ctrl,
894 Node*& fast_oop_ctrl, Node*& fast_oop_rawmem,
895 intx prefetch_lines) const {
896 PhaseIterGVN& igvn = macro->igvn();
897
898 // Allocate several words more for the Shenandoah brooks pointer.
899 size_in_bytes = new AddXNode(size_in_bytes, igvn.MakeConX(ShenandoahBrooksPointer::byte_size()));
900 macro->transform_later(size_in_bytes);
901
902 Node* fast_oop = BarrierSetC2::obj_allocate(macro, ctrl, mem, toobig_false, size_in_bytes,
903 i_o, needgc_ctrl, fast_oop_ctrl, fast_oop_rawmem,
904 prefetch_lines);
905
906 // Bump up object for Shenandoah brooks pointer.
907 fast_oop = new AddPNode(macro->top(), fast_oop, igvn.MakeConX(ShenandoahBrooksPointer::byte_size()));
908 macro->transform_later(fast_oop);
909
910 // Initialize Shenandoah brooks pointer to point to the object itself.
911 fast_oop_rawmem = macro->make_store(fast_oop_ctrl, fast_oop_rawmem, fast_oop, ShenandoahBrooksPointer::byte_offset(), fast_oop, T_OBJECT);
912
913 return fast_oop;
914 }
915
916 // Support for GC barriers emitted during parsing
917 bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const {
918 if (node->Opcode() != Op_CallLeaf && node->Opcode() != Op_CallLeafNoFP) {
919 return false;
920 }
921 CallLeafNode *call = node->as_CallLeaf();
922 if (call->_name == NULL) {
923 return false;
924 }
925
926 return strcmp(call->_name, "shenandoah_clone_barrier") == 0 ||
927 strcmp(call->_name, "shenandoah_cas_obj") == 0 ||
928 strcmp(call->_name, "shenandoah_wb_pre") == 0;
929 }
930
931 Node* ShenandoahBarrierSetC2::step_over_gc_barrier(Node* c) const {
932 return ShenandoahBarrierNode::skip_through_barrier(c);
933 }
934
935 bool ShenandoahBarrierSetC2::expand_barriers(Compile* C, PhaseIterGVN& igvn) const {
936 return !ShenandoahWriteBarrierNode::expand(C, igvn);
937 }
938
939 bool ShenandoahBarrierSetC2::optimize_loops(PhaseIdealLoop* phase, LoopOptsMode mode, VectorSet& visited, Node_Stack& nstack, Node_List& worklist) const {
940 if (mode == LoopOptsShenandoahExpand) {
941 assert(UseShenandoahGC, "only for shenandoah");
942 ShenandoahWriteBarrierNode::pin_and_expand(phase);
943 return true;
944 } else if (mode == LoopOptsShenandoahPostExpand) {
945 assert(UseShenandoahGC, "only for shenandoah");
946 visited.Clear();
947 ShenandoahWriteBarrierNode::optimize_after_expansion(visited, nstack, worklist, phase);
948 return true;
949 }
950 GrowableArray<MemoryGraphFixer*> memory_graph_fixers;
951 ShenandoahWriteBarrierNode::optimize_before_expansion(phase, memory_graph_fixers, false);
952 return false;
953 }
954
955 bool ShenandoahBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, ArrayCopyPhase phase) const {
956 bool is_oop = type == T_OBJECT || type == T_ARRAY;
957 if (!is_oop) {
958 return false;
959 }
960
961 if (tightly_coupled_alloc) {
962 if (phase == Optimization) {
963 return false;
964 }
965 return !is_clone;
966 }
967 if (phase == Optimization) {
968 return !ShenandoahStoreValEnqueueBarrier;
969 }
970 return true;
971 }
972
973 bool ShenandoahBarrierSetC2::clone_needs_postbarrier(ArrayCopyNode *ac, PhaseIterGVN& igvn) {
974 Node* src = ac->in(ArrayCopyNode::Src);
975 const TypeOopPtr* src_type = igvn.type(src)->is_oopptr();
976 if (src_type->isa_instptr() != NULL) {
977 ciInstanceKlass* ik = src_type->klass()->as_instance_klass();
978 if ((src_type->klass_is_exact() || (!ik->is_interface() && !ik->has_subklass())) && !ik->has_injected_fields()) {
979 if (ik->has_object_fields()) {
980 return true;
1021 barrier_call->init_req(TypeFunc::Memory , m);
1022 barrier_call->init_req(TypeFunc::ReturnAdr, igvn.C->top());
1023 barrier_call->init_req(TypeFunc::FramePtr, igvn.C->top());
1024 barrier_call->init_req(TypeFunc::Parms+0, dest->in(AddPNode::Base));
1025
1026 barrier_call = igvn.transform(barrier_call);
1027 c = new ProjNode(barrier_call,TypeFunc::Control);
1028 c = igvn.transform(c);
1029 m = new ProjNode(barrier_call, TypeFunc::Memory);
1030 m = igvn.transform(m);
1031
1032 Node* out_c = ac->proj_out(TypeFunc::Control);
1033 Node* out_m = ac->proj_out(TypeFunc::Memory);
1034 igvn.replace_node(out_c, c);
1035 igvn.replace_node(out_m, m);
1036 }
1037
1038
1039 // Support for macro expanded GC barriers
1040 void ShenandoahBarrierSetC2::register_potential_barrier_node(Node* node) const {
1041 if (node->Opcode() == Op_ShenandoahWriteBarrier) {
1042 state()->add_shenandoah_barrier((ShenandoahWriteBarrierNode*) node);
1043 }
1044 }
1045
1046 void ShenandoahBarrierSetC2::unregister_potential_barrier_node(Node* node) const {
1047 if (node->Opcode() == Op_ShenandoahWriteBarrier) {
1048 state()->remove_shenandoah_barrier((ShenandoahWriteBarrierNode*) node);
1049 }
1050 }
1051
1052 void ShenandoahBarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* n) const {
1053 if (is_shenandoah_wb_pre_call(n)) {
1054 shenandoah_eliminate_wb_pre(n, ¯o->igvn());
1055 }
1056 }
1057
1058 void ShenandoahBarrierSetC2::shenandoah_eliminate_wb_pre(Node* call, PhaseIterGVN* igvn) const {
1059 assert(UseShenandoahGC && is_shenandoah_wb_pre_call(call), "");
1060 Node* c = call->as_Call()->proj_out(TypeFunc::Control);
1061 c = c->unique_ctrl_out();
1062 assert(c->is_Region() && c->req() == 3, "where's the pre barrier control flow?");
1063 c = c->unique_ctrl_out();
1064 assert(c->is_Region() && c->req() == 3, "where's the pre barrier control flow?");
1065 Node* iff = c->in(1)->is_IfProj() ? c->in(1)->in(0) : c->in(2)->in(0);
1066 assert(iff->is_If(), "expect test");
1067 if (!is_shenandoah_marking_if(igvn, iff)) {
1068 c = c->unique_ctrl_out();
1074 igvn->replace_node(cmpx, igvn->makecon(TypeInt::CC_EQ));
1075 igvn->rehash_node_delayed(call);
1076 call->del_req(call->req()-1);
1077 }
1078
1079 void ShenandoahBarrierSetC2::enqueue_useful_gc_barrier(PhaseIterGVN* igvn, Node* node) const {
1080 if (node->Opcode() == Op_AddP && ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(node)) {
1081 igvn->add_users_to_worklist(node);
1082 }
1083 }
1084
1085 void ShenandoahBarrierSetC2::eliminate_useless_gc_barriers(Unique_Node_List &useful, Compile* C) const {
1086 for (uint i = 0; i < useful.size(); i++) {
1087 Node* n = useful.at(i);
1088 if (n->Opcode() == Op_AddP && ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(n)) {
1089 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
1090 C->record_for_igvn(n->fast_out(i));
1091 }
1092 }
1093 }
1094 for (int i = state()->shenandoah_barriers_count()-1; i >= 0; i--) {
1095 ShenandoahWriteBarrierNode* n = state()->shenandoah_barrier(i);
1096 if (!useful.member(n)) {
1097 state()->remove_shenandoah_barrier(n);
1098 }
1099 }
1100
1101 }
1102
1103 bool ShenandoahBarrierSetC2::has_special_unique_user(const Node* node) const {
1104 assert(node->outcnt() == 1, "match only for unique out");
1105 Node* n = node->unique_out();
1106 return node->Opcode() == Op_ShenandoahWriteBarrier && n->Opcode() == Op_ShenandoahWBMemProj;
1107 }
1108
1109 void ShenandoahBarrierSetC2::add_users_to_worklist(Unique_Node_List* worklist) const {}
1110
1111 void* ShenandoahBarrierSetC2::create_barrier_state(Arena* comp_arena) const {
1112 return new(comp_arena) ShenandoahBarrierSetC2State(comp_arena);
1113 }
1114
1115 ShenandoahBarrierSetC2State* ShenandoahBarrierSetC2::state() const {
1116 return reinterpret_cast<ShenandoahBarrierSetC2State*>(Compile::current()->barrier_set_state());
1117 }
1118
1119 // If the BarrierSetC2 state has kept macro nodes in its compilation unit state to be
1120 // expanded later, then now is the time to do so.
1121 bool ShenandoahBarrierSetC2::expand_macro_nodes(PhaseMacroExpand* macro) const { return false; }
1122
1123 #ifdef ASSERT
1124 void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase phase) const {
1125 if (ShenandoahVerifyOptoBarriers && phase == BarrierSetC2::BeforeExpand) {
1126 ShenandoahBarrierNode::verify(Compile::current()->root());
1127 } else if (phase == BarrierSetC2::BeforeCodeGen) {
1128 // Verify G1 pre-barriers
1129 const int marking_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset());
1130
1131 ResourceArea *area = Thread::current()->resource_area();
1132 Unique_Node_List visited(area);
1133 Node_List worklist(area);
1134 // We're going to walk control flow backwards starting from the Root
1135 worklist.push(compile->root());
1136 while (worklist.size() > 0) {
1137 Node *x = worklist.pop();
1138 if (x == NULL || x == compile->top()) continue;
1139 if (visited.member(x)) {
1140 continue;
1141 } else {
1142 visited.push(x);
1143 }
1144
1145 if (x->is_Region()) {
1146 for (uint i = 1; i < x->req(); i++) {
1212 PhaseIterGVN* igvn = phase->is_IterGVN();
1213 if (in1 != n->in(1)) {
1214 if (igvn != NULL) {
1215 n->set_req_X(1, in1, igvn);
1216 } else {
1217 n->set_req(1, in1);
1218 }
1219 assert(in2 == n->in(2), "only one change");
1220 return n;
1221 }
1222 if (in2 != n->in(2)) {
1223 if (igvn != NULL) {
1224 n->set_req_X(2, in2, igvn);
1225 } else {
1226 n->set_req(2, in2);
1227 }
1228 return n;
1229 }
1230 } else if (can_reshape &&
1231 n->Opcode() == Op_If &&
1232 ShenandoahWriteBarrierNode::is_heap_stable_test(n) &&
1233 n->in(0) != NULL) {
1234 Node* dom = n->in(0);
1235 Node* prev_dom = n;
1236 int op = n->Opcode();
1237 int dist = 16;
1238 // Search up the dominator tree for another heap stable test
1239 while (dom->Opcode() != op || // Not same opcode?
1240 !ShenandoahWriteBarrierNode::is_heap_stable_test(dom) || // Not same input 1?
1241 prev_dom->in(0) != dom) { // One path of test does not dominate?
1242 if (dist < 0) return NULL;
1243
1244 dist--;
1245 prev_dom = dom;
1246 dom = IfNode::up_one_dom(dom);
1247 if (!dom) return NULL;
1248 }
1249
1250 // Check that we did not follow a loop back to ourselves
1251 if (n == dom) {
1252 return NULL;
1253 }
1254
1255 return n->as_If()->dominated_by(prev_dom, phase->is_IterGVN());
1256 }
1257
1258 return NULL;
1259 }
1260
1261 Node* ShenandoahBarrierSetC2::identity_node(PhaseGVN* phase, Node* n) const {
1262 if (n->is_Load()) {
1263 Node *mem = n->in(MemNode::Memory);
1264 Node *value = n->as_Load()->can_see_stored_value(mem, phase);
1265 if (value) {
1266 PhaseIterGVN *igvn = phase->is_IterGVN();
1267 if (igvn != NULL &&
1268 value->is_Phi() &&
1269 value->req() > 2 &&
1270 value->in(1) != NULL &&
1271 value->in(1)->is_ShenandoahBarrier()) {
1272 if (igvn->_worklist.member(value) ||
1273 igvn->_worklist.member(value->in(0)) ||
1274 (value->in(0)->in(1) != NULL &&
1275 value->in(0)->in(1)->is_IfProj() &&
1276 (igvn->_worklist.member(value->in(0)->in(1)) ||
1277 (value->in(0)->in(1)->in(0) != NULL &&
1278 igvn->_worklist.member(value->in(0)->in(1)->in(0)))))) {
1279 igvn->_worklist.push(n);
1280 return n;
1281 }
1282 }
1283 // (This works even when value is a Con, but LoadNode::Value
1284 // usually runs first, producing the singleton type of the Con.)
1285 Node *value_no_barrier = step_over_gc_barrier(value->Opcode() == Op_EncodeP ? value->in(1) : value);
1286 if (value->Opcode() == Op_EncodeP) {
1287 if (value_no_barrier != value->in(1)) {
1288 Node *encode = value->clone();
1289 encode->set_req(1, value_no_barrier);
1290 encode = phase->transform(encode);
1291 return encode;
1292 }
1293 } else {
1294 return value_no_barrier;
1295 }
1296 }
1297 }
1298 return n;
1299 }
1300
1301 bool ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(Node* n) {
1302 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
1303 Node* u = n->fast_out(i);
1304 if (!is_shenandoah_wb_pre_call(u)) {
1305 return false;
1306 }
1307 }
1308 return n->outcnt() > 0;
1309 }
1310
1311 bool ShenandoahBarrierSetC2::flatten_gc_alias_type(const TypePtr*& adr_type) const {
1312 int offset = adr_type->offset();
1313 if (offset == ShenandoahBrooksPointer::byte_offset()) {
1314 if (adr_type->isa_aryptr()) {
1315 adr_type = TypeAryPtr::make(adr_type->ptr(), adr_type->isa_aryptr()->ary(), adr_type->isa_aryptr()->klass(), false, offset);
1316 } else if (adr_type->isa_instptr()) {
1317 adr_type = TypeInstPtr::make(adr_type->ptr(), ciEnv::current()->Object_klass(), false, NULL, offset);
1318 }
1319 return true;
1320 } else {
1321 return false;
1322 }
1323 }
1324
1325 bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, uint opcode) const {
1326 switch (opcode) {
1327 case Op_CallLeaf:
1328 case Op_CallLeafNoFP: {
1329 assert (n->is_Call(), "");
1330 CallNode *call = n->as_Call();
1331 if (ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(call)) {
1332 uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type()->domain()->cnt();
1333 if (call->req() > cnt) {
1334 assert(call->req() == cnt + 1, "only one extra input");
1335 Node *addp = call->in(cnt);
1336 assert(!ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(addp), "useless address computation?");
1337 call->del_req(cnt);
1338 }
1339 }
1340 return false;
1341 }
1342 case Op_ShenandoahCompareAndSwapP:
1343 case Op_ShenandoahCompareAndSwapN:
1344 case Op_ShenandoahWeakCompareAndSwapN:
1345 case Op_ShenandoahWeakCompareAndSwapP:
1346 case Op_ShenandoahCompareAndExchangeP:
1347 case Op_ShenandoahCompareAndExchangeN:
1348 #ifdef ASSERT
1349 if( VerifyOptoOopOffsets ) {
1350 MemNode* mem = n->as_Mem();
1351 // Check to see if address types have grounded out somehow.
1352 const TypeInstPtr *tp = mem->in(MemNode::Address)->bottom_type()->isa_instptr();
1353 ciInstanceKlass *k = tp->klass()->as_instance_klass();
1354 bool oop_offset_is_sane = k->contains_field_offset(tp->offset());
1355 assert( !tp || oop_offset_is_sane, "" );
1356 }
1357 #endif
1358 return true;
1359 case Op_ShenandoahReadBarrier:
1360 return true;
1361 case Op_ShenandoahWriteBarrier:
1362 assert(false, "should have been expanded already");
1363 return true;
1364 default:
1365 return false;
1366 }
1367 }
1368
1369 #ifdef ASSERT
1370 bool ShenandoahBarrierSetC2::verify_gc_alias_type(const TypePtr* adr_type, int offset) const {
1371 if (offset == ShenandoahBrooksPointer::byte_offset() &&
1372 (adr_type->base() == Type::AryPtr || adr_type->base() == Type::OopPtr)) {
1373 return true;
1374 } else {
1375 return false;
1376 }
1377 }
1378 #endif
1379
1380 bool ShenandoahBarrierSetC2::escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const {
1381 switch (opcode) {
1382 case Op_ShenandoahCompareAndExchangeP:
1383 case Op_ShenandoahCompareAndExchangeN:
1384 conn_graph->add_objload_to_connection_graph(n, delayed_worklist);
1385 // fallthrough
1386 case Op_ShenandoahWeakCompareAndSwapP:
1387 case Op_ShenandoahWeakCompareAndSwapN:
1388 case Op_ShenandoahCompareAndSwapP:
1389 case Op_ShenandoahCompareAndSwapN:
1390 conn_graph->add_to_congraph_unsafe_access(n, opcode, delayed_worklist);
1391 return true;
1392 case Op_StoreP: {
1393 Node* adr = n->in(MemNode::Address);
1394 const Type* adr_type = gvn->type(adr);
1395 // Pointer stores in G1 barriers looks like unsafe access.
1396 // Ignore such stores to be able scalar replace non-escaping
1397 // allocations.
1398 if (adr_type->isa_rawptr() && adr->is_AddP()) {
1399 Node* base = conn_graph->get_addp_base(adr);
1400 if (base->Opcode() == Op_LoadP &&
1401 base->in(MemNode::Address)->is_AddP()) {
1402 adr = base->in(MemNode::Address);
1403 Node* tls = conn_graph->get_addp_base(adr);
1404 if (tls->Opcode() == Op_ThreadLocal) {
1405 int offs = (int) gvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot);
1406 const int buf_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset());
1407 if (offs == buf_offset) {
1408 return true; // Pre barrier previous oop value store.
1409 }
1410 }
1411 }
1412 }
1413 return false;
1414 }
1415 case Op_ShenandoahReadBarrier:
1416 case Op_ShenandoahWriteBarrier:
1417 // Barriers 'pass through' its arguments. I.e. what goes in, comes out.
1418 // It doesn't escape.
1419 conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(ShenandoahBarrierNode::ValueIn), delayed_worklist);
1420 break;
1421 case Op_ShenandoahEnqueueBarrier:
1422 conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), delayed_worklist);
1423 break;
1424 default:
1425 // Nothing
1426 break;
1427 }
1428 return false;
1429 }
1430
1431 bool ShenandoahBarrierSetC2::escape_add_final_edges(ConnectionGraph* conn_graph, PhaseGVN* gvn, Node* n, uint opcode) const {
1432 switch (opcode) {
1433 case Op_ShenandoahCompareAndExchangeP:
1434 case Op_ShenandoahCompareAndExchangeN: {
1435 Node *adr = n->in(MemNode::Address);
1436 conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, adr, NULL);
1437 // fallthrough
1438 }
1439 case Op_ShenandoahCompareAndSwapP:
1440 case Op_ShenandoahCompareAndSwapN:
1441 case Op_ShenandoahWeakCompareAndSwapP:
1442 case Op_ShenandoahWeakCompareAndSwapN:
1443 return conn_graph->add_final_edges_unsafe_access(n, opcode);
1444 case Op_ShenandoahReadBarrier:
1445 case Op_ShenandoahWriteBarrier:
1446 // Barriers 'pass through' its arguments. I.e. what goes in, comes out.
1447 // It doesn't escape.
1448 conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(ShenandoahBarrierNode::ValueIn), NULL);
1449 return true;
1450 case Op_ShenandoahEnqueueBarrier:
1451 conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), NULL);
1452 return true;
1453 default:
1454 // Nothing
1455 break;
1456 }
1457 return false;
1458 }
1459
1460 bool ShenandoahBarrierSetC2::escape_has_out_with_unsafe_object(Node* n) const {
1461 return n->has_out_with(Op_ShenandoahCompareAndExchangeP) || n->has_out_with(Op_ShenandoahCompareAndExchangeN) ||
1462 n->has_out_with(Op_ShenandoahCompareAndSwapP, Op_ShenandoahCompareAndSwapN, Op_ShenandoahWeakCompareAndSwapP, Op_ShenandoahWeakCompareAndSwapN);
1463
1464 }
1465
1466 bool ShenandoahBarrierSetC2::escape_is_barrier_node(Node* n) const {
1467 return n->is_ShenandoahBarrier();
1468 }
1469
1470 bool ShenandoahBarrierSetC2::matcher_find_shared_visit(Matcher* matcher, Matcher::MStack& mstack, Node* n, uint opcode, bool& mem_op, int& mem_addr_idx) const {
1471 switch (opcode) {
1472 case Op_ShenandoahReadBarrier:
1473 if (n->in(ShenandoahBarrierNode::ValueIn)->is_DecodeNarrowPtr()) {
1474 matcher->set_shared(n->in(ShenandoahBarrierNode::ValueIn)->in(1));
1475 }
1476 matcher->set_shared(n);
1477 return true;
1478 default:
1479 break;
1480 }
1481 return false;
1482 }
1483
1484 bool ShenandoahBarrierSetC2::matcher_find_shared_post_visit(Matcher* matcher, Node* n, uint opcode) const {
1485 switch (opcode) {
1486 case Op_ShenandoahCompareAndExchangeP:
1487 case Op_ShenandoahCompareAndExchangeN:
1488 case Op_ShenandoahWeakCompareAndSwapP:
1489 case Op_ShenandoahWeakCompareAndSwapN:
1490 case Op_ShenandoahCompareAndSwapP:
1491 case Op_ShenandoahCompareAndSwapN: { // Convert trinary to binary-tree
1492 Node* newval = n->in(MemNode::ValueIn);
1493 Node* oldval = n->in(LoadStoreConditionalNode::ExpectedIn);
1494 Node* pair = new BinaryNode(oldval, newval);
1495 n->set_req(MemNode::ValueIn,pair);
1496 n->del_req(LoadStoreConditionalNode::ExpectedIn);
1497 return true;
1498 }
1499 default:
1500 break;
1501 }
1502 return false;
1503 }
1504
1505 bool ShenandoahBarrierSetC2::matcher_is_store_load_barrier(Node* x, uint xop) const {
1506 return xop == Op_ShenandoahCompareAndExchangeP ||
1507 xop == Op_ShenandoahCompareAndExchangeN ||
1508 xop == Op_ShenandoahWeakCompareAndSwapP ||
1509 xop == Op_ShenandoahWeakCompareAndSwapN ||
1510 xop == Op_ShenandoahCompareAndSwapN ||
1511 xop == Op_ShenandoahCompareAndSwapP;
1512 }
1513
1514 void ShenandoahBarrierSetC2::igvn_add_users_to_worklist(PhaseIterGVN* igvn, Node* use) const {
1515 if (use->is_ShenandoahBarrier()) {
1516 for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) {
1517 Node* u = use->fast_out(i2);
1518 Node* cmp = use->find_out_with(Op_CmpP);
1519 if (u->Opcode() == Op_CmpP) {
1520 igvn->_worklist.push(cmp);
1521 }
1522 }
1523 }
1524 }
1525
1526 void ShenandoahBarrierSetC2::ccp_analyze(PhaseCCP* ccp, Unique_Node_List& worklist, Node* use) const {
1527 if (use->is_ShenandoahBarrier()) {
1528 for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) {
1529 Node* p = use->fast_out(i2);
1530 if (p->Opcode() == Op_AddP) {
1531 for (DUIterator_Fast i3max, i3 = p->fast_outs(i3max); i3 < i3max; i3++) {
1532 Node* q = p->fast_out(i3);
1533 if (q->is_Load()) {
1534 if(q->bottom_type() != ccp->type(q)) {
1535 worklist.push(q);
1536 }
1537 }
1538 }
1539 }
1540 }
1541 }
1542 }
1543
1544 Node* ShenandoahBarrierSetC2::split_if_pre(PhaseIdealLoop* phase, Node* n) const {
1545 if (n->Opcode() == Op_ShenandoahReadBarrier) {
1546 ((ShenandoahReadBarrierNode*)n)->try_move(phase);
1547 } else if (n->Opcode() == Op_ShenandoahWriteBarrier) {
1548 return ((ShenandoahWriteBarrierNode*)n)->try_split_thru_phi(phase);
1549 }
1550
1551 return NULL;
1552 }
1553
1554 bool ShenandoahBarrierSetC2::build_loop_late_post(PhaseIdealLoop* phase, Node* n) const {
1555 return ShenandoahBarrierNode::build_loop_late_post(phase, n);
1556 }
1557
1558 bool ShenandoahBarrierSetC2::sink_node(PhaseIdealLoop* phase, Node* n, Node* x, Node* x_ctrl, Node* n_ctrl) const {
1559 if (n->is_ShenandoahBarrier()) {
1560 return x->as_ShenandoahBarrier()->sink_node(phase, x_ctrl, n_ctrl);
1561 }
1562 if (n->is_MergeMem()) {
1563 // PhaseIdealLoop::split_if_with_blocks_post() would:
1564 // _igvn._worklist.yank(x);
1565 // which sometimes causes chains of MergeMem which some of
1566 // shenandoah specific code doesn't support
1567 phase->register_new_node(x, x_ctrl);
1568 return true;
1569 }
1570 return false;
1571 }
|
26 #include "gc/shenandoah/shenandoahHeap.hpp"
27 #include "gc/shenandoah/shenandoahHeuristics.hpp"
28 #include "gc/shenandoah/shenandoahRuntime.hpp"
29 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
30 #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
31 #include "gc/shenandoah/c2/shenandoahSupport.hpp"
32 #include "opto/arraycopynode.hpp"
33 #include "opto/escape.hpp"
34 #include "opto/graphKit.hpp"
35 #include "opto/idealKit.hpp"
36 #include "opto/macro.hpp"
37 #include "opto/movenode.hpp"
38 #include "opto/narrowptrnode.hpp"
39 #include "opto/rootnode.hpp"
40
41 ShenandoahBarrierSetC2* ShenandoahBarrierSetC2::bsc2() {
42 return reinterpret_cast<ShenandoahBarrierSetC2*>(BarrierSet::barrier_set()->barrier_set_c2());
43 }
44
45 ShenandoahBarrierSetC2State::ShenandoahBarrierSetC2State(Arena* comp_arena)
46 : _enqueue_barriers(new (comp_arena) GrowableArray<ShenandoahEnqueueBarrierNode*>(comp_arena, 8, 0, NULL)),
47 _load_reference_barriers(new (comp_arena) GrowableArray<ShenandoahLoadReferenceBarrierNode*>(comp_arena, 8, 0, NULL)) {
48 }
49
50 int ShenandoahBarrierSetC2State::enqueue_barriers_count() const {
51 return _enqueue_barriers->length();
52 }
53
54 ShenandoahEnqueueBarrierNode* ShenandoahBarrierSetC2State::enqueue_barrier(int idx) const {
55 return _enqueue_barriers->at(idx);
56 }
57
58 void ShenandoahBarrierSetC2State::add_enqueue_barrier(ShenandoahEnqueueBarrierNode * n) {
59 assert(!_enqueue_barriers->contains(n), "duplicate entry in barrier list");
60 _enqueue_barriers->append(n);
61 }
62
63 void ShenandoahBarrierSetC2State::remove_enqueue_barrier(ShenandoahEnqueueBarrierNode * n) {
64 if (_enqueue_barriers->contains(n)) {
65 _enqueue_barriers->remove(n);
66 }
67 }
68
69 int ShenandoahBarrierSetC2State::load_reference_barriers_count() const {
70 return _load_reference_barriers->length();
71 }
72
73 ShenandoahLoadReferenceBarrierNode* ShenandoahBarrierSetC2State::load_reference_barrier(int idx) const {
74 return _load_reference_barriers->at(idx);
75 }
76
77 void ShenandoahBarrierSetC2State::add_load_reference_barrier(ShenandoahLoadReferenceBarrierNode * n) {
78 assert(!_load_reference_barriers->contains(n), "duplicate entry in barrier list");
79 _load_reference_barriers->append(n);
80 }
81
82 void ShenandoahBarrierSetC2State::remove_load_reference_barrier(ShenandoahLoadReferenceBarrierNode * n) {
83 if (_load_reference_barriers->contains(n)) {
84 _load_reference_barriers->remove(n);
85 }
86 }
87
88 Node* ShenandoahBarrierSetC2::shenandoah_storeval_barrier(GraphKit* kit, Node* obj) const {
89 if (ShenandoahStoreValEnqueueBarrier) {
90 obj = shenandoah_enqueue_barrier(kit, obj);
91 }
92 return obj;
93 }
94
95 #define __ kit->
96
97 bool ShenandoahBarrierSetC2::satb_can_remove_pre_barrier(GraphKit* kit, PhaseTransform* phase, Node* adr,
98 BasicType bt, uint adr_idx) const {
99 intptr_t offset = 0;
100 Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset);
101 AllocateNode* alloc = AllocateNode::Ideal_allocation(base, phase);
102
103 if (offset == Type::OffsetBot) {
104 return false; // cannot unalias unless there are precise offsets
105 }
106
107 if (alloc == NULL) {
108 return false; // No allocation found
109 }
110
111 intptr_t size_in_bytes = type2aelembytes(bt);
112
113 Node* mem = __ memory(adr_idx); // start searching here...
114
115 for (int cnt = 0; cnt < 50; cnt++) {
222 Node* no_base = __ top();
223 Node* zero = __ ConI(0);
224 Node* zeroX = __ ConX(0);
225
226 float likely = PROB_LIKELY(0.999);
227 float unlikely = PROB_UNLIKELY(0.999);
228
229 // Offsets into the thread
230 const int index_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset());
231 const int buffer_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset());
232
233 // Now the actual pointers into the thread
234 Node* buffer_adr = __ AddP(no_base, tls, __ ConX(buffer_offset));
235 Node* index_adr = __ AddP(no_base, tls, __ ConX(index_offset));
236
237 // Now some of the values
238 Node* marking;
239 Node* gc_state = __ AddP(no_base, tls, __ ConX(in_bytes(ShenandoahThreadLocalData::gc_state_offset())));
240 Node* ld = __ load(__ ctrl(), gc_state, TypeInt::BYTE, T_BYTE, Compile::AliasIdxRaw);
241 marking = __ AndI(ld, __ ConI(ShenandoahHeap::MARKING));
242 assert(ShenandoahBarrierC2Support::is_gc_state_load(ld), "Should match the shape");
243
244 // if (!marking)
245 __ if_then(marking, BoolTest::ne, zero, unlikely); {
246 BasicType index_bt = TypeX_X->basic_type();
247 assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 SATBMarkQueue::_index with wrong size.");
248 Node* index = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw);
249
250 if (do_load) {
251 // load original value
252 // alias_idx correct??
253 pre_val = __ load(__ ctrl(), adr, val_type, bt, alias_idx);
254 }
255
256 // if (pre_val != NULL)
257 __ if_then(pre_val, BoolTest::ne, kit->null()); {
258 Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw);
259
260 // is the queue for this thread full?
261 __ if_then(index, BoolTest::ne, zeroX, likely); {
262
279 } __ end_if(); // (!marking)
280
281 // Final sync IdealKit and GraphKit.
282 kit->final_sync(ideal);
283
284 if (ShenandoahSATBBarrier && adr != NULL) {
285 Node* c = kit->control();
286 Node* call = c->in(1)->in(1)->in(1)->in(0);
287 assert(is_shenandoah_wb_pre_call(call), "shenandoah_wb_pre call expected");
288 call->add_req(adr);
289 }
290 }
291
292 bool ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(Node* call) {
293 return call->is_CallLeaf() &&
294 call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry);
295 }
296
297 bool ShenandoahBarrierSetC2::is_shenandoah_wb_call(Node* call) {
298 return call->is_CallLeaf() &&
299 call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT);
300 }
301
302 bool ShenandoahBarrierSetC2::is_shenandoah_marking_if(PhaseTransform *phase, Node* n) {
303 if (n->Opcode() != Op_If) {
304 return false;
305 }
306
307 Node* bol = n->in(1);
308 assert(bol->is_Bool(), "");
309 Node* cmpx = bol->in(1);
310 if (bol->as_Bool()->_test._test == BoolTest::ne &&
311 cmpx->is_Cmp() && cmpx->in(2) == phase->intcon(0) &&
312 is_shenandoah_state_load(cmpx->in(1)->in(1)) &&
313 cmpx->in(1)->in(2)->is_Con() &&
314 cmpx->in(1)->in(2) == phase->intcon(ShenandoahHeap::MARKING)) {
315 return true;
316 }
317
318 return false;
319 }
467 // create result type (range)
468 fields = TypeTuple::fields(0);
469 const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields);
470
471 return TypeFunc::make(domain, range);
472 }
473
474 const TypeFunc* ShenandoahBarrierSetC2::shenandoah_write_barrier_Type() {
475 const Type **fields = TypeTuple::fields(1);
476 fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value
477 const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields);
478
479 // create result type (range)
480 fields = TypeTuple::fields(1);
481 fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL;
482 const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+1, fields);
483
484 return TypeFunc::make(domain, range);
485 }
486
487 Node* ShenandoahBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const {
488 DecoratorSet decorators = access.decorators();
489
490 const TypePtr* adr_type = access.addr().type();
491 Node* adr = access.addr().node();
492
493 bool anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
494 bool on_heap = (decorators & IN_HEAP) != 0;
495
496 if (!access.is_oop() || (!on_heap && !anonymous)) {
497 return BarrierSetC2::store_at_resolved(access, val);
498 }
499
500 if (access.is_parse_access()) {
501 C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);
502 GraphKit* kit = parse_access.kit();
503
504 uint adr_idx = kit->C->get_alias_index(adr_type);
505 assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" );
506 Node* value = val.node();
507 value = shenandoah_storeval_barrier(kit, value);
508 val.set_node(value);
509 shenandoah_write_barrier_pre(kit, true /* do_load */, /*kit->control(),*/ access.base(), adr, adr_idx, val.node(),
510 static_cast<const TypeOopPtr*>(val.type()), NULL /* pre_val */, access.type());
511 } else {
512 assert(access.is_opt_access(), "only for optimization passes");
513 assert(((decorators & C2_TIGHTLY_COUPLED_ALLOC) != 0 || !ShenandoahSATBBarrier) && (decorators & C2_ARRAY_COPY) != 0, "unexpected caller of this code");
514 C2OptAccess& opt_access = static_cast<C2OptAccess&>(access);
515 PhaseGVN& gvn = opt_access.gvn();
516 MergeMemNode* mm = opt_access.mem();
517
518 if (ShenandoahStoreValEnqueueBarrier) {
519 Node* enqueue = gvn.transform(new ShenandoahEnqueueBarrierNode(val.node()));
520 val.set_node(enqueue);
521 }
522 }
523 return BarrierSetC2::store_at_resolved(access, val);
524 }
525
526 Node* ShenandoahBarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const {
527 DecoratorSet decorators = access.decorators();
528
529 Node* adr = access.addr().node();
530 Node* obj = access.base();
531
532 bool mismatched = (decorators & C2_MISMATCHED) != 0;
533 bool unknown = (decorators & ON_UNKNOWN_OOP_REF) != 0;
534 bool on_heap = (decorators & IN_HEAP) != 0;
535 bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
536 bool is_unordered = (decorators & MO_UNORDERED) != 0;
537 bool need_cpu_mem_bar = !is_unordered || mismatched || !on_heap;
538
539 Node* top = Compile::current()->top();
540
541 Node* offset = adr->is_AddP() ? adr->in(AddPNode::Offset) : top;
542 Node* load = BarrierSetC2::load_at_resolved(access, val_type);
543
544 if (access.is_oop()) {
545 if (ShenandoahLoadRefBarrier) {
546 load = new ShenandoahLoadReferenceBarrierNode(NULL, load);
547 if (access.is_parse_access()) {
548 load = static_cast<C2ParseAccess &>(access).kit()->gvn().transform(load);
549 } else {
550 load = static_cast<C2OptAccess &>(access).gvn().transform(load);
551 }
552 }
553 }
554
555 // If we are reading the value of the referent field of a Reference
556 // object (either by using Unsafe directly or through reflection)
557 // then, if SATB is enabled, we need to record the referent in an
558 // SATB log buffer using the pre-barrier mechanism.
559 // Also we need to add memory barrier to prevent commoning reads
560 // from this field across safepoint since GC can change its value.
561 bool need_read_barrier = ShenandoahKeepAliveBarrier &&
562 (on_heap && (on_weak || (unknown && offset != top && obj != top)));
563
564 if (!access.is_oop() || !need_read_barrier) {
565 return load;
566 }
567
568 assert(access.is_parse_access(), "entry not supported at optimization time");
569 C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);
570 GraphKit* kit = parse_access.kit();
571
572 if (on_weak) {
573 // Use the pre-barrier to record the value in the referent field
574 satb_write_barrier_pre(kit, false /* do_load */,
608 if (ShenandoahCASBarrier) {
609 load_store = kit->gvn().transform(new ShenandoahCompareAndExchangeNNode(kit->control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo));
610 } else {
611 load_store = kit->gvn().transform(new CompareAndExchangeNNode(kit->control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo));
612 }
613 } else
614 #endif
615 {
616 if (ShenandoahCASBarrier) {
617 load_store = kit->gvn().transform(new ShenandoahCompareAndExchangePNode(kit->control(), mem, adr, new_val, expected_val, adr_type, value_type->is_oopptr(), mo));
618 } else {
619 load_store = kit->gvn().transform(new CompareAndExchangePNode(kit->control(), mem, adr, new_val, expected_val, adr_type, value_type->is_oopptr(), mo));
620 }
621 }
622
623 access.set_raw_access(load_store);
624 pin_atomic_op(access);
625
626 #ifdef _LP64
627 if (adr->bottom_type()->is_ptr_to_narrowoop()) {
628 load_store = kit->gvn().transform(new DecodeNNode(load_store, load_store->get_ptr_type()));
629 }
630 #endif
631 load_store = kit->gvn().transform(new ShenandoahLoadReferenceBarrierNode(NULL, load_store));
632 return load_store;
633 }
634 return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type);
635 }
636
637 Node* ShenandoahBarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
638 Node* new_val, const Type* value_type) const {
639 GraphKit* kit = access.kit();
640 if (access.is_oop()) {
641 new_val = shenandoah_storeval_barrier(kit, new_val);
642 shenandoah_write_barrier_pre(kit, false /* do_load */,
643 NULL, NULL, max_juint, NULL, NULL,
644 expected_val /* pre_val */, T_OBJECT);
645 DecoratorSet decorators = access.decorators();
646 MemNode::MemOrd mo = access.mem_node_mo();
647 Node* mem = access.memory();
648 bool is_weak_cas = (decorators & C2_WEAK_CMPXCHG) != 0;
649 Node* load_store = NULL;
650 Node* adr = access.addr().node();
651 #ifdef _LP64
679 load_store = kit->gvn().transform(new WeakCompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo));
680 } else {
681 load_store = kit->gvn().transform(new CompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo));
682 }
683 }
684 }
685 access.set_raw_access(load_store);
686 pin_atomic_op(access);
687 return load_store;
688 }
689 return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);
690 }
691
692 Node* ShenandoahBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* val, const Type* value_type) const {
693 GraphKit* kit = access.kit();
694 if (access.is_oop()) {
695 val = shenandoah_storeval_barrier(kit, val);
696 }
697 Node* result = BarrierSetC2::atomic_xchg_at_resolved(access, val, value_type);
698 if (access.is_oop()) {
699 result = kit->gvn().transform(new ShenandoahLoadReferenceBarrierNode(NULL, result));
700 shenandoah_write_barrier_pre(kit, false /* do_load */,
701 NULL, NULL, max_juint, NULL, NULL,
702 result /* pre_val */, T_OBJECT);
703 }
704 return result;
705 }
706
707 void ShenandoahBarrierSetC2::clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const {
708 assert(!src->is_AddP(), "unexpected input");
709 BarrierSetC2::clone(kit, src, dst, size, is_array);
710 }
711
712 Node* ShenandoahBarrierSetC2::obj_allocate(PhaseMacroExpand* macro, Node* ctrl, Node* mem, Node* toobig_false, Node* size_in_bytes,
713 Node*& i_o, Node*& needgc_ctrl,
714 Node*& fast_oop_ctrl, Node*& fast_oop_rawmem,
715 intx prefetch_lines) const {
716 PhaseIterGVN& igvn = macro->igvn();
717
718 // Allocate several words more for the Shenandoah brooks pointer.
719 size_in_bytes = new AddXNode(size_in_bytes, igvn.MakeConX(ShenandoahBrooksPointer::byte_size()));
720 macro->transform_later(size_in_bytes);
721
722 Node* fast_oop = BarrierSetC2::obj_allocate(macro, ctrl, mem, toobig_false, size_in_bytes,
723 i_o, needgc_ctrl, fast_oop_ctrl, fast_oop_rawmem,
724 prefetch_lines);
725
726 // Bump up object for Shenandoah brooks pointer.
727 fast_oop = new AddPNode(macro->top(), fast_oop, igvn.MakeConX(ShenandoahBrooksPointer::byte_size()));
728 macro->transform_later(fast_oop);
729
730 // Initialize Shenandoah brooks pointer to point to the object itself.
731 fast_oop_rawmem = macro->make_store(fast_oop_ctrl, fast_oop_rawmem, fast_oop, ShenandoahBrooksPointer::byte_offset(), fast_oop, T_OBJECT);
732
733 return fast_oop;
734 }
735
736 // Support for GC barriers emitted during parsing
737 bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const {
738 if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) return true;
739 if (node->Opcode() != Op_CallLeaf && node->Opcode() != Op_CallLeafNoFP) {
740 return false;
741 }
742 CallLeafNode *call = node->as_CallLeaf();
743 if (call->_name == NULL) {
744 return false;
745 }
746
747 return strcmp(call->_name, "shenandoah_clone_barrier") == 0 ||
748 strcmp(call->_name, "shenandoah_cas_obj") == 0 ||
749 strcmp(call->_name, "shenandoah_wb_pre") == 0;
750 }
751
752 Node* ShenandoahBarrierSetC2::step_over_gc_barrier(Node* c) const {
753 if (c->Opcode() == Op_ShenandoahLoadReferenceBarrier) {
754 return c->in(ShenandoahLoadReferenceBarrierNode::ValueIn);
755 }
756 if (c->Opcode() == Op_ShenandoahEnqueueBarrier) {
757 c = c->in(1);
758 }
759 return c;
760 }
761
762 bool ShenandoahBarrierSetC2::expand_barriers(Compile* C, PhaseIterGVN& igvn) const {
763 return !ShenandoahBarrierC2Support::expand(C, igvn);
764 }
765
766 bool ShenandoahBarrierSetC2::optimize_loops(PhaseIdealLoop* phase, LoopOptsMode mode, VectorSet& visited, Node_Stack& nstack, Node_List& worklist) const {
767 if (mode == LoopOptsShenandoahExpand) {
768 assert(UseShenandoahGC, "only for shenandoah");
769 ShenandoahBarrierC2Support::pin_and_expand(phase);
770 return true;
771 } else if (mode == LoopOptsShenandoahPostExpand) {
772 assert(UseShenandoahGC, "only for shenandoah");
773 visited.Clear();
774 ShenandoahBarrierC2Support::optimize_after_expansion(visited, nstack, worklist, phase);
775 return true;
776 }
777 return false;
778 }
779
780 bool ShenandoahBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, ArrayCopyPhase phase) const {
781 bool is_oop = type == T_OBJECT || type == T_ARRAY;
782 if (!is_oop) {
783 return false;
784 }
785 if (tightly_coupled_alloc) {
786 if (phase == Optimization) {
787 return false;
788 }
789 return !is_clone;
790 }
791 if (phase == Optimization) {
792 return !ShenandoahStoreValEnqueueBarrier;
793 }
794 return true;
795 }
796
797 bool ShenandoahBarrierSetC2::clone_needs_postbarrier(ArrayCopyNode *ac, PhaseIterGVN& igvn) {
798 Node* src = ac->in(ArrayCopyNode::Src);
799 const TypeOopPtr* src_type = igvn.type(src)->is_oopptr();
800 if (src_type->isa_instptr() != NULL) {
801 ciInstanceKlass* ik = src_type->klass()->as_instance_klass();
802 if ((src_type->klass_is_exact() || (!ik->is_interface() && !ik->has_subklass())) && !ik->has_injected_fields()) {
803 if (ik->has_object_fields()) {
804 return true;
845 barrier_call->init_req(TypeFunc::Memory , m);
846 barrier_call->init_req(TypeFunc::ReturnAdr, igvn.C->top());
847 barrier_call->init_req(TypeFunc::FramePtr, igvn.C->top());
848 barrier_call->init_req(TypeFunc::Parms+0, dest->in(AddPNode::Base));
849
850 barrier_call = igvn.transform(barrier_call);
851 c = new ProjNode(barrier_call,TypeFunc::Control);
852 c = igvn.transform(c);
853 m = new ProjNode(barrier_call, TypeFunc::Memory);
854 m = igvn.transform(m);
855
856 Node* out_c = ac->proj_out(TypeFunc::Control);
857 Node* out_m = ac->proj_out(TypeFunc::Memory);
858 igvn.replace_node(out_c, c);
859 igvn.replace_node(out_m, m);
860 }
861
862
863 // Support for macro expanded GC barriers
864 void ShenandoahBarrierSetC2::register_potential_barrier_node(Node* node) const {
865 if (node->Opcode() == Op_ShenandoahEnqueueBarrier) {
866 state()->add_enqueue_barrier((ShenandoahEnqueueBarrierNode*) node);
867 }
868 if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) {
869 state()->add_load_reference_barrier((ShenandoahLoadReferenceBarrierNode*) node);
870 }
871 }
872
873 void ShenandoahBarrierSetC2::unregister_potential_barrier_node(Node* node) const {
874 if (node->Opcode() == Op_ShenandoahEnqueueBarrier) {
875 state()->remove_enqueue_barrier((ShenandoahEnqueueBarrierNode*) node);
876 }
877 if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) {
878 state()->remove_load_reference_barrier((ShenandoahLoadReferenceBarrierNode*) node);
879 }
880 }
881
882 void ShenandoahBarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* n) const {
883 if (is_shenandoah_wb_pre_call(n)) {
884 shenandoah_eliminate_wb_pre(n, ¯o->igvn());
885 }
886 }
887
888 void ShenandoahBarrierSetC2::shenandoah_eliminate_wb_pre(Node* call, PhaseIterGVN* igvn) const {
889 assert(UseShenandoahGC && is_shenandoah_wb_pre_call(call), "");
890 Node* c = call->as_Call()->proj_out(TypeFunc::Control);
891 c = c->unique_ctrl_out();
892 assert(c->is_Region() && c->req() == 3, "where's the pre barrier control flow?");
893 c = c->unique_ctrl_out();
894 assert(c->is_Region() && c->req() == 3, "where's the pre barrier control flow?");
895 Node* iff = c->in(1)->is_IfProj() ? c->in(1)->in(0) : c->in(2)->in(0);
896 assert(iff->is_If(), "expect test");
897 if (!is_shenandoah_marking_if(igvn, iff)) {
898 c = c->unique_ctrl_out();
904 igvn->replace_node(cmpx, igvn->makecon(TypeInt::CC_EQ));
905 igvn->rehash_node_delayed(call);
906 call->del_req(call->req()-1);
907 }
908
909 void ShenandoahBarrierSetC2::enqueue_useful_gc_barrier(PhaseIterGVN* igvn, Node* node) const {
910 if (node->Opcode() == Op_AddP && ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(node)) {
911 igvn->add_users_to_worklist(node);
912 }
913 }
914
915 void ShenandoahBarrierSetC2::eliminate_useless_gc_barriers(Unique_Node_List &useful, Compile* C) const {
916 for (uint i = 0; i < useful.size(); i++) {
917 Node* n = useful.at(i);
918 if (n->Opcode() == Op_AddP && ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(n)) {
919 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
920 C->record_for_igvn(n->fast_out(i));
921 }
922 }
923 }
924 for (int i = state()->enqueue_barriers_count() - 1; i >= 0; i--) {
925 ShenandoahEnqueueBarrierNode* n = state()->enqueue_barrier(i);
926 if (!useful.member(n)) {
927 state()->remove_enqueue_barrier(n);
928 }
929 }
930 for (int i = state()->load_reference_barriers_count() - 1; i >= 0; i--) {
931 ShenandoahLoadReferenceBarrierNode* n = state()->load_reference_barrier(i);
932 if (!useful.member(n)) {
933 state()->remove_load_reference_barrier(n);
934 }
935 }
936 }
937
938 void ShenandoahBarrierSetC2::add_users_to_worklist(Unique_Node_List* worklist) const {}
939
940 void* ShenandoahBarrierSetC2::create_barrier_state(Arena* comp_arena) const {
941 return new(comp_arena) ShenandoahBarrierSetC2State(comp_arena);
942 }
943
944 ShenandoahBarrierSetC2State* ShenandoahBarrierSetC2::state() const {
945 return reinterpret_cast<ShenandoahBarrierSetC2State*>(Compile::current()->barrier_set_state());
946 }
947
948 // If the BarrierSetC2 state has kept macro nodes in its compilation unit state to be
949 // expanded later, then now is the time to do so.
950 bool ShenandoahBarrierSetC2::expand_macro_nodes(PhaseMacroExpand* macro) const { return false; }
951
952 #ifdef ASSERT
953 void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase phase) const {
954 if (ShenandoahVerifyOptoBarriers && phase == BarrierSetC2::BeforeExpand) {
955 ShenandoahBarrierC2Support::verify(Compile::current()->root());
956 } else if (phase == BarrierSetC2::BeforeCodeGen) {
957 // Verify G1 pre-barriers
958 const int marking_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset());
959
960 ResourceArea *area = Thread::current()->resource_area();
961 Unique_Node_List visited(area);
962 Node_List worklist(area);
963 // We're going to walk control flow backwards starting from the Root
964 worklist.push(compile->root());
965 while (worklist.size() > 0) {
966 Node *x = worklist.pop();
967 if (x == NULL || x == compile->top()) continue;
968 if (visited.member(x)) {
969 continue;
970 } else {
971 visited.push(x);
972 }
973
974 if (x->is_Region()) {
975 for (uint i = 1; i < x->req(); i++) {
1041 PhaseIterGVN* igvn = phase->is_IterGVN();
1042 if (in1 != n->in(1)) {
1043 if (igvn != NULL) {
1044 n->set_req_X(1, in1, igvn);
1045 } else {
1046 n->set_req(1, in1);
1047 }
1048 assert(in2 == n->in(2), "only one change");
1049 return n;
1050 }
1051 if (in2 != n->in(2)) {
1052 if (igvn != NULL) {
1053 n->set_req_X(2, in2, igvn);
1054 } else {
1055 n->set_req(2, in2);
1056 }
1057 return n;
1058 }
1059 } else if (can_reshape &&
1060 n->Opcode() == Op_If &&
1061 ShenandoahBarrierC2Support::is_heap_stable_test(n) &&
1062 n->in(0) != NULL) {
1063 Node* dom = n->in(0);
1064 Node* prev_dom = n;
1065 int op = n->Opcode();
1066 int dist = 16;
1067 // Search up the dominator tree for another heap stable test
1068 while (dom->Opcode() != op || // Not same opcode?
1069 !ShenandoahBarrierC2Support::is_heap_stable_test(dom) || // Not same input 1?
1070 prev_dom->in(0) != dom) { // One path of test does not dominate?
1071 if (dist < 0) return NULL;
1072
1073 dist--;
1074 prev_dom = dom;
1075 dom = IfNode::up_one_dom(dom);
1076 if (!dom) return NULL;
1077 }
1078
1079 // Check that we did not follow a loop back to ourselves
1080 if (n == dom) {
1081 return NULL;
1082 }
1083
1084 return n->as_If()->dominated_by(prev_dom, phase->is_IterGVN());
1085 }
1086
1087 return NULL;
1088 }
1089
1090 bool ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(Node* n) {
1091 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
1092 Node* u = n->fast_out(i);
1093 if (!is_shenandoah_wb_pre_call(u)) {
1094 return false;
1095 }
1096 }
1097 return n->outcnt() > 0;
1098 }
1099
1100 bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, uint opcode) const {
1101 switch (opcode) {
1102 case Op_CallLeaf:
1103 case Op_CallLeafNoFP: {
1104 assert (n->is_Call(), "");
1105 CallNode *call = n->as_Call();
1106 if (ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(call)) {
1107 uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type()->domain()->cnt();
1108 if (call->req() > cnt) {
1109 assert(call->req() == cnt + 1, "only one extra input");
1110 Node *addp = call->in(cnt);
1111 assert(!ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(addp), "useless address computation?");
1112 call->del_req(cnt);
1113 }
1114 }
1115 return false;
1116 }
1117 case Op_ShenandoahCompareAndSwapP:
1118 case Op_ShenandoahCompareAndSwapN:
1119 case Op_ShenandoahWeakCompareAndSwapN:
1120 case Op_ShenandoahWeakCompareAndSwapP:
1121 case Op_ShenandoahCompareAndExchangeP:
1122 case Op_ShenandoahCompareAndExchangeN:
1123 #ifdef ASSERT
1124 if( VerifyOptoOopOffsets ) {
1125 MemNode* mem = n->as_Mem();
1126 // Check to see if address types have grounded out somehow.
1127 const TypeInstPtr *tp = mem->in(MemNode::Address)->bottom_type()->isa_instptr();
1128 ciInstanceKlass *k = tp->klass()->as_instance_klass();
1129 bool oop_offset_is_sane = k->contains_field_offset(tp->offset());
1130 assert( !tp || oop_offset_is_sane, "" );
1131 }
1132 #endif
1133 return true;
1134 case Op_ShenandoahLoadReferenceBarrier:
1135 assert(false, "should have been expanded already");
1136 return true;
1137 default:
1138 return false;
1139 }
1140 }
1141
1142 bool ShenandoahBarrierSetC2::escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const {
1143 switch (opcode) {
1144 case Op_ShenandoahCompareAndExchangeP:
1145 case Op_ShenandoahCompareAndExchangeN:
1146 conn_graph->add_objload_to_connection_graph(n, delayed_worklist);
1147 // fallthrough
1148 case Op_ShenandoahWeakCompareAndSwapP:
1149 case Op_ShenandoahWeakCompareAndSwapN:
1150 case Op_ShenandoahCompareAndSwapP:
1151 case Op_ShenandoahCompareAndSwapN:
1152 conn_graph->add_to_congraph_unsafe_access(n, opcode, delayed_worklist);
1153 return true;
1154 case Op_StoreP: {
1155 Node* adr = n->in(MemNode::Address);
1156 const Type* adr_type = gvn->type(adr);
1157 // Pointer stores in G1 barriers looks like unsafe access.
1158 // Ignore such stores to be able scalar replace non-escaping
1159 // allocations.
1160 if (adr_type->isa_rawptr() && adr->is_AddP()) {
1161 Node* base = conn_graph->get_addp_base(adr);
1162 if (base->Opcode() == Op_LoadP &&
1163 base->in(MemNode::Address)->is_AddP()) {
1164 adr = base->in(MemNode::Address);
1165 Node* tls = conn_graph->get_addp_base(adr);
1166 if (tls->Opcode() == Op_ThreadLocal) {
1167 int offs = (int) gvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot);
1168 const int buf_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset());
1169 if (offs == buf_offset) {
1170 return true; // Pre barrier previous oop value store.
1171 }
1172 }
1173 }
1174 }
1175 return false;
1176 }
1177 case Op_ShenandoahEnqueueBarrier:
1178 conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), delayed_worklist);
1179 break;
1180 case Op_ShenandoahLoadReferenceBarrier:
1181 conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(ShenandoahLoadReferenceBarrierNode::ValueIn), delayed_worklist);
1182 return true;
1183 default:
1184 // Nothing
1185 break;
1186 }
1187 return false;
1188 }
1189
1190 bool ShenandoahBarrierSetC2::escape_add_final_edges(ConnectionGraph* conn_graph, PhaseGVN* gvn, Node* n, uint opcode) const {
1191 switch (opcode) {
1192 case Op_ShenandoahCompareAndExchangeP:
1193 case Op_ShenandoahCompareAndExchangeN: {
1194 Node *adr = n->in(MemNode::Address);
1195 conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, adr, NULL);
1196 // fallthrough
1197 }
1198 case Op_ShenandoahCompareAndSwapP:
1199 case Op_ShenandoahCompareAndSwapN:
1200 case Op_ShenandoahWeakCompareAndSwapP:
1201 case Op_ShenandoahWeakCompareAndSwapN:
1202 return conn_graph->add_final_edges_unsafe_access(n, opcode);
1203 case Op_ShenandoahEnqueueBarrier:
1204 conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), NULL);
1205 return true;
1206 case Op_ShenandoahLoadReferenceBarrier:
1207 conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(ShenandoahLoadReferenceBarrierNode::ValueIn), NULL);
1208 return true;
1209 default:
1210 // Nothing
1211 break;
1212 }
1213 return false;
1214 }
1215
1216 bool ShenandoahBarrierSetC2::escape_has_out_with_unsafe_object(Node* n) const {
1217 return n->has_out_with(Op_ShenandoahCompareAndExchangeP) || n->has_out_with(Op_ShenandoahCompareAndExchangeN) ||
1218 n->has_out_with(Op_ShenandoahCompareAndSwapP, Op_ShenandoahCompareAndSwapN, Op_ShenandoahWeakCompareAndSwapP, Op_ShenandoahWeakCompareAndSwapN);
1219
1220 }
1221
1222 bool ShenandoahBarrierSetC2::escape_is_barrier_node(Node* n) const {
1223 return n->Opcode() == Op_ShenandoahLoadReferenceBarrier;
1224 }
1225
1226 bool ShenandoahBarrierSetC2::matcher_find_shared_post_visit(Matcher* matcher, Node* n, uint opcode) const {
1227 switch (opcode) {
1228 case Op_ShenandoahCompareAndExchangeP:
1229 case Op_ShenandoahCompareAndExchangeN:
1230 case Op_ShenandoahWeakCompareAndSwapP:
1231 case Op_ShenandoahWeakCompareAndSwapN:
1232 case Op_ShenandoahCompareAndSwapP:
1233 case Op_ShenandoahCompareAndSwapN: { // Convert trinary to binary-tree
1234 Node* newval = n->in(MemNode::ValueIn);
1235 Node* oldval = n->in(LoadStoreConditionalNode::ExpectedIn);
1236 Node* pair = new BinaryNode(oldval, newval);
1237 n->set_req(MemNode::ValueIn,pair);
1238 n->del_req(LoadStoreConditionalNode::ExpectedIn);
1239 return true;
1240 }
1241 default:
1242 break;
1243 }
1244 return false;
1245 }
1246
1247 bool ShenandoahBarrierSetC2::matcher_is_store_load_barrier(Node* x, uint xop) const {
1248 return xop == Op_ShenandoahCompareAndExchangeP ||
1249 xop == Op_ShenandoahCompareAndExchangeN ||
1250 xop == Op_ShenandoahWeakCompareAndSwapP ||
1251 xop == Op_ShenandoahWeakCompareAndSwapN ||
1252 xop == Op_ShenandoahCompareAndSwapN ||
1253 xop == Op_ShenandoahCompareAndSwapP;
1254 }
|