72 // to the static memory. |
72 // to the static memory. |
73 // |
73 // |
74 // C2 does not have local variables. However for the purposes of constructing |
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: |
75 // the connection graph, the following IR nodes are treated as local variables: |
76 // Phi (pointer values) |
76 // Phi (pointer values) |
77 // LoadP |
77 // LoadP, LoadN |
78 // Proj#5 (value returned from callnodes including allocations) |
78 // Proj#5 (value returned from callnodes including allocations) |
79 // CheckCastPP, CastPP |
79 // CheckCastPP, CastPP |
80 // |
80 // |
81 // The LoadP, Proj and CheckCastPP behave like variables assigned to only once. |
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 |
82 // Only a Phi can have multiple assignments. Each input to a Phi is treated |
83 // as an assignment to it. |
83 // as an assignment to it. |
84 // |
84 // |
85 // The following node types are JavaObject: |
85 // The following node types are JavaObject: |
86 // |
86 // |
87 // top() |
87 // phantom_object (general globally escaped object) |
88 // Allocate |
88 // Allocate |
89 // AllocateArray |
89 // AllocateArray |
90 // Parm (for incoming arguments) |
90 // Parm (for incoming arguments) |
91 // CastX2P ("unsafe" operations) |
91 // CastX2P ("unsafe" operations) |
92 // CreateEx |
92 // CreateEx |
93 // ConP |
93 // ConP |
94 // LoadKlass |
94 // LoadKlass |
95 // ThreadLocal |
95 // ThreadLocal |
|
96 // CallStaticJava (which returns Object) |
96 // |
97 // |
97 // AddP nodes are fields. |
98 // AddP nodes are fields. |
98 // |
99 // |
99 // After building the graph, a pass is made over the nodes, deleting deferred |
100 // After building the graph, a pass is made over the nodes, deleting deferred |
100 // nodes and copying the edges from the target of the deferred edge to the |
101 // nodes and copying the edges from the target of the deferred edge to the |
128 Field = 3 |
129 Field = 3 |
129 } NodeType; |
130 } NodeType; |
130 |
131 |
131 typedef enum { |
132 typedef enum { |
132 UnknownEscape = 0, |
133 UnknownEscape = 0, |
133 NoEscape = 1, // A scalar replaceable object with unique type. |
134 NoEscape = 1, // An object does not escape method or thread and it is |
134 ArgEscape = 2, // An object passed as argument or referenced by |
135 // not passed to call. It could be replaced with scalar. |
135 // argument (and not globally escape during call). |
136 ArgEscape = 2, // An object does not escape method or thread but it is |
136 GlobalEscape = 3 // An object escapes the method and thread. |
137 // passed as argument to call or referenced by argument |
|
138 // and it does not escape during call. |
|
139 GlobalEscape = 3 // An object escapes the method or thread. |
137 } EscapeState; |
140 } EscapeState; |
138 |
141 |
139 typedef enum { |
142 typedef enum { |
140 UnknownEdge = 0, |
143 UnknownEdge = 0, |
141 PointsToEdge = 1, |
144 PointsToEdge = 1, |
151 INITIAL_EDGE_COUNT = 4 |
154 INITIAL_EDGE_COUNT = 4 |
152 }; |
155 }; |
153 |
156 |
154 NodeType _type; |
157 NodeType _type; |
155 EscapeState _escape; |
158 EscapeState _escape; |
156 GrowableArray<uint>* _edges; // outgoing edges |
159 GrowableArray<uint>* _edges; // outgoing edges |
|
160 Node* _node; // Ideal node corresponding to this PointsTo node. |
|
161 int _offset; // Object fields offsets. |
|
162 bool _scalar_replaceable; // Not escaped object could be replaced with scalar |
157 |
163 |
158 public: |
164 public: |
159 Node* _node; // Ideal node corresponding to this PointsTo node. |
|
160 int _offset; // Object fields offsets. |
|
161 bool _scalar_replaceable;// Not escaped object could be replaced with scalar |
|
162 bool _hidden_alias; // This node is an argument to a function. |
|
163 // which may return it creating a hidden alias. |
|
164 |
|
165 PointsToNode(): |
165 PointsToNode(): |
166 _type(UnknownType), |
166 _type(UnknownType), |
167 _escape(UnknownEscape), |
167 _escape(UnknownEscape), |
168 _edges(NULL), |
168 _edges(NULL), |
169 _node(NULL), |
169 _node(NULL), |
170 _offset(-1), |
170 _offset(-1), |
171 _scalar_replaceable(true), |
171 _scalar_replaceable(true) {} |
172 _hidden_alias(false) {} |
|
173 |
172 |
174 |
173 |
175 EscapeState escape_state() const { return _escape; } |
174 EscapeState escape_state() const { return _escape; } |
176 NodeType node_type() const { return _type;} |
175 NodeType node_type() const { return _type;} |
177 int offset() { return _offset;} |
176 int offset() { return _offset;} |
|
177 bool scalar_replaceable() { return _scalar_replaceable;} |
178 |
178 |
179 void set_offset(int offs) { _offset = offs;} |
179 void set_offset(int offs) { _offset = offs;} |
180 void set_escape_state(EscapeState state) { _escape = state; } |
180 void set_escape_state(EscapeState state) { _escape = state; } |
181 void set_node_type(NodeType ntype) { |
181 void set_node_type(NodeType ntype) { |
182 assert(_type == UnknownType || _type == ntype, "Can't change node type"); |
182 assert(_type == UnknownType || _type == ntype, "Can't change node type"); |
183 _type = ntype; |
183 _type = ntype; |
184 } |
184 } |
|
185 void set_scalar_replaceable(bool v) { _scalar_replaceable = v; } |
185 |
186 |
186 // count of outgoing edges |
187 // count of outgoing edges |
187 uint edge_count() const { return (_edges == NULL) ? 0 : _edges->length(); } |
188 uint edge_count() const { return (_edges == NULL) ? 0 : _edges->length(); } |
188 |
189 |
189 // node index of target of outgoing edge "e" |
190 // node index of target of outgoing edge "e" |
231 |
232 |
232 uint _phantom_object; // Index of globally escaping object |
233 uint _phantom_object; // Index of globally escaping object |
233 // that pointer values loaded from |
234 // that pointer values loaded from |
234 // a field which has not been set |
235 // a field which has not been set |
235 // are assumed to point to. |
236 // are assumed to point to. |
236 uint _oop_null; // ConP(#NULL) |
237 uint _oop_null; // ConP(#NULL)->_idx |
237 uint _noop_null; // ConN(#NULL) |
238 uint _noop_null; // ConN(#NULL)->_idx |
238 |
239 |
239 Compile * _compile; // Compile object for current compilation |
240 Compile * _compile; // Compile object for current compilation |
240 PhaseIterGVN * _igvn; // Value numbering |
241 PhaseIterGVN * _igvn; // Value numbering |
241 |
242 |
242 // Address of an element in _nodes. Used when the element is to be modified |
243 // Address of an element in _nodes. Used when the element is to be modified |
337 } |
338 } |
338 |
339 |
339 // Set the escape state of a node |
340 // Set the escape state of a node |
340 void set_escape_state(uint ni, PointsToNode::EscapeState es); |
341 void set_escape_state(uint ni, PointsToNode::EscapeState es); |
341 |
342 |
|
343 // Find fields initializing values for allocations. |
|
344 void find_init_values(Node* n, VectorSet* visited, PhaseTransform* phase); |
|
345 |
342 // Adjust escape state after Connection Graph is built. |
346 // Adjust escape state after Connection Graph is built. |
343 void adjust_escape_state(int nidx, PhaseTransform* phase); |
347 void adjust_escape_state(Node* n); |
|
348 |
|
349 // Propagate escape states to referenced nodes. |
|
350 bool propagate_escape_state(GrowableArray<int>* cg_worklist, |
|
351 GrowableArray<uint>* worklist, |
|
352 PointsToNode::EscapeState esc_state); |
344 |
353 |
345 // Compute the escape information |
354 // Compute the escape information |
346 bool compute_escape(); |
355 bool compute_escape(); |
347 |
356 |
348 public: |
357 public: |
354 // Perform escape analysis |
363 // Perform escape analysis |
355 static void do_analysis(Compile *C, PhaseIterGVN *igvn); |
364 static void do_analysis(Compile *C, PhaseIterGVN *igvn); |
356 |
365 |
357 // escape state of a node |
366 // escape state of a node |
358 PointsToNode::EscapeState escape_state(Node *n); |
367 PointsToNode::EscapeState escape_state(Node *n); |
359 |
|
360 // other information we have collected |
|
361 bool is_scalar_replaceable(Node *n) { |
|
362 if (_collecting || (n->_idx >= nodes_size())) |
|
363 return false; |
|
364 PointsToNode* ptn = ptnode_adr(n->_idx); |
|
365 return ptn->escape_state() == PointsToNode::NoEscape && ptn->_scalar_replaceable; |
|
366 } |
|
367 |
|
368 bool hidden_alias(Node *n) { |
|
369 if (_collecting || (n->_idx >= nodes_size())) |
|
370 return true; |
|
371 PointsToNode* ptn = ptnode_adr(n->_idx); |
|
372 return (ptn->escape_state() != PointsToNode::NoEscape) || ptn->_hidden_alias; |
|
373 } |
|
374 |
368 |
375 #ifndef PRODUCT |
369 #ifndef PRODUCT |
376 void dump(); |
370 void dump(); |
377 #endif |
371 #endif |
378 }; |
372 }; |