1 | /* |
2 | * Copyright (c) 2005, 2019, 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 | #ifndef SHARE_OPTO_ESCAPE_HPP |
26 | #define SHARE_OPTO_ESCAPE_HPP |
27 | |
28 | #include "opto/addnode.hpp" |
29 | #include "opto/node.hpp" |
30 | #include "utilities/growableArray.hpp" |
31 | |
32 | // |
33 | // Adaptation for C2 of the escape analysis algorithm described in: |
34 | // |
35 | // [Choi99] Jong-Deok Shoi, Manish Gupta, Mauricio Seffano, |
36 | // Vugranam C. Sreedhar, Sam Midkiff, |
37 | // "Escape Analysis for Java", Procedings of ACM SIGPLAN |
38 | // OOPSLA Conference, November 1, 1999 |
39 | // |
40 | // The flow-insensitive analysis described in the paper has been implemented. |
41 | // |
42 | // The analysis requires construction of a "connection graph" (CG) for |
43 | // the method being analyzed. The nodes of the connection graph are: |
44 | // |
45 | // - Java objects (JO) |
46 | // - Local variables (LV) |
47 | // - Fields of an object (OF), these also include array elements |
48 | // |
49 | // The CG contains 3 types of edges: |
50 | // |
51 | // - PointsTo (-P>) {LV, OF} to JO |
52 | // - Deferred (-D>) from {LV, OF} to {LV, OF} |
53 | // - Field (-F>) from JO to OF |
54 | // |
55 | // The following utility functions is used by the algorithm: |
56 | // |
57 | // PointsTo(n) - n is any CG node, it returns the set of JO that n could |
58 | // point to. |
59 | // |
60 | // The algorithm describes how to construct the connection graph |
61 | // in the following 4 cases: |
62 | // |
63 | // Case Edges Created |
64 | // |
65 | // (1) p = new T() LV -P> JO |
66 | // (2) p = q LV -D> LV |
67 | // (3) p.f = q JO -F> OF, OF -D> LV |
68 | // (4) p = q.f JO -F> OF, LV -D> OF |
69 | // |
70 | // In all these cases, p and q are local variables. For static field |
71 | // references, we can construct a local variable containing a reference |
72 | // to the static memory. |
73 | // |
74 | // C2 does not have local variables. However for the purposes of constructing |
75 | // the connection graph, the following IR nodes are treated as local variables: |
76 | // Phi (pointer values) |
77 | // LoadP, LoadN |
78 | // Proj#5 (value returned from callnodes including allocations) |
79 | // CheckCastPP, CastPP |
80 | // |
81 | // The LoadP, Proj and CheckCastPP behave like variables assigned to only once. |
82 | // Only a Phi can have multiple assignments. Each input to a Phi is treated |
83 | // as an assignment to it. |
84 | // |
85 | // The following node types are JavaObject: |
86 | // |
87 | // phantom_object (general globally escaped object) |
88 | // Allocate |
89 | // AllocateArray |
90 | // Parm (for incoming arguments) |
91 | // CastX2P ("unsafe" operations) |
92 | // CreateEx |
93 | // ConP |
94 | // LoadKlass |
95 | // ThreadLocal |
96 | // CallStaticJava (which returns Object) |
97 | // |
98 | // AddP nodes are fields. |
99 | // |
100 | // After building the graph, a pass is made over the nodes, deleting deferred |
101 | // nodes and copying the edges from the target of the deferred edge to the |
102 | // source. This results in a graph with no deferred edges, only: |
103 | // |
104 | // LV -P> JO |
105 | // OF -P> JO (the object whose oop is stored in the field) |
106 | // JO -F> OF |
107 | // |
108 | // Then, for each node which is GlobalEscape, anything it could point to |
109 | // is marked GlobalEscape. Finally, for any node marked ArgEscape, anything |
110 | // it could point to is marked ArgEscape. |
111 | // |
112 | |
113 | class Compile; |
114 | class Node; |
115 | class CallNode; |
116 | class PhiNode; |
117 | class PhaseTransform; |
118 | class PointsToNode; |
119 | class Type; |
120 | class TypePtr; |
121 | class VectorSet; |
122 | |
123 | class JavaObjectNode; |
124 | class LocalVarNode; |
125 | class FieldNode; |
126 | class ArraycopyNode; |
127 | |
128 | class ConnectionGraph; |
129 | |
130 | // ConnectionGraph nodes |
131 | class PointsToNode : public ResourceObj { |
132 | GrowableArray<PointsToNode*> _edges; // List of nodes this node points to |
133 | GrowableArray<PointsToNode*> _uses; // List of nodes which point to this node |
134 | |
135 | const u1 _type; // NodeType |
136 | u1 _flags; // NodeFlags |
137 | u1 _escape; // EscapeState of object |
138 | u1 _fields_escape; // EscapeState of object's fields |
139 | |
140 | Node* const _node; // Ideal node corresponding to this PointsTo node. |
141 | const int _idx; // Cached ideal node's _idx |
142 | const uint _pidx; // Index of this node |
143 | |
144 | public: |
145 | typedef enum { |
146 | UnknownType = 0, |
147 | JavaObject = 1, |
148 | LocalVar = 2, |
149 | Field = 3, |
150 | Arraycopy = 4 |
151 | } NodeType; |
152 | |
153 | typedef enum { |
154 | UnknownEscape = 0, |
155 | NoEscape = 1, // An object does not escape method or thread and it is |
156 | // not passed to call. It could be replaced with scalar. |
157 | ArgEscape = 2, // An object does not escape method or thread but it is |
158 | // passed as argument to call or referenced by argument |
159 | // and it does not escape during call. |
160 | GlobalEscape = 3 // An object escapes the method or thread. |
161 | } EscapeState; |
162 | |
163 | typedef enum { |
164 | ScalarReplaceable = 1, // Not escaped object could be replaced with scalar |
165 | PointsToUnknown = 2, // Has edge to phantom_object |
166 | ArraycopySrc = 4, // Has edge from Arraycopy node |
167 | ArraycopyDst = 8 // Has edge to Arraycopy node |
168 | } NodeFlags; |
169 | |
170 | |
171 | inline PointsToNode(ConnectionGraph* CG, Node* n, EscapeState es, NodeType type); |
172 | |
173 | uint pidx() const { return _pidx; } |
174 | |
175 | Node* ideal_node() const { return _node; } |
176 | int idx() const { return _idx; } |
177 | |
178 | bool is_JavaObject() const { return _type == (u1)JavaObject; } |
179 | bool is_LocalVar() const { return _type == (u1)LocalVar; } |
180 | bool is_Field() const { return _type == (u1)Field; } |
181 | bool is_Arraycopy() const { return _type == (u1)Arraycopy; } |
182 | |
183 | JavaObjectNode* as_JavaObject() { assert(is_JavaObject(),"" ); return (JavaObjectNode*)this; } |
184 | LocalVarNode* as_LocalVar() { assert(is_LocalVar(),"" ); return (LocalVarNode*)this; } |
185 | FieldNode* as_Field() { assert(is_Field(),"" ); return (FieldNode*)this; } |
186 | ArraycopyNode* as_Arraycopy() { assert(is_Arraycopy(),"" ); return (ArraycopyNode*)this; } |
187 | |
188 | EscapeState escape_state() const { return (EscapeState)_escape; } |
189 | void set_escape_state(EscapeState state) { _escape = (u1)state; } |
190 | |
191 | EscapeState fields_escape_state() const { return (EscapeState)_fields_escape; } |
192 | void set_fields_escape_state(EscapeState state) { _fields_escape = (u1)state; } |
193 | |
194 | bool has_unknown_ptr() const { return (_flags & PointsToUnknown) != 0; } |
195 | void set_has_unknown_ptr() { _flags |= PointsToUnknown; } |
196 | |
197 | bool arraycopy_src() const { return (_flags & ArraycopySrc) != 0; } |
198 | void set_arraycopy_src() { _flags |= ArraycopySrc; } |
199 | bool arraycopy_dst() const { return (_flags & ArraycopyDst) != 0; } |
200 | void set_arraycopy_dst() { _flags |= ArraycopyDst; } |
201 | |
202 | bool scalar_replaceable() const { return (_flags & ScalarReplaceable) != 0;} |
203 | void set_scalar_replaceable(bool v) { |
204 | if (v) |
205 | _flags |= ScalarReplaceable; |
206 | else |
207 | _flags &= ~ScalarReplaceable; |
208 | } |
209 | |
210 | int edge_count() const { return _edges.length(); } |
211 | PointsToNode* edge(int e) const { return _edges.at(e); } |
212 | bool add_edge(PointsToNode* edge) { return _edges.append_if_missing(edge); } |
213 | |
214 | int use_count() const { return _uses.length(); } |
215 | PointsToNode* use(int e) const { return _uses.at(e); } |
216 | bool add_use(PointsToNode* use) { return _uses.append_if_missing(use); } |
217 | |
218 | // Mark base edge use to distinguish from stored value edge. |
219 | bool add_base_use(FieldNode* use) { return _uses.append_if_missing((PointsToNode*)((intptr_t)use + 1)); } |
220 | static bool is_base_use(PointsToNode* use) { return (((intptr_t)use) & 1); } |
221 | static PointsToNode* get_use_node(PointsToNode* use) { return (PointsToNode*)(((intptr_t)use) & ~1); } |
222 | |
223 | // Return true if this node points to specified node or nodes it points to. |
224 | bool points_to(JavaObjectNode* ptn) const; |
225 | |
226 | // Return true if this node points only to non-escaping allocations. |
227 | bool non_escaping_allocation(); |
228 | |
229 | // Return true if one node points to an other. |
230 | bool meet(PointsToNode* ptn); |
231 | |
232 | #ifndef PRODUCT |
233 | NodeType node_type() const { return (NodeType)_type;} |
234 | void dump(bool print_state=true) const; |
235 | #endif |
236 | |
237 | }; |
238 | |
239 | class LocalVarNode: public PointsToNode { |
240 | public: |
241 | LocalVarNode(ConnectionGraph *CG, Node* n, EscapeState es): |
242 | PointsToNode(CG, n, es, LocalVar) {} |
243 | }; |
244 | |
245 | class JavaObjectNode: public PointsToNode { |
246 | public: |
247 | JavaObjectNode(ConnectionGraph *CG, Node* n, EscapeState es): |
248 | PointsToNode(CG, n, es, JavaObject) { |
249 | if (es > NoEscape) |
250 | set_scalar_replaceable(false); |
251 | } |
252 | }; |
253 | |
254 | class FieldNode: public PointsToNode { |
255 | GrowableArray<PointsToNode*> _bases; // List of JavaObject nodes which point to this node |
256 | const int _offset; // Field's offset. |
257 | const bool _is_oop; // Field points to object |
258 | bool _has_unknown_base; // Has phantom_object base |
259 | public: |
260 | FieldNode(ConnectionGraph *CG, Node* n, EscapeState es, int offs, bool is_oop): |
261 | PointsToNode(CG, n, es, Field), |
262 | _offset(offs), _is_oop(is_oop), |
263 | _has_unknown_base(false) {} |
264 | |
265 | int offset() const { return _offset;} |
266 | bool is_oop() const { return _is_oop;} |
267 | bool has_unknown_base() const { return _has_unknown_base; } |
268 | void set_has_unknown_base() { _has_unknown_base = true; } |
269 | |
270 | int base_count() const { return _bases.length(); } |
271 | PointsToNode* base(int e) const { return _bases.at(e); } |
272 | bool add_base(PointsToNode* base) { return _bases.append_if_missing(base); } |
273 | #ifdef ASSERT |
274 | // Return true if bases points to this java object. |
275 | bool has_base(JavaObjectNode* ptn) const; |
276 | #endif |
277 | |
278 | }; |
279 | |
280 | class ArraycopyNode: public PointsToNode { |
281 | public: |
282 | ArraycopyNode(ConnectionGraph *CG, Node* n, EscapeState es): |
283 | PointsToNode(CG, n, es, Arraycopy) {} |
284 | }; |
285 | |
286 | // Iterators for PointsTo node's edges: |
287 | // for (EdgeIterator i(n); i.has_next(); i.next()) { |
288 | // PointsToNode* u = i.get(); |
289 | class PointsToIterator: public StackObj { |
290 | protected: |
291 | const PointsToNode* node; |
292 | const int cnt; |
293 | int i; |
294 | public: |
295 | inline PointsToIterator(const PointsToNode* n, int cnt) : node(n), cnt(cnt), i(0) { } |
296 | inline bool has_next() const { return i < cnt; } |
297 | inline void next() { i++; } |
298 | PointsToNode* get() const { ShouldNotCallThis(); return NULL; } |
299 | }; |
300 | |
301 | class EdgeIterator: public PointsToIterator { |
302 | public: |
303 | inline EdgeIterator(const PointsToNode* n) : PointsToIterator(n, n->edge_count()) { } |
304 | inline PointsToNode* get() const { return node->edge(i); } |
305 | }; |
306 | |
307 | class UseIterator: public PointsToIterator { |
308 | public: |
309 | inline UseIterator(const PointsToNode* n) : PointsToIterator(n, n->use_count()) { } |
310 | inline PointsToNode* get() const { return node->use(i); } |
311 | }; |
312 | |
313 | class BaseIterator: public PointsToIterator { |
314 | public: |
315 | inline BaseIterator(const FieldNode* n) : PointsToIterator(n, n->base_count()) { } |
316 | inline PointsToNode* get() const { return ((PointsToNode*)node)->as_Field()->base(i); } |
317 | }; |
318 | |
319 | |
320 | class ConnectionGraph: public ResourceObj { |
321 | friend class PointsToNode; |
322 | private: |
323 | GrowableArray<PointsToNode*> _nodes; // Map from ideal nodes to |
324 | // ConnectionGraph nodes. |
325 | |
326 | GrowableArray<PointsToNode*> _worklist; // Nodes to be processed |
327 | VectorSet _in_worklist; |
328 | uint _next_pidx; |
329 | |
330 | bool _collecting; // Indicates whether escape information |
331 | // is still being collected. If false, |
332 | // no new nodes will be processed. |
333 | |
334 | bool _verify; // verify graph |
335 | |
336 | JavaObjectNode* phantom_obj; // Unknown object |
337 | JavaObjectNode* null_obj; |
338 | Node* _pcmp_neq; // ConI(#CC_GT) |
339 | Node* _pcmp_eq; // ConI(#CC_EQ) |
340 | |
341 | Compile* _compile; // Compile object for current compilation |
342 | PhaseIterGVN* _igvn; // Value numbering |
343 | |
344 | Unique_Node_List ideal_nodes; // Used by CG construction and types splitting. |
345 | |
346 | // Address of an element in _nodes. Used when the element is to be modified |
347 | PointsToNode* ptnode_adr(int idx) const { |
348 | // There should be no new ideal nodes during ConnectionGraph build, |
349 | // growableArray::at() will throw assert otherwise. |
350 | return _nodes.at(idx); |
351 | } |
352 | uint nodes_size() const { return _nodes.length(); } |
353 | |
354 | uint next_pidx() { return _next_pidx++; } |
355 | |
356 | // Add nodes to ConnectionGraph. |
357 | void add_local_var(Node* n, PointsToNode::EscapeState es); |
358 | void add_java_object(Node* n, PointsToNode::EscapeState es); |
359 | void add_field(Node* n, PointsToNode::EscapeState es, int offset); |
360 | void add_arraycopy(Node* n, PointsToNode::EscapeState es, PointsToNode* src, PointsToNode* dst); |
361 | |
362 | // Compute the escape state for arguments to a call. |
363 | void process_call_arguments(CallNode *call); |
364 | |
365 | // Add PointsToNode node corresponding to a call |
366 | void add_call_node(CallNode* call); |
367 | |
368 | // Map ideal node to existing PointsTo node (usually phantom_object). |
369 | void map_ideal_node(Node *n, PointsToNode* ptn) { |
370 | assert(ptn != NULL, "only existing PointsTo node" ); |
371 | _nodes.at_put(n->_idx, ptn); |
372 | } |
373 | |
374 | // Create PointsToNode node and add it to Connection Graph. |
375 | void add_node_to_connection_graph(Node *n, Unique_Node_List *delayed_worklist); |
376 | |
377 | // Add final simple edges to graph. |
378 | void add_final_edges(Node *n); |
379 | |
380 | // Finish Graph construction. |
381 | bool complete_connection_graph(GrowableArray<PointsToNode*>& ptnodes_worklist, |
382 | GrowableArray<JavaObjectNode*>& non_escaped_worklist, |
383 | GrowableArray<JavaObjectNode*>& java_objects_worklist, |
384 | GrowableArray<FieldNode*>& oop_fields_worklist); |
385 | |
386 | #ifdef ASSERT |
387 | void verify_connection_graph(GrowableArray<PointsToNode*>& ptnodes_worklist, |
388 | GrowableArray<JavaObjectNode*>& non_escaped_worklist, |
389 | GrowableArray<JavaObjectNode*>& java_objects_worklist, |
390 | GrowableArray<Node*>& addp_worklist); |
391 | #endif |
392 | |
393 | // Add all references to this JavaObject node. |
394 | int add_java_object_edges(JavaObjectNode* jobj, bool populate_worklist); |
395 | |
396 | // Put node on worklist if it is (or was) not there. |
397 | inline void add_to_worklist(PointsToNode* pt) { |
398 | PointsToNode* ptf = pt; |
399 | uint pidx_bias = 0; |
400 | if (PointsToNode::is_base_use(pt)) { |
401 | // Create a separate entry in _in_worklist for a marked base edge |
402 | // because _worklist may have an entry for a normal edge pointing |
403 | // to the same node. To separate them use _next_pidx as bias. |
404 | ptf = PointsToNode::get_use_node(pt)->as_Field(); |
405 | pidx_bias = _next_pidx; |
406 | } |
407 | if (!_in_worklist.test_set(ptf->pidx() + pidx_bias)) { |
408 | _worklist.append(pt); |
409 | } |
410 | } |
411 | |
412 | // Put on worklist all uses of this node. |
413 | inline void add_uses_to_worklist(PointsToNode* pt) { |
414 | for (UseIterator i(pt); i.has_next(); i.next()) { |
415 | add_to_worklist(i.get()); |
416 | } |
417 | } |
418 | |
419 | // Put on worklist all field's uses and related field nodes. |
420 | void add_field_uses_to_worklist(FieldNode* field); |
421 | |
422 | // Put on worklist all related field nodes. |
423 | void add_fields_to_worklist(FieldNode* field, PointsToNode* base); |
424 | |
425 | // Find fields which have unknown value. |
426 | int find_field_value(FieldNode* field); |
427 | |
428 | // Find fields initializing values for allocations. |
429 | int find_init_values(JavaObjectNode* ptn, PointsToNode* init_val, PhaseTransform* phase); |
430 | |
431 | // Set the escape state of an object and its fields. |
432 | void set_escape_state(PointsToNode* ptn, PointsToNode::EscapeState esc) { |
433 | // Don't change non-escaping state of NULL pointer. |
434 | if (ptn != null_obj) { |
435 | if (ptn->escape_state() < esc) |
436 | ptn->set_escape_state(esc); |
437 | if (ptn->fields_escape_state() < esc) |
438 | ptn->set_fields_escape_state(esc); |
439 | } |
440 | } |
441 | void set_fields_escape_state(PointsToNode* ptn, PointsToNode::EscapeState esc) { |
442 | // Don't change non-escaping state of NULL pointer. |
443 | if (ptn != null_obj) { |
444 | if (ptn->fields_escape_state() < esc) |
445 | ptn->set_fields_escape_state(esc); |
446 | } |
447 | } |
448 | |
449 | // Propagate GlobalEscape and ArgEscape escape states to all nodes |
450 | // and check that we still have non-escaping java objects. |
451 | bool find_non_escaped_objects(GrowableArray<PointsToNode*>& ptnodes_worklist, |
452 | GrowableArray<JavaObjectNode*>& non_escaped_worklist); |
453 | |
454 | // Adjust scalar_replaceable state after Connection Graph is built. |
455 | void adjust_scalar_replaceable_state(JavaObjectNode* jobj); |
456 | |
457 | // Optimize ideal graph. |
458 | void optimize_ideal_graph(GrowableArray<Node*>& ptr_cmp_worklist, |
459 | GrowableArray<Node*>& storestore_worklist); |
460 | // Optimize objects compare. |
461 | Node* optimize_ptr_compare(Node* n); |
462 | |
463 | // Returns unique corresponding java object or NULL. |
464 | JavaObjectNode* unique_java_object(Node *n); |
465 | |
466 | // Add an edge of the specified type pointing to the specified target. |
467 | bool add_edge(PointsToNode* from, PointsToNode* to) { |
468 | assert(!from->is_Field() || from->as_Field()->is_oop(), "sanity" ); |
469 | |
470 | if (to == phantom_obj) { |
471 | if (from->has_unknown_ptr()) { |
472 | return false; // already points to phantom_obj |
473 | } |
474 | from->set_has_unknown_ptr(); |
475 | } |
476 | |
477 | bool is_new = from->add_edge(to); |
478 | assert(to != phantom_obj || is_new, "sanity" ); |
479 | if (is_new) { // New edge? |
480 | assert(!_verify, "graph is incomplete" ); |
481 | is_new = to->add_use(from); |
482 | assert(is_new, "use should be also new" ); |
483 | } |
484 | return is_new; |
485 | } |
486 | |
487 | // Add an edge from Field node to its base and back. |
488 | bool add_base(FieldNode* from, PointsToNode* to) { |
489 | assert(!to->is_Arraycopy(), "sanity" ); |
490 | if (to == phantom_obj) { |
491 | if (from->has_unknown_base()) { |
492 | return false; // already has phantom_obj base |
493 | } |
494 | from->set_has_unknown_base(); |
495 | } |
496 | bool is_new = from->add_base(to); |
497 | assert(to != phantom_obj || is_new, "sanity" ); |
498 | if (is_new) { // New edge? |
499 | assert(!_verify, "graph is incomplete" ); |
500 | if (to == null_obj) |
501 | return is_new; // Don't add fields to NULL pointer. |
502 | if (to->is_JavaObject()) { |
503 | is_new = to->add_edge(from); |
504 | } else { |
505 | is_new = to->add_base_use(from); |
506 | } |
507 | assert(is_new, "use should be also new" ); |
508 | } |
509 | return is_new; |
510 | } |
511 | |
512 | // Helper functions |
513 | bool is_oop_field(Node* n, int offset, bool* unsafe); |
514 | static Node* find_second_addp(Node* addp, Node* n); |
515 | // offset of a field reference |
516 | int address_offset(Node* adr, PhaseTransform *phase); |
517 | |
518 | |
519 | // Propagate unique types created for unescaped allocated objects |
520 | // through the graph |
521 | void split_unique_types(GrowableArray<Node *> &alloc_worklist, GrowableArray<ArrayCopyNode*> &arraycopy_worklist); |
522 | |
523 | // Helper methods for unique types split. |
524 | bool split_AddP(Node *addp, Node *base); |
525 | |
526 | PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, bool &new_created); |
527 | PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist); |
528 | |
529 | void move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phis); |
530 | Node* find_inst_mem(Node* mem, int alias_idx,GrowableArray<PhiNode *> &orig_phi_worklist); |
531 | Node* step_through_mergemem(MergeMemNode *mmem, int alias_idx, const TypeOopPtr *toop); |
532 | |
533 | |
534 | GrowableArray<MergeMemNode*> _mergemem_worklist; // List of all MergeMem nodes |
535 | |
536 | Node_Array _node_map; // used for bookeeping during type splitting |
537 | // Used for the following purposes: |
538 | // Memory Phi - most recent unique Phi split out |
539 | // from this Phi |
540 | // MemNode - new memory input for this node |
541 | // ChecCastPP - allocation that this is a cast of |
542 | // allocation - CheckCastPP of the allocation |
543 | |
544 | // manage entries in _node_map |
545 | |
546 | void set_map(Node* from, Node* to) { |
547 | ideal_nodes.push(from); |
548 | _node_map.map(from->_idx, to); |
549 | } |
550 | |
551 | Node* get_map(int idx) { return _node_map[idx]; } |
552 | |
553 | PhiNode* get_map_phi(int idx) { |
554 | Node* phi = _node_map[idx]; |
555 | return (phi == NULL) ? NULL : phi->as_Phi(); |
556 | } |
557 | |
558 | // Notify optimizer that a node has been modified |
559 | void record_for_optimizer(Node *n); |
560 | |
561 | // Compute the escape information |
562 | bool compute_escape(); |
563 | |
564 | public: |
565 | ConnectionGraph(Compile *C, PhaseIterGVN *igvn); |
566 | |
567 | // Check for non-escaping candidates |
568 | static bool has_candidates(Compile *C); |
569 | |
570 | // Perform escape analysis |
571 | static void do_analysis(Compile *C, PhaseIterGVN *igvn); |
572 | |
573 | bool not_global_escape(Node *n); |
574 | |
575 | // To be used by, e.g., BarrierSetC2 impls |
576 | Node* get_addp_base(Node* addp); |
577 | |
578 | // Utility function for nodes that load an object |
579 | void add_objload_to_connection_graph(Node* n, Unique_Node_List* delayed_worklist); |
580 | |
581 | // Add LocalVar node and edge if possible |
582 | void add_local_var_and_edge(Node* n, PointsToNode::EscapeState es, Node* to, |
583 | Unique_Node_List *delayed_worklist) { |
584 | PointsToNode* ptn = ptnode_adr(to->_idx); |
585 | if (delayed_worklist != NULL) { // First iteration of CG construction |
586 | add_local_var(n, es); |
587 | if (ptn == NULL) { |
588 | delayed_worklist->push(n); |
589 | return; // Process it later. |
590 | } |
591 | } else { |
592 | assert(ptn != NULL, "node should be registered" ); |
593 | } |
594 | add_edge(ptnode_adr(n->_idx), ptn); |
595 | } |
596 | |
597 | void add_to_congraph_unsafe_access(Node* n, uint opcode, Unique_Node_List* delayed_worklist); |
598 | bool add_final_edges_unsafe_access(Node* n, uint opcode); |
599 | |
600 | #ifndef PRODUCT |
601 | void dump(GrowableArray<PointsToNode*>& ptnodes_worklist); |
602 | #endif |
603 | }; |
604 | |
605 | inline PointsToNode::PointsToNode(ConnectionGraph *CG, Node* n, EscapeState es, NodeType type): |
606 | _edges(CG->_compile->comp_arena(), 2, 0, NULL), |
607 | _uses (CG->_compile->comp_arena(), 2, 0, NULL), |
608 | _type((u1)type), |
609 | _flags(ScalarReplaceable), |
610 | _escape((u1)es), |
611 | _fields_escape((u1)es), |
612 | _node(n), |
613 | _idx(n->_idx), |
614 | _pidx(CG->next_pidx()) { |
615 | assert(n != NULL && es != UnknownEscape, "sanity" ); |
616 | } |
617 | |
618 | #endif // SHARE_OPTO_ESCAPE_HPP |
619 | |