1/*
2 * Copyright (c) 2015, 2018, Red Hat, Inc. All rights reserved.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 *
22 */
23
24#ifndef SHARE_GC_SHENANDOAH_C2_SHENANDOAHSUPPORT_HPP
25#define SHARE_GC_SHENANDOAH_C2_SHENANDOAHSUPPORT_HPP
26
27#include "memory/allocation.hpp"
28#include "opto/addnode.hpp"
29#include "opto/graphKit.hpp"
30#include "opto/machnode.hpp"
31#include "opto/memnode.hpp"
32#include "opto/multnode.hpp"
33#include "opto/node.hpp"
34
35class PhaseGVN;
36class MemoryGraphFixer;
37
38class ShenandoahBarrierC2Support : public AllStatic {
39private:
40#ifdef ASSERT
41 enum verify_type {
42 ShenandoahLoad,
43 ShenandoahStore,
44 ShenandoahValue,
45 ShenandoahOopStore,
46 ShenandoahNone
47 };
48
49 static bool verify_helper(Node* in, Node_Stack& phis, VectorSet& visited, verify_type t, bool trace, Unique_Node_List& barriers_used);
50 static void report_verify_failure(const char* msg, Node* n1 = NULL, Node* n2 = NULL);
51 static void verify_raw_mem(RootNode* root);
52#endif
53 static Node* dom_mem(Node* mem, Node* ctrl, int alias, Node*& mem_ctrl, PhaseIdealLoop* phase);
54 static Node* no_branches(Node* c, Node* dom, bool allow_one_proj, PhaseIdealLoop* phase);
55 static bool is_heap_state_test(Node* iff, int mask);
56 static bool try_common_gc_state_load(Node *n, PhaseIdealLoop *phase);
57 static bool has_safepoint_between(Node* start, Node* stop, PhaseIdealLoop *phase);
58 static Node* find_bottom_mem(Node* ctrl, PhaseIdealLoop* phase);
59 static void follow_barrier_uses(Node* n, Node* ctrl, Unique_Node_List& uses, PhaseIdealLoop* phase);
60 static void test_null(Node*& ctrl, Node* val, Node*& null_ctrl, PhaseIdealLoop* phase);
61 static void test_heap_stable(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl,
62 PhaseIdealLoop* phase);
63 static void call_lrb_stub(Node*& ctrl, Node*& val, Node*& result_mem, Node* raw_mem, PhaseIdealLoop* phase);
64 static Node* clone_null_check(Node*& c, Node* val, Node* unc_ctrl, PhaseIdealLoop* phase);
65 static void fix_null_check(Node* unc, Node* unc_ctrl, Node* new_unc_ctrl, Unique_Node_List& uses,
66 PhaseIdealLoop* phase);
67 static void in_cset_fast_test(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase);
68 static void move_heap_stable_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase);
69 static void merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase);
70 static bool identical_backtoback_ifs(Node *n, PhaseIdealLoop* phase);
71 static void fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase);
72 static IfNode* find_unswitching_candidate(const IdealLoopTree *loop, PhaseIdealLoop* phase);
73
74public:
75 static bool is_dominator(Node* d_c, Node* n_c, Node* d, Node* n, PhaseIdealLoop* phase);
76 static bool is_dominator_same_ctrl(Node* c, Node* d, Node* n, PhaseIdealLoop* phase);
77
78 static bool is_gc_state_load(Node* n);
79 static bool is_heap_stable_test(Node* iff);
80
81 static bool expand(Compile* C, PhaseIterGVN& igvn);
82 static void pin_and_expand(PhaseIdealLoop* phase);
83 static void optimize_after_expansion(VectorSet& visited, Node_Stack& nstack, Node_List& old_new, PhaseIdealLoop* phase);
84
85#ifdef ASSERT
86 static void verify(RootNode* root);
87#endif
88};
89
90class ShenandoahEnqueueBarrierNode : public Node {
91public:
92 ShenandoahEnqueueBarrierNode(Node* val);
93
94 const Type *bottom_type() const;
95 const Type* Value(PhaseGVN* phase) const;
96 Node* Identity(PhaseGVN* phase);
97
98 int Opcode() const;
99
100private:
101 enum { Needed, NotNeeded, MaybeNeeded };
102
103 static int needed(Node* n);
104 static Node* next(Node* n);
105};
106
107class MemoryGraphFixer : public ResourceObj {
108private:
109 Node_List _memory_nodes;
110 int _alias;
111 PhaseIdealLoop* _phase;
112 bool _include_lsm;
113
114 void collect_memory_nodes();
115 Node* get_ctrl(Node* n) const;
116 Node* ctrl_or_self(Node* n) const;
117 bool mem_is_valid(Node* m, Node* c) const;
118 MergeMemNode* allocate_merge_mem(Node* mem, Node* rep_proj, Node* rep_ctrl) const;
119 MergeMemNode* clone_merge_mem(Node* u, Node* mem, Node* rep_proj, Node* rep_ctrl, DUIterator& i) const;
120 void fix_memory_uses(Node* mem, Node* replacement, Node* rep_proj, Node* rep_ctrl) const;
121 bool should_process_phi(Node* phi) const;
122 bool has_mem_phi(Node* region) const;
123
124public:
125 MemoryGraphFixer(int alias, bool include_lsm, PhaseIdealLoop* phase) :
126 _alias(alias), _phase(phase), _include_lsm(include_lsm) {
127 assert(_alias != Compile::AliasIdxBot, "unsupported");
128 collect_memory_nodes();
129 }
130
131 Node* find_mem(Node* ctrl, Node* n) const;
132 void fix_mem(Node* ctrl, Node* region, Node* mem, Node* mem_for_ctrl, Node* mem_phi, Unique_Node_List& uses);
133 int alias() const { return _alias; }
134};
135
136class ShenandoahCompareAndSwapPNode : public CompareAndSwapPNode {
137public:
138 ShenandoahCompareAndSwapPNode(Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord)
139 : CompareAndSwapPNode(c, mem, adr, val, ex, mem_ord) { }
140
141 virtual Node *Ideal(PhaseGVN *phase, bool can_reshape) {
142 if (in(ExpectedIn) != NULL && phase->type(in(ExpectedIn)) == TypePtr::NULL_PTR) {
143 return new CompareAndSwapPNode(in(MemNode::Control), in(MemNode::Memory), in(MemNode::Address), in(MemNode::ValueIn), in(ExpectedIn), order());
144 }
145 return NULL;
146 }
147
148 virtual int Opcode() const;
149};
150
151class ShenandoahCompareAndSwapNNode : public CompareAndSwapNNode {
152public:
153 ShenandoahCompareAndSwapNNode(Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord)
154 : CompareAndSwapNNode(c, mem, adr, val, ex, mem_ord) { }
155
156 virtual Node *Ideal(PhaseGVN *phase, bool can_reshape) {
157 if (in(ExpectedIn) != NULL && phase->type(in(ExpectedIn)) == TypeNarrowOop::NULL_PTR) {
158 return new CompareAndSwapNNode(in(MemNode::Control), in(MemNode::Memory), in(MemNode::Address), in(MemNode::ValueIn), in(ExpectedIn), order());
159 }
160 return NULL;
161 }
162
163 virtual int Opcode() const;
164};
165
166class ShenandoahWeakCompareAndSwapPNode : public WeakCompareAndSwapPNode {
167public:
168 ShenandoahWeakCompareAndSwapPNode(Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord)
169 : WeakCompareAndSwapPNode(c, mem, adr, val, ex, mem_ord) { }
170
171 virtual Node *Ideal(PhaseGVN *phase, bool can_reshape) {
172 if (in(ExpectedIn) != NULL && phase->type(in(ExpectedIn)) == TypePtr::NULL_PTR) {
173 return new WeakCompareAndSwapPNode(in(MemNode::Control), in(MemNode::Memory), in(MemNode::Address), in(MemNode::ValueIn), in(ExpectedIn), order());
174 }
175 return NULL;
176 }
177
178 virtual int Opcode() const;
179};
180
181class ShenandoahWeakCompareAndSwapNNode : public WeakCompareAndSwapNNode {
182public:
183 ShenandoahWeakCompareAndSwapNNode(Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord)
184 : WeakCompareAndSwapNNode(c, mem, adr, val, ex, mem_ord) { }
185
186 virtual Node *Ideal(PhaseGVN *phase, bool can_reshape) {
187 if (in(ExpectedIn) != NULL && phase->type(in(ExpectedIn)) == TypeNarrowOop::NULL_PTR) {
188 return new WeakCompareAndSwapNNode(in(MemNode::Control), in(MemNode::Memory), in(MemNode::Address), in(MemNode::ValueIn), in(ExpectedIn), order());
189 }
190 return NULL;
191 }
192
193 virtual int Opcode() const;
194};
195
196class ShenandoahCompareAndExchangePNode : public CompareAndExchangePNode {
197public:
198 ShenandoahCompareAndExchangePNode(Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, const Type* t, MemNode::MemOrd mem_ord)
199 : CompareAndExchangePNode(c, mem, adr, val, ex, at, t, mem_ord) { }
200
201 virtual Node *Ideal(PhaseGVN *phase, bool can_reshape) {
202 if (in(ExpectedIn) != NULL && phase->type(in(ExpectedIn)) == TypePtr::NULL_PTR) {
203 return new CompareAndExchangePNode(in(MemNode::Control), in(MemNode::Memory), in(MemNode::Address), in(MemNode::ValueIn), in(ExpectedIn), adr_type(), bottom_type(), order());
204 }
205 return NULL;
206 }
207
208 virtual int Opcode() const;
209};
210
211class ShenandoahCompareAndExchangeNNode : public CompareAndExchangeNNode {
212public:
213 ShenandoahCompareAndExchangeNNode(Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, const Type* t, MemNode::MemOrd mem_ord)
214 : CompareAndExchangeNNode(c, mem, adr, val, ex, at, t, mem_ord) { }
215
216 virtual Node *Ideal(PhaseGVN *phase, bool can_reshape) {
217 if (in(ExpectedIn) != NULL && phase->type(in(ExpectedIn)) == TypeNarrowOop::NULL_PTR) {
218 return new CompareAndExchangeNNode(in(MemNode::Control), in(MemNode::Memory), in(MemNode::Address), in(MemNode::ValueIn), in(ExpectedIn), adr_type(), bottom_type(), order());
219 }
220 return NULL;
221 }
222
223 virtual int Opcode() const;
224};
225
226class ShenandoahLoadReferenceBarrierNode : public Node {
227public:
228 enum {
229 Control,
230 ValueIn
231 };
232
233 enum Strength {
234 NONE, WEAK, STRONG, NA
235 };
236
237 ShenandoahLoadReferenceBarrierNode(Node* ctrl, Node* val);
238
239 virtual int Opcode() const;
240 virtual const Type* bottom_type() const;
241 virtual const Type* Value(PhaseGVN* phase) const;
242 virtual const class TypePtr *adr_type() const { return TypeOopPtr::BOTTOM; }
243 virtual uint match_edge(uint idx) const {
244 return idx >= ValueIn;
245 }
246 virtual uint ideal_reg() const { return Op_RegP; }
247
248 virtual Node* Identity(PhaseGVN* phase);
249
250 uint size_of() const {
251 return sizeof(*this);
252 }
253
254 Strength get_barrier_strength();
255 CallStaticJavaNode* pin_and_expand_null_check(PhaseIterGVN& igvn);
256
257private:
258 bool needs_barrier(PhaseGVN* phase, Node* n);
259 bool needs_barrier_impl(PhaseGVN* phase, Node* n, Unique_Node_List &visited);
260};
261
262
263#endif // SHARE_GC_SHENANDOAH_C2_SHENANDOAHSUPPORT_HPP
264