23 */ |
23 */ |
24 |
24 |
25 // |
25 // |
26 // Adaptation for C2 of the escape analysis algorithm described in: |
26 // Adaptation for C2 of the escape analysis algorithm described in: |
27 // |
27 // |
28 // [Choi99] Jong-Deok Shoi, Manish Gupta, Mauricio Seffano, Vugranam C. Sreedhar, |
28 // [Choi99] Jong-Deok Shoi, Manish Gupta, Mauricio Seffano, |
29 // Sam Midkiff, "Escape Analysis for Java", Procedings of ACM SIGPLAN |
29 // Vugranam C. Sreedhar, Sam Midkiff, |
30 // OOPSLA Conference, November 1, 1999 |
30 // "Escape Analysis for Java", Procedings of ACM SIGPLAN |
|
31 // OOPSLA Conference, November 1, 1999 |
31 // |
32 // |
32 // The flow-insensitive analysis described in the paper has been implemented. |
33 // The flow-insensitive analysis described in the paper has been implemented. |
33 // |
34 // |
34 // The analysis requires construction of a "connection graph" (CG) for the method being |
35 // The analysis requires construction of a "connection graph" (CG) for |
35 // analyzed. The nodes of the connection graph are: |
36 // the method being analyzed. The nodes of the connection graph are: |
36 // |
37 // |
37 // - Java objects (JO) |
38 // - Java objects (JO) |
38 // - Local variables (LV) |
39 // - Local variables (LV) |
39 // - Fields of an object (OF), these also include array elements |
40 // - Fields of an object (OF), these also include array elements |
40 // |
41 // |
41 // The CG contains 3 types of edges: |
42 // The CG contains 3 types of edges: |
42 // |
43 // |
43 // - PointsTo (-P>) {LV,OF} to JO |
44 // - PointsTo (-P>) {LV, OF} to JO |
44 // - Deferred (-D>) from {LV, OF} to {LV, OF} |
45 // - Deferred (-D>) from {LV, OF} to {LV, OF} |
45 // - Field (-F>) from JO to OF |
46 // - Field (-F>) from JO to OF |
46 // |
47 // |
47 // The following utility functions is used by the algorithm: |
48 // The following utility functions is used by the algorithm: |
48 // |
49 // |
49 // PointsTo(n) - n is any CG node, it returns the set of JO that n could |
50 // PointsTo(n) - n is any CG node, it returns the set of JO that n could |
50 // point to. |
51 // point to. |
51 // |
52 // |
52 // The algorithm describes how to construct the connection graph in the following 4 cases: |
53 // The algorithm describes how to construct the connection graph |
|
54 // in the following 4 cases: |
53 // |
55 // |
54 // Case Edges Created |
56 // Case Edges Created |
55 // |
57 // |
56 // (1) p = new T() LV -P> JO |
58 // (1) p = new T() LV -P> JO |
57 // (2) p = q LV -D> LV |
59 // (2) p = q LV -D> LV |
58 // (3) p.f = q JO -F> OF, OF -D> LV |
60 // (3) p.f = q JO -F> OF, OF -D> LV |
59 // (4) p = q.f JO -F> OF, LV -D> OF |
61 // (4) p = q.f JO -F> OF, LV -D> OF |
60 // |
62 // |
61 // In all these cases, p and q are local variables. For static field references, we can |
63 // In all these cases, p and q are local variables. For static field |
62 // construct a local variable containing a reference to the static memory. |
64 // references, we can construct a local variable containing a reference |
|
65 // to the static memory. |
63 // |
66 // |
64 // C2 does not have local variables. However for the purposes of constructing |
67 // C2 does not have local variables. However for the purposes of constructing |
65 // the connection graph, the following IR nodes are treated as local variables: |
68 // the connection graph, the following IR nodes are treated as local variables: |
66 // Phi (pointer values) |
69 // Phi (pointer values) |
67 // LoadP |
70 // LoadP |
68 // Proj (value returned from callnodes including allocations) |
71 // Proj#5 (value returned from callnodes including allocations) |
69 // CheckCastPP |
72 // CheckCastPP, CastPP |
70 // |
73 // |
71 // The LoadP, Proj and CheckCastPP behave like variables assigned to only once. Only |
74 // The LoadP, Proj and CheckCastPP behave like variables assigned to only once. |
72 // a Phi can have multiple assignments. Each input to a Phi is treated |
75 // Only a Phi can have multiple assignments. Each input to a Phi is treated |
73 // as an assignment to it. |
76 // as an assignment to it. |
74 // |
77 // |
75 // The following note types are JavaObject: |
78 // The following node types are JavaObject: |
76 // |
79 // |
77 // top() |
80 // top() |
78 // Allocate |
81 // Allocate |
79 // AllocateArray |
82 // AllocateArray |
80 // Parm (for incoming arguments) |
83 // Parm (for incoming arguments) |
|
84 // CastX2P ("unsafe" operations) |
81 // CreateEx |
85 // CreateEx |
82 // ConP |
86 // ConP |
83 // LoadKlass |
87 // LoadKlass |
|
88 // ThreadLocal |
84 // |
89 // |
85 // AddP nodes are fields. |
90 // AddP nodes are fields. |
86 // |
91 // |
87 // After building the graph, a pass is made over the nodes, deleting deferred |
92 // After building the graph, a pass is made over the nodes, deleting deferred |
88 // nodes and copying the edges from the target of the deferred edge to the |
93 // nodes and copying the edges from the target of the deferred edge to the |
89 // source. This results in a graph with no deferred edges, only: |
94 // source. This results in a graph with no deferred edges, only: |
90 // |
95 // |
91 // LV -P> JO |
96 // LV -P> JO |
92 // OF -P> JO |
97 // OF -P> JO (the object whose oop is stored in the field) |
93 // JO -F> OF |
98 // JO -F> OF |
94 // |
99 // |
95 // Then, for each node which is GlobalEscape, anything it could point to |
100 // Then, for each node which is GlobalEscape, anything it could point to |
96 // is marked GlobalEscape. Finally, for any node marked ArgEscape, anything |
101 // is marked GlobalEscape. Finally, for any node marked ArgEscape, anything |
97 // it could point to is marked ArgEscape. |
102 // it could point to is marked ArgEscape. |
138 INITIAL_EDGE_COUNT = 4 |
144 INITIAL_EDGE_COUNT = 4 |
139 }; |
145 }; |
140 |
146 |
141 NodeType _type; |
147 NodeType _type; |
142 EscapeState _escape; |
148 EscapeState _escape; |
143 GrowableArray<uint>* _edges; // outgoing edges |
149 GrowableArray<uint>* _edges; // outgoing edges |
144 int _offset; // for fields |
150 |
145 |
|
146 bool _unique_type; // For allocated objects, this node may be a unique type |
|
147 public: |
151 public: |
148 Node* _node; // Ideal node corresponding to this PointsTo node |
152 Node* _node; // Ideal node corresponding to this PointsTo node. |
149 int _inputs_processed; // the number of Phi inputs that have been processed so far |
153 int _offset; // Object fields offsets. |
150 bool _hidden_alias; // this node is an argument to a function which may return it |
154 bool _scalar_replaceable;// Not escaped object could be replaced with scalar |
151 // creating a hidden alias |
155 bool _hidden_alias; // This node is an argument to a function. |
152 |
156 // which may return it creating a hidden alias. |
153 |
157 |
154 PointsToNode(): _offset(-1), _type(UnknownType), _escape(UnknownEscape), _edges(NULL), _node(NULL), _inputs_processed(0), _hidden_alias(false), _unique_type(true) {} |
158 PointsToNode(): |
|
159 _type(UnknownType), |
|
160 _escape(UnknownEscape), |
|
161 _edges(NULL), |
|
162 _node(NULL), |
|
163 _offset(-1), |
|
164 _scalar_replaceable(true), |
|
165 _hidden_alias(false) {} |
|
166 |
155 |
167 |
156 EscapeState escape_state() const { return _escape; } |
168 EscapeState escape_state() const { return _escape; } |
157 NodeType node_type() const { return _type;} |
169 NodeType node_type() const { return _type;} |
158 int offset() { return _offset;} |
170 int offset() { return _offset;} |
159 |
171 |
180 |
192 |
181 }; |
193 }; |
182 |
194 |
183 class ConnectionGraph: public ResourceObj { |
195 class ConnectionGraph: public ResourceObj { |
184 private: |
196 private: |
185 enum { |
197 GrowableArray<PointsToNode>* _nodes; // Connection graph nodes indexed |
186 INITIAL_NODE_COUNT = 100 // initial size of _nodes array |
198 // by ideal node index. |
187 }; |
199 |
188 |
200 Unique_Node_List _delayed_worklist; // Nodes to be processed before |
189 |
201 // the call build_connection_graph(). |
190 GrowableArray<PointsToNode>* _nodes; // connection graph nodes Indexed by ideal |
202 |
191 // node index |
203 VectorSet _processed; // Records which nodes have been |
192 Unique_Node_List _deferred; // Phi's to be processed after parsing |
204 // processed. |
193 VectorSet _processed; // records which nodes have been processed |
205 |
194 bool _collecting; // indicates whether escape information is |
206 bool _collecting; // Indicates whether escape information |
195 // still being collected. If false, no new |
207 // is still being collected. If false, |
196 // nodes will be processed |
208 // no new nodes will be processed. |
197 uint _phantom_object; // index of globally escaping object that |
209 |
198 // pointer values loaded from a field which |
210 bool _has_allocations; // Indicates whether method has any |
199 // has not been set are assumed to point to |
211 // non-escaping allocations. |
200 Compile * _compile; // Compile object for current compilation |
212 |
|
213 uint _phantom_object; // Index of globally escaping object |
|
214 // that pointer values loaded from |
|
215 // a field which has not been set |
|
216 // are assumed to point to. |
|
217 |
|
218 Compile * _compile; // Compile object for current compilation |
201 |
219 |
202 // address of an element in _nodes. Used when the element is to be modified |
220 // address of an element in _nodes. Used when the element is to be modified |
203 PointsToNode *ptnode_adr(uint idx) { |
221 PointsToNode *ptnode_adr(uint idx) { |
204 if ((uint)_nodes->length() <= idx) { |
222 if ((uint)_nodes->length() <= idx) { |
205 // expand _nodes array |
223 // expand _nodes array |
206 PointsToNode dummy = _nodes->at_grow(idx); |
224 PointsToNode dummy = _nodes->at_grow(idx); |
207 } |
225 } |
208 return _nodes->adr_at(idx); |
226 return _nodes->adr_at(idx); |
209 } |
227 } |
210 |
228 |
|
229 // Add node to ConnectionGraph. |
|
230 void add_node(Node *n, PointsToNode::NodeType nt, PointsToNode::EscapeState es, bool done); |
|
231 |
211 // offset of a field reference |
232 // offset of a field reference |
212 int type_to_offset(const Type *t); |
233 int address_offset(Node* adr, PhaseTransform *phase); |
213 |
234 |
214 // compute the escape state for arguments to a call |
235 // compute the escape state for arguments to a call |
215 void process_call_arguments(CallNode *call, PhaseTransform *phase); |
236 void process_call_arguments(CallNode *call, PhaseTransform *phase); |
216 |
237 |
217 // compute the escape state for the return value of a call |
238 // compute the escape state for the return value of a call |
218 void process_call_result(ProjNode *resproj, PhaseTransform *phase); |
239 void process_call_result(ProjNode *resproj, PhaseTransform *phase); |
219 |
240 |
220 // compute the escape state of a Phi. This may be called multiple |
241 // Populate Connection Graph with Ideal nodes. |
221 // times as new inputs are added to the Phi. |
242 void record_for_escape_analysis(Node *n, PhaseTransform *phase); |
222 void process_phi_escape(PhiNode *phi, PhaseTransform *phase); |
243 |
223 |
244 // Build Connection Graph and set nodes escape state. |
224 // compute the escape state of an ideal node. |
245 void build_connection_graph(Node *n, PhaseTransform *phase); |
225 void record_escape_work(Node *n, PhaseTransform *phase); |
|
226 |
246 |
227 // walk the connection graph starting at the node corresponding to "n" and |
247 // walk the connection graph starting at the node corresponding to "n" and |
228 // add the index of everything it could point to, to "ptset". This may cause |
248 // add the index of everything it could point to, to "ptset". This may cause |
229 // Phi's encountered to get (re)processed (which requires "phase".) |
249 // Phi's encountered to get (re)processed (which requires "phase".) |
230 void PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase); |
250 void PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase); |
239 // Add an edge to node given by "to_i" from any field of adr_i whose offset |
259 // Add an edge to node given by "to_i" from any field of adr_i whose offset |
240 // matches "offset" A deferred edge is added if to_i is a LocalVar, and |
260 // matches "offset" A deferred edge is added if to_i is a LocalVar, and |
241 // a pointsto edge is added if it is a JavaObject |
261 // a pointsto edge is added if it is a JavaObject |
242 void add_edge_from_fields(uint adr, uint to_i, int offs); |
262 void add_edge_from_fields(uint adr, uint to_i, int offs); |
243 |
263 |
244 // Add a deferred edge from node given by "from_i" to any field of adr_i whose offset |
264 // Add a deferred edge from node given by "from_i" to any field |
245 // matches "offset" |
265 // of adr_i whose offset matches "offset" |
246 void add_deferred_edge_to_fields(uint from_i, uint adr, int offs); |
266 void add_deferred_edge_to_fields(uint from_i, uint adr, int offs); |
247 |
267 |
248 |
268 |
249 // Remove outgoing deferred edges from the node referenced by "ni". |
269 // Remove outgoing deferred edges from the node referenced by "ni". |
250 // Any outgoing edges from the target of the deferred edge are copied |
270 // Any outgoing edges from the target of the deferred edge are copied |
260 // allocation - CheckCastPP of the allocation |
280 // allocation - CheckCastPP of the allocation |
261 void split_AddP(Node *addp, Node *base, PhaseGVN *igvn); |
281 void split_AddP(Node *addp, Node *base, PhaseGVN *igvn); |
262 PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn, bool &new_created); |
282 PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn, bool &new_created); |
263 PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn); |
283 PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn); |
264 Node *find_mem(Node *mem, int alias_idx, PhaseGVN *igvn); |
284 Node *find_mem(Node *mem, int alias_idx, PhaseGVN *igvn); |
|
285 Node *find_inst_mem(Node *mem, int alias_idx,GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn); |
|
286 |
265 // Propagate unique types created for unescaped allocated objects |
287 // Propagate unique types created for unescaped allocated objects |
266 // through the graph |
288 // through the graph |
267 void split_unique_types(GrowableArray<Node *> &alloc_worklist); |
289 void split_unique_types(GrowableArray<Node *> &alloc_worklist); |
268 |
290 |
269 // manage entries in _node_map |
291 // manage entries in _node_map |
283 } |
305 } |
284 |
306 |
285 // Set the escape state of a node |
307 // Set the escape state of a node |
286 void set_escape_state(uint ni, PointsToNode::EscapeState es); |
308 void set_escape_state(uint ni, PointsToNode::EscapeState es); |
287 |
309 |
288 // bypass any casts and return the node they refer to |
|
289 Node * skip_casts(Node *n); |
|
290 |
|
291 // Get Compile object for current compilation. |
310 // Get Compile object for current compilation. |
292 Compile *C() const { return _compile; } |
311 Compile *C() const { return _compile; } |
293 |
312 |
294 public: |
313 public: |
295 ConnectionGraph(Compile *C); |
314 ConnectionGraph(Compile *C); |
296 |
315 |
297 // record a Phi for later processing. |
316 // Compute the escape information |
298 void record_for_escape_analysis(Node *n); |
|
299 |
|
300 // process a node and fill in its connection graph node |
|
301 void record_escape(Node *n, PhaseTransform *phase); |
|
302 |
|
303 // All nodes have been recorded, compute the escape information |
|
304 void compute_escape(); |
317 void compute_escape(); |
305 |
318 |
306 // escape state of a node |
319 // escape state of a node |
307 PointsToNode::EscapeState escape_state(Node *n, PhaseTransform *phase); |
320 PointsToNode::EscapeState escape_state(Node *n, PhaseTransform *phase); |
|
321 // other information we have collected |
|
322 bool is_scalar_replaceable(Node *n) { |
|
323 if (_collecting) |
|
324 return false; |
|
325 PointsToNode ptn = _nodes->at_grow(n->_idx); |
|
326 return ptn.escape_state() == PointsToNode::NoEscape && ptn._scalar_replaceable; |
|
327 } |
308 |
328 |
309 bool hidden_alias(Node *n) { |
329 bool hidden_alias(Node *n) { |
310 if (_collecting) |
330 if (_collecting) |
311 return true; |
331 return true; |
312 PointsToNode ptn = _nodes->at_grow(n->_idx); |
332 PointsToNode ptn = _nodes->at_grow(n->_idx); |