Mercurial > hg > truffle
comparison src/share/vm/opto/escape.cpp @ 244:524eca34ea76
6684714: Optimize EA Connection Graph build performance
Summary: switch on EA by default, optimize Connection Graph construction
Reviewed-by: rasbold, never
author | kvn |
---|---|
date | Thu, 03 Jul 2008 18:02:47 -0700 |
parents | 1dd146f17531 |
children | 4a4c365f777d |
comparison
equal
deleted
inserted
replaced
231:72c3e8693c9a | 244:524eca34ea76 |
---|---|
23 */ | 23 */ |
24 | 24 |
25 #include "incls/_precompiled.incl" | 25 #include "incls/_precompiled.incl" |
26 #include "incls/_escape.cpp.incl" | 26 #include "incls/_escape.cpp.incl" |
27 | 27 |
28 uint PointsToNode::edge_target(uint e) const { | |
29 assert(_edges != NULL && e < (uint)_edges->length(), "valid edge index"); | |
30 return (_edges->at(e) >> EdgeShift); | |
31 } | |
32 | |
33 PointsToNode::EdgeType PointsToNode::edge_type(uint e) const { | |
34 assert(_edges != NULL && e < (uint)_edges->length(), "valid edge index"); | |
35 return (EdgeType) (_edges->at(e) & EdgeMask); | |
36 } | |
37 | |
38 void PointsToNode::add_edge(uint targIdx, PointsToNode::EdgeType et) { | 28 void PointsToNode::add_edge(uint targIdx, PointsToNode::EdgeType et) { |
39 uint v = (targIdx << EdgeShift) + ((uint) et); | 29 uint v = (targIdx << EdgeShift) + ((uint) et); |
40 if (_edges == NULL) { | 30 if (_edges == NULL) { |
41 Arena *a = Compile::current()->comp_arena(); | 31 Arena *a = Compile::current()->comp_arena(); |
42 _edges = new(a) GrowableArray<uint>(a, INITIAL_EDGE_COUNT, 0, 0); | 32 _edges = new(a) GrowableArray<uint>(a, INITIAL_EDGE_COUNT, 0, 0); |
85 else | 75 else |
86 _node->dump(); | 76 _node->dump(); |
87 } | 77 } |
88 #endif | 78 #endif |
89 | 79 |
90 ConnectionGraph::ConnectionGraph(Compile * C) : _processed(C->comp_arena()), _node_map(C->comp_arena()) { | 80 ConnectionGraph::ConnectionGraph(Compile * C) : |
91 _collecting = true; | 81 _nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()), |
92 this->_compile = C; | 82 _processed(C->comp_arena()), |
93 const PointsToNode &dummy = PointsToNode(); | 83 _collecting(true), |
94 int sz = C->unique(); | 84 _compile(C), |
95 _nodes = new(C->comp_arena()) GrowableArray<PointsToNode>(C->comp_arena(), sz, sz, dummy); | 85 _node_map(C->comp_arena()) { |
86 | |
96 _phantom_object = C->top()->_idx; | 87 _phantom_object = C->top()->_idx; |
97 PointsToNode *phn = ptnode_adr(_phantom_object); | 88 PointsToNode *phn = ptnode_adr(_phantom_object); |
98 phn->_node = C->top(); | 89 phn->_node = C->top(); |
99 phn->set_node_type(PointsToNode::JavaObject); | 90 phn->set_node_type(PointsToNode::JavaObject); |
100 phn->set_escape_state(PointsToNode::GlobalEscape); | 91 phn->set_escape_state(PointsToNode::GlobalEscape); |
180 uint idx = n->_idx; | 171 uint idx = n->_idx; |
181 PointsToNode::EscapeState es; | 172 PointsToNode::EscapeState es; |
182 | 173 |
183 // If we are still collecting or there were no non-escaping allocations | 174 // If we are still collecting or there were no non-escaping allocations |
184 // we don't know the answer yet | 175 // we don't know the answer yet |
185 if (_collecting || !_has_allocations) | 176 if (_collecting) |
186 return PointsToNode::UnknownEscape; | 177 return PointsToNode::UnknownEscape; |
187 | 178 |
188 // if the node was created after the escape computation, return | 179 // if the node was created after the escape computation, return |
189 // UnknownEscape | 180 // UnknownEscape |
190 if (idx >= (uint)_nodes->length()) | 181 if (idx >= nodes_size()) |
191 return PointsToNode::UnknownEscape; | 182 return PointsToNode::UnknownEscape; |
192 | 183 |
193 es = _nodes->at_grow(idx).escape_state(); | 184 es = ptnode_adr(idx)->escape_state(); |
194 | 185 |
195 // if we have already computed a value, return it | 186 // if we have already computed a value, return it |
196 if (es != PointsToNode::UnknownEscape) | 187 if (es != PointsToNode::UnknownEscape) |
197 return es; | 188 return es; |
189 | |
190 // PointsTo() calls n->uncast() which can return a new ideal node. | |
191 if (n->uncast()->_idx >= nodes_size()) | |
192 return PointsToNode::UnknownEscape; | |
198 | 193 |
199 // compute max escape state of anything this node could point to | 194 // compute max escape state of anything this node could point to |
200 VectorSet ptset(Thread::current()->resource_area()); | 195 VectorSet ptset(Thread::current()->resource_area()); |
201 PointsTo(ptset, n, phase); | 196 PointsTo(ptset, n, phase); |
202 for(VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i) { | 197 for(VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i) { |
203 uint pt = i.elem; | 198 uint pt = i.elem; |
204 PointsToNode::EscapeState pes = _nodes->adr_at(pt)->escape_state(); | 199 PointsToNode::EscapeState pes = ptnode_adr(pt)->escape_state(); |
205 if (pes > es) | 200 if (pes > es) |
206 es = pes; | 201 es = pes; |
207 } | 202 } |
208 // cache the computed escape state | 203 // cache the computed escape state |
209 assert(es != PointsToNode::UnknownEscape, "should have computed an escape state"); | 204 assert(es != PointsToNode::UnknownEscape, "should have computed an escape state"); |
210 _nodes->adr_at(idx)->set_escape_state(es); | 205 ptnode_adr(idx)->set_escape_state(es); |
211 return es; | 206 return es; |
212 } | 207 } |
213 | 208 |
214 void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase) { | 209 void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase) { |
215 VectorSet visited(Thread::current()->resource_area()); | 210 VectorSet visited(Thread::current()->resource_area()); |
218 #ifdef ASSERT | 213 #ifdef ASSERT |
219 Node *orig_n = n; | 214 Node *orig_n = n; |
220 #endif | 215 #endif |
221 | 216 |
222 n = n->uncast(); | 217 n = n->uncast(); |
223 PointsToNode npt = _nodes->at_grow(n->_idx); | 218 PointsToNode* npt = ptnode_adr(n->_idx); |
224 | 219 |
225 // If we have a JavaObject, return just that object | 220 // If we have a JavaObject, return just that object |
226 if (npt.node_type() == PointsToNode::JavaObject) { | 221 if (npt->node_type() == PointsToNode::JavaObject) { |
227 ptset.set(n->_idx); | 222 ptset.set(n->_idx); |
228 return; | 223 return; |
229 } | 224 } |
230 #ifdef ASSERT | 225 #ifdef ASSERT |
231 if (npt._node == NULL) { | 226 if (npt->_node == NULL) { |
232 if (orig_n != n) | 227 if (orig_n != n) |
233 orig_n->dump(); | 228 orig_n->dump(); |
234 n->dump(); | 229 n->dump(); |
235 assert(npt._node != NULL, "unregistered node"); | 230 assert(npt->_node != NULL, "unregistered node"); |
236 } | 231 } |
237 #endif | 232 #endif |
238 worklist.push(n->_idx); | 233 worklist.push(n->_idx); |
239 while(worklist.length() > 0) { | 234 while(worklist.length() > 0) { |
240 int ni = worklist.pop(); | 235 int ni = worklist.pop(); |
241 PointsToNode pn = _nodes->at_grow(ni); | 236 if (visited.test_set(ni)) |
242 if (!visited.test_set(ni)) { | 237 continue; |
243 // ensure that all inputs of a Phi have been processed | 238 |
244 assert(!_collecting || !pn._node->is_Phi() || _processed.test(ni),""); | 239 PointsToNode* pn = ptnode_adr(ni); |
245 | 240 // ensure that all inputs of a Phi have been processed |
246 int edges_processed = 0; | 241 assert(!_collecting || !pn->_node->is_Phi() || _processed.test(ni),""); |
247 for (uint e = 0; e < pn.edge_count(); e++) { | 242 |
248 uint etgt = pn.edge_target(e); | 243 int edges_processed = 0; |
249 PointsToNode::EdgeType et = pn.edge_type(e); | 244 uint e_cnt = pn->edge_count(); |
250 if (et == PointsToNode::PointsToEdge) { | 245 for (uint e = 0; e < e_cnt; e++) { |
251 ptset.set(etgt); | 246 uint etgt = pn->edge_target(e); |
252 edges_processed++; | 247 PointsToNode::EdgeType et = pn->edge_type(e); |
253 } else if (et == PointsToNode::DeferredEdge) { | 248 if (et == PointsToNode::PointsToEdge) { |
254 worklist.push(etgt); | 249 ptset.set(etgt); |
255 edges_processed++; | 250 edges_processed++; |
256 } else { | 251 } else if (et == PointsToNode::DeferredEdge) { |
257 assert(false,"neither PointsToEdge or DeferredEdge"); | 252 worklist.push(etgt); |
258 } | 253 edges_processed++; |
259 } | 254 } else { |
260 if (edges_processed == 0) { | 255 assert(false,"neither PointsToEdge or DeferredEdge"); |
261 // no deferred or pointsto edges found. Assume the value was set | 256 } |
262 // outside this method. Add the phantom object to the pointsto set. | 257 } |
263 ptset.set(_phantom_object); | 258 if (edges_processed == 0) { |
264 } | 259 // no deferred or pointsto edges found. Assume the value was set |
260 // outside this method. Add the phantom object to the pointsto set. | |
261 ptset.set(_phantom_object); | |
265 } | 262 } |
266 } | 263 } |
267 } | 264 } |
268 | 265 |
269 void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edges, VectorSet* visited) { | 266 void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edges, VectorSet* visited) { |
270 // This method is most expensive during ConnectionGraph construction. | 267 // This method is most expensive during ConnectionGraph construction. |
271 // Reuse vectorSet and an additional growable array for deferred edges. | 268 // Reuse vectorSet and an additional growable array for deferred edges. |
272 deferred_edges->clear(); | 269 deferred_edges->clear(); |
273 visited->Clear(); | 270 visited->Clear(); |
274 | 271 |
275 uint i = 0; | 272 visited->set(ni); |
276 PointsToNode *ptn = ptnode_adr(ni); | 273 PointsToNode *ptn = ptnode_adr(ni); |
277 | 274 |
278 // Mark current edges as visited and move deferred edges to separate array. | 275 // Mark current edges as visited and move deferred edges to separate array. |
279 while (i < ptn->edge_count()) { | 276 for (uint i = 0; i < ptn->edge_count(); ) { |
280 uint t = ptn->edge_target(i); | 277 uint t = ptn->edge_target(i); |
281 #ifdef ASSERT | 278 #ifdef ASSERT |
282 assert(!visited->test_set(t), "expecting no duplications"); | 279 assert(!visited->test_set(t), "expecting no duplications"); |
283 #else | 280 #else |
284 visited->set(t); | 281 visited->set(t); |
291 } | 288 } |
292 } | 289 } |
293 for (int next = 0; next < deferred_edges->length(); ++next) { | 290 for (int next = 0; next < deferred_edges->length(); ++next) { |
294 uint t = deferred_edges->at(next); | 291 uint t = deferred_edges->at(next); |
295 PointsToNode *ptt = ptnode_adr(t); | 292 PointsToNode *ptt = ptnode_adr(t); |
296 for (uint j = 0; j < ptt->edge_count(); j++) { | 293 uint e_cnt = ptt->edge_count(); |
297 uint n1 = ptt->edge_target(j); | 294 for (uint e = 0; e < e_cnt; e++) { |
298 if (visited->test_set(n1)) | 295 uint etgt = ptt->edge_target(e); |
296 if (visited->test_set(etgt)) | |
299 continue; | 297 continue; |
300 switch(ptt->edge_type(j)) { | 298 |
301 case PointsToNode::PointsToEdge: | 299 PointsToNode::EdgeType et = ptt->edge_type(e); |
302 add_pointsto_edge(ni, n1); | 300 if (et == PointsToNode::PointsToEdge) { |
303 if(n1 == _phantom_object) { | 301 add_pointsto_edge(ni, etgt); |
304 // Special case - field set outside (globally escaping). | 302 if(etgt == _phantom_object) { |
305 ptn->set_escape_state(PointsToNode::GlobalEscape); | 303 // Special case - field set outside (globally escaping). |
306 } | 304 ptn->set_escape_state(PointsToNode::GlobalEscape); |
307 break; | 305 } |
308 case PointsToNode::DeferredEdge: | 306 } else if (et == PointsToNode::DeferredEdge) { |
309 deferred_edges->append(n1); | 307 deferred_edges->append(etgt); |
310 break; | 308 } else { |
311 case PointsToNode::FieldEdge: | 309 assert(false,"invalid connection graph"); |
312 assert(false, "invalid connection graph"); | |
313 break; | |
314 } | 310 } |
315 } | 311 } |
316 } | 312 } |
317 } | 313 } |
318 | 314 |
320 // Add an edge to node given by "to_i" from any field of adr_i whose offset | 316 // Add an edge to node given by "to_i" from any field of adr_i whose offset |
321 // matches "offset" A deferred edge is added if to_i is a LocalVar, and | 317 // matches "offset" A deferred edge is added if to_i is a LocalVar, and |
322 // a pointsto edge is added if it is a JavaObject | 318 // a pointsto edge is added if it is a JavaObject |
323 | 319 |
324 void ConnectionGraph::add_edge_from_fields(uint adr_i, uint to_i, int offs) { | 320 void ConnectionGraph::add_edge_from_fields(uint adr_i, uint to_i, int offs) { |
325 PointsToNode an = _nodes->at_grow(adr_i); | 321 PointsToNode* an = ptnode_adr(adr_i); |
326 PointsToNode to = _nodes->at_grow(to_i); | 322 PointsToNode* to = ptnode_adr(to_i); |
327 bool deferred = (to.node_type() == PointsToNode::LocalVar); | 323 bool deferred = (to->node_type() == PointsToNode::LocalVar); |
328 | 324 |
329 for (uint fe = 0; fe < an.edge_count(); fe++) { | 325 for (uint fe = 0; fe < an->edge_count(); fe++) { |
330 assert(an.edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); | 326 assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); |
331 int fi = an.edge_target(fe); | 327 int fi = an->edge_target(fe); |
332 PointsToNode pf = _nodes->at_grow(fi); | 328 PointsToNode* pf = ptnode_adr(fi); |
333 int po = pf.offset(); | 329 int po = pf->offset(); |
334 if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { | 330 if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { |
335 if (deferred) | 331 if (deferred) |
336 add_deferred_edge(fi, to_i); | 332 add_deferred_edge(fi, to_i); |
337 else | 333 else |
338 add_pointsto_edge(fi, to_i); | 334 add_pointsto_edge(fi, to_i); |
341 } | 337 } |
342 | 338 |
343 // Add a deferred edge from node given by "from_i" to any field of adr_i | 339 // Add a deferred edge from node given by "from_i" to any field of adr_i |
344 // whose offset matches "offset". | 340 // whose offset matches "offset". |
345 void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) { | 341 void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) { |
346 PointsToNode an = _nodes->at_grow(adr_i); | 342 PointsToNode* an = ptnode_adr(adr_i); |
347 for (uint fe = 0; fe < an.edge_count(); fe++) { | 343 for (uint fe = 0; fe < an->edge_count(); fe++) { |
348 assert(an.edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); | 344 assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); |
349 int fi = an.edge_target(fe); | 345 int fi = an->edge_target(fe); |
350 PointsToNode pf = _nodes->at_grow(fi); | 346 PointsToNode* pf = ptnode_adr(fi); |
351 int po = pf.offset(); | 347 int po = pf->offset(); |
352 if (pf.edge_count() == 0) { | 348 if (pf->edge_count() == 0) { |
353 // we have not seen any stores to this field, assume it was set outside this method | 349 // we have not seen any stores to this field, assume it was set outside this method |
354 add_pointsto_edge(fi, _phantom_object); | 350 add_pointsto_edge(fi, _phantom_object); |
355 } | 351 } |
356 if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { | 352 if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { |
357 add_deferred_edge(from_i, fi); | 353 add_deferred_edge(from_i, fi); |
833 VectorSet ptset(Thread::current()->resource_area()); | 829 VectorSet ptset(Thread::current()->resource_area()); |
834 | 830 |
835 | 831 |
836 // Phase 1: Process possible allocations from alloc_worklist. | 832 // Phase 1: Process possible allocations from alloc_worklist. |
837 // Create instance types for the CheckCastPP for allocations where possible. | 833 // Create instance types for the CheckCastPP for allocations where possible. |
834 // | |
835 // (Note: don't forget to change the order of the second AddP node on | |
836 // the alloc_worklist if the order of the worklist processing is changed, | |
837 // see the comment in find_second_addp().) | |
838 // | |
838 while (alloc_worklist.length() != 0) { | 839 while (alloc_worklist.length() != 0) { |
839 Node *n = alloc_worklist.pop(); | 840 Node *n = alloc_worklist.pop(); |
840 uint ni = n->_idx; | 841 uint ni = n->_idx; |
841 const TypeOopPtr* tinst = NULL; | 842 const TypeOopPtr* tinst = NULL; |
842 if (n->is_Call()) { | 843 if (n->is_Call()) { |
843 CallNode *alloc = n->as_Call(); | 844 CallNode *alloc = n->as_Call(); |
844 // copy escape information to call node | 845 // copy escape information to call node |
845 PointsToNode* ptn = _nodes->adr_at(alloc->_idx); | 846 PointsToNode* ptn = ptnode_adr(alloc->_idx); |
846 PointsToNode::EscapeState es = escape_state(alloc, igvn); | 847 PointsToNode::EscapeState es = escape_state(alloc, igvn); |
847 // We have an allocation or call which returns a Java object, | 848 // We have an allocation or call which returns a Java object, |
848 // see if it is unescaped. | 849 // see if it is unescaped. |
849 if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable) | 850 if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable) |
850 continue; | 851 continue; |
897 (t->isa_instptr() || t->isa_aryptr())) { | 898 (t->isa_instptr() || t->isa_aryptr())) { |
898 | 899 |
899 // First, put on the worklist all Field edges from Connection Graph | 900 // First, put on the worklist all Field edges from Connection Graph |
900 // which is more accurate then putting immediate users from Ideal Graph. | 901 // which is more accurate then putting immediate users from Ideal Graph. |
901 for (uint e = 0; e < ptn->edge_count(); e++) { | 902 for (uint e = 0; e < ptn->edge_count(); e++) { |
902 Node *use = _nodes->adr_at(ptn->edge_target(e))->_node; | 903 Node *use = ptnode_adr(ptn->edge_target(e))->_node; |
903 assert(ptn->edge_type(e) == PointsToNode::FieldEdge && use->is_AddP(), | 904 assert(ptn->edge_type(e) == PointsToNode::FieldEdge && use->is_AddP(), |
904 "only AddP nodes are Field edges in CG"); | 905 "only AddP nodes are Field edges in CG"); |
905 if (use->outcnt() > 0) { // Don't process dead nodes | 906 if (use->outcnt() > 0) { // Don't process dead nodes |
906 Node* addp2 = find_second_addp(use, use->in(AddPNode::Base)); | 907 Node* addp2 = find_second_addp(use, use->in(AddPNode::Base)); |
907 if (addp2 != NULL) { | 908 if (addp2 != NULL) { |
1060 if (_compile->failing()) { | 1061 if (_compile->failing()) { |
1061 return; | 1062 return; |
1062 } | 1063 } |
1063 if (mem != n->in(MemNode::Memory)) { | 1064 if (mem != n->in(MemNode::Memory)) { |
1064 set_map(n->_idx, mem); | 1065 set_map(n->_idx, mem); |
1065 _nodes->adr_at(n->_idx)->_node = n; | 1066 ptnode_adr(n->_idx)->_node = n; |
1066 } | 1067 } |
1067 if (n->is_Load()) { | 1068 if (n->is_Load()) { |
1068 continue; // don't push users | 1069 continue; // don't push users |
1069 } else if (n->is_LoadStore()) { | 1070 } else if (n->is_LoadStore()) { |
1070 // get the memory projection | 1071 // get the memory projection |
1221 record_for_optimizer(phi); | 1222 record_for_optimizer(phi); |
1222 } | 1223 } |
1223 | 1224 |
1224 // Update the memory inputs of MemNodes with the value we computed | 1225 // Update the memory inputs of MemNodes with the value we computed |
1225 // in Phase 2. | 1226 // in Phase 2. |
1226 for (int i = 0; i < _nodes->length(); i++) { | 1227 for (uint i = 0; i < nodes_size(); i++) { |
1227 Node *nmem = get_map(i); | 1228 Node *nmem = get_map(i); |
1228 if (nmem != NULL) { | 1229 if (nmem != NULL) { |
1229 Node *n = _nodes->adr_at(i)->_node; | 1230 Node *n = ptnode_adr(i)->_node; |
1230 if (n != NULL && n->is_Mem()) { | 1231 if (n != NULL && n->is_Mem()) { |
1231 igvn->hash_delete(n); | 1232 igvn->hash_delete(n); |
1232 n->set_req(MemNode::Memory, nmem); | 1233 n->set_req(MemNode::Memory, nmem); |
1233 igvn->hash_insert(n); | 1234 igvn->hash_insert(n); |
1234 record_for_optimizer(n); | 1235 record_for_optimizer(n); |
1235 } | 1236 } |
1236 } | 1237 } |
1237 } | 1238 } |
1238 } | 1239 } |
1239 | 1240 |
1240 void ConnectionGraph::compute_escape() { | 1241 bool ConnectionGraph::has_candidates(Compile *C) { |
1242 // EA brings benefits only when the code has allocations and/or locks which | |
1243 // are represented by ideal Macro nodes. | |
1244 int cnt = C->macro_count(); | |
1245 for( int i=0; i < cnt; i++ ) { | |
1246 Node *n = C->macro_node(i); | |
1247 if ( n->is_Allocate() ) | |
1248 return true; | |
1249 if( n->is_Lock() ) { | |
1250 Node* obj = n->as_Lock()->obj_node()->uncast(); | |
1251 if( !(obj->is_Parm() || obj->is_Con()) ) | |
1252 return true; | |
1253 } | |
1254 } | |
1255 return false; | |
1256 } | |
1257 | |
1258 bool ConnectionGraph::compute_escape() { | |
1259 Compile* C = _compile; | |
1241 | 1260 |
1242 // 1. Populate Connection Graph (CG) with Ideal nodes. | 1261 // 1. Populate Connection Graph (CG) with Ideal nodes. |
1243 | 1262 |
1244 Unique_Node_List worklist_init; | 1263 Unique_Node_List worklist_init; |
1245 worklist_init.map(_compile->unique(), NULL); // preallocate space | 1264 worklist_init.map(C->unique(), NULL); // preallocate space |
1246 | 1265 |
1247 // Initialize worklist | 1266 // Initialize worklist |
1248 if (_compile->root() != NULL) { | 1267 if (C->root() != NULL) { |
1249 worklist_init.push(_compile->root()); | 1268 worklist_init.push(C->root()); |
1250 } | 1269 } |
1251 | 1270 |
1252 GrowableArray<int> cg_worklist; | 1271 GrowableArray<int> cg_worklist; |
1253 PhaseGVN* igvn = _compile->initial_gvn(); | 1272 PhaseGVN* igvn = C->initial_gvn(); |
1254 bool has_allocations = false; | 1273 bool has_allocations = false; |
1255 | 1274 |
1256 // Push all useful nodes onto CG list and set their type. | 1275 // Push all useful nodes onto CG list and set their type. |
1257 for( uint next = 0; next < worklist_init.size(); ++next ) { | 1276 for( uint next = 0; next < worklist_init.size(); ++next ) { |
1258 Node* n = worklist_init.at(next); | 1277 Node* n = worklist_init.at(next); |
1259 record_for_escape_analysis(n, igvn); | 1278 record_for_escape_analysis(n, igvn); |
1260 if (n->is_Call() && | 1279 // Only allocations and java static calls results are checked |
1261 _nodes->adr_at(n->_idx)->node_type() == PointsToNode::JavaObject) { | 1280 // for an escape status. See process_call_result() below. |
1281 if (n->is_Allocate() || n->is_CallStaticJava() && | |
1282 ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) { | |
1262 has_allocations = true; | 1283 has_allocations = true; |
1263 } | 1284 } |
1264 if(n->is_AddP()) | 1285 if(n->is_AddP()) |
1265 cg_worklist.append(n->_idx); | 1286 cg_worklist.append(n->_idx); |
1266 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { | 1287 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
1267 Node* m = n->fast_out(i); // Get user | 1288 Node* m = n->fast_out(i); // Get user |
1268 worklist_init.push(m); | 1289 worklist_init.push(m); |
1269 } | 1290 } |
1270 } | 1291 } |
1271 | 1292 |
1272 if (has_allocations) { | 1293 if (!has_allocations) { |
1273 _has_allocations = true; | |
1274 } else { | |
1275 _has_allocations = false; | |
1276 _collecting = false; | 1294 _collecting = false; |
1277 return; // Nothing to do. | 1295 return false; // Nothing to do. |
1278 } | 1296 } |
1279 | 1297 |
1280 // 2. First pass to create simple CG edges (doesn't require to walk CG). | 1298 // 2. First pass to create simple CG edges (doesn't require to walk CG). |
1281 for( uint next = 0; next < _delayed_worklist.size(); ++next ) { | 1299 uint delayed_size = _delayed_worklist.size(); |
1300 for( uint next = 0; next < delayed_size; ++next ) { | |
1282 Node* n = _delayed_worklist.at(next); | 1301 Node* n = _delayed_worklist.at(next); |
1283 build_connection_graph(n, igvn); | 1302 build_connection_graph(n, igvn); |
1284 } | 1303 } |
1285 | 1304 |
1286 // 3. Pass to create fields edges (Allocate -F-> AddP). | 1305 // 3. Pass to create fields edges (Allocate -F-> AddP). |
1287 for( int next = 0; next < cg_worklist.length(); ++next ) { | 1306 uint cg_length = cg_worklist.length(); |
1307 for( uint next = 0; next < cg_length; ++next ) { | |
1288 int ni = cg_worklist.at(next); | 1308 int ni = cg_worklist.at(next); |
1289 build_connection_graph(_nodes->adr_at(ni)->_node, igvn); | 1309 build_connection_graph(ptnode_adr(ni)->_node, igvn); |
1290 } | 1310 } |
1291 | 1311 |
1292 cg_worklist.clear(); | 1312 cg_worklist.clear(); |
1293 cg_worklist.append(_phantom_object); | 1313 cg_worklist.append(_phantom_object); |
1294 | 1314 |
1295 // 4. Build Connection Graph which need | 1315 // 4. Build Connection Graph which need |
1296 // to walk the connection graph. | 1316 // to walk the connection graph. |
1297 for (uint ni = 0; ni < (uint)_nodes->length(); ni++) { | 1317 for (uint ni = 0; ni < nodes_size(); ni++) { |
1298 PointsToNode* ptn = _nodes->adr_at(ni); | 1318 PointsToNode* ptn = ptnode_adr(ni); |
1299 Node *n = ptn->_node; | 1319 Node *n = ptn->_node; |
1300 if (n != NULL) { // Call, AddP, LoadP, StoreP | 1320 if (n != NULL) { // Call, AddP, LoadP, StoreP |
1301 build_connection_graph(n, igvn); | 1321 build_connection_graph(n, igvn); |
1302 if (ptn->node_type() != PointsToNode::UnknownType) | 1322 if (ptn->node_type() != PointsToNode::UnknownType) |
1303 cg_worklist.append(n->_idx); // Collect CG nodes | 1323 cg_worklist.append(n->_idx); // Collect CG nodes |
1304 } | 1324 } |
1305 } | 1325 } |
1306 | 1326 |
1307 VectorSet ptset(Thread::current()->resource_area()); | 1327 VectorSet ptset(Thread::current()->resource_area()); |
1308 GrowableArray<Node*> alloc_worklist; | |
1309 GrowableArray<int> worklist; | |
1310 GrowableArray<uint> deferred_edges; | 1328 GrowableArray<uint> deferred_edges; |
1311 VectorSet visited(Thread::current()->resource_area()); | 1329 VectorSet visited(Thread::current()->resource_area()); |
1312 | 1330 |
1313 // remove deferred edges from the graph and collect | 1331 // 5. Remove deferred edges from the graph and collect |
1314 // information we will need for type splitting | 1332 // information needed for type splitting. |
1315 for( int next = 0; next < cg_worklist.length(); ++next ) { | 1333 cg_length = cg_worklist.length(); |
1334 for( uint next = 0; next < cg_length; ++next ) { | |
1316 int ni = cg_worklist.at(next); | 1335 int ni = cg_worklist.at(next); |
1317 PointsToNode* ptn = _nodes->adr_at(ni); | 1336 PointsToNode* ptn = ptnode_adr(ni); |
1318 PointsToNode::NodeType nt = ptn->node_type(); | 1337 PointsToNode::NodeType nt = ptn->node_type(); |
1319 Node *n = ptn->_node; | |
1320 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { | 1338 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { |
1321 remove_deferred(ni, &deferred_edges, &visited); | 1339 remove_deferred(ni, &deferred_edges, &visited); |
1340 Node *n = ptn->_node; | |
1322 if (n->is_AddP()) { | 1341 if (n->is_AddP()) { |
1323 // If this AddP computes an address which may point to more that one | 1342 // If this AddP computes an address which may point to more that one |
1324 // object or more then one field (array's element), nothing the address | 1343 // object or more then one field (array's element), nothing the address |
1325 // points to can be scalar replaceable. | 1344 // points to can be scalar replaceable. |
1326 Node *base = get_addp_base(n); | 1345 Node *base = get_addp_base(n); |
1327 ptset.Clear(); | 1346 ptset.Clear(); |
1328 PointsTo(ptset, base, igvn); | 1347 PointsTo(ptset, base, igvn); |
1329 if (ptset.Size() > 1 || | 1348 if (ptset.Size() > 1 || |
1330 (ptset.Size() != 0 && ptn->offset() == Type::OffsetBot)) { | 1349 (ptset.Size() != 0 && ptn->offset() == Type::OffsetBot)) { |
1331 for( VectorSetI j(&ptset); j.test(); ++j ) { | 1350 for( VectorSetI j(&ptset); j.test(); ++j ) { |
1332 uint pt = j.elem; | 1351 ptnode_adr(j.elem)->_scalar_replaceable = false; |
1333 ptnode_adr(pt)->_scalar_replaceable = false; | |
1334 } | 1352 } |
1335 } | 1353 } |
1336 } | 1354 } |
1337 } else if (nt == PointsToNode::JavaObject && n->is_Call()) { | 1355 } |
1338 // Push call on alloc_worlist (alocations are calls) | 1356 } |
1339 // for processing by split_unique_types(). | 1357 |
1340 alloc_worklist.append(n); | 1358 // 6. Propagate escape states. |
1341 } | 1359 GrowableArray<int> worklist; |
1342 } | 1360 bool has_non_escaping_obj = false; |
1343 | 1361 |
1344 // push all GlobalEscape nodes on the worklist | 1362 // push all GlobalEscape nodes on the worklist |
1345 for( int next = 0; next < cg_worklist.length(); ++next ) { | 1363 for( uint next = 0; next < cg_length; ++next ) { |
1346 int nk = cg_worklist.at(next); | 1364 int nk = cg_worklist.at(next); |
1347 if (_nodes->adr_at(nk)->escape_state() == PointsToNode::GlobalEscape) | 1365 if (ptnode_adr(nk)->escape_state() == PointsToNode::GlobalEscape) |
1348 worklist.append(nk); | 1366 worklist.push(nk); |
1349 } | 1367 } |
1350 // mark all node reachable from GlobalEscape nodes | 1368 // mark all nodes reachable from GlobalEscape nodes |
1351 while(worklist.length() > 0) { | 1369 while(worklist.length() > 0) { |
1352 PointsToNode n = _nodes->at(worklist.pop()); | 1370 PointsToNode* ptn = ptnode_adr(worklist.pop()); |
1353 for (uint ei = 0; ei < n.edge_count(); ei++) { | 1371 uint e_cnt = ptn->edge_count(); |
1354 uint npi = n.edge_target(ei); | 1372 for (uint ei = 0; ei < e_cnt; ei++) { |
1373 uint npi = ptn->edge_target(ei); | |
1355 PointsToNode *np = ptnode_adr(npi); | 1374 PointsToNode *np = ptnode_adr(npi); |
1356 if (np->escape_state() < PointsToNode::GlobalEscape) { | 1375 if (np->escape_state() < PointsToNode::GlobalEscape) { |
1357 np->set_escape_state(PointsToNode::GlobalEscape); | 1376 np->set_escape_state(PointsToNode::GlobalEscape); |
1358 worklist.append_if_missing(npi); | 1377 worklist.push(npi); |
1359 } | 1378 } |
1360 } | 1379 } |
1361 } | 1380 } |
1362 | 1381 |
1363 // push all ArgEscape nodes on the worklist | 1382 // push all ArgEscape nodes on the worklist |
1364 for( int next = 0; next < cg_worklist.length(); ++next ) { | 1383 for( uint next = 0; next < cg_length; ++next ) { |
1365 int nk = cg_worklist.at(next); | 1384 int nk = cg_worklist.at(next); |
1366 if (_nodes->adr_at(nk)->escape_state() == PointsToNode::ArgEscape) | 1385 if (ptnode_adr(nk)->escape_state() == PointsToNode::ArgEscape) |
1367 worklist.push(nk); | 1386 worklist.push(nk); |
1368 } | 1387 } |
1369 // mark all node reachable from ArgEscape nodes | 1388 // mark all nodes reachable from ArgEscape nodes |
1370 while(worklist.length() > 0) { | 1389 while(worklist.length() > 0) { |
1371 PointsToNode n = _nodes->at(worklist.pop()); | 1390 PointsToNode* ptn = ptnode_adr(worklist.pop()); |
1372 for (uint ei = 0; ei < n.edge_count(); ei++) { | 1391 if (ptn->node_type() == PointsToNode::JavaObject) |
1373 uint npi = n.edge_target(ei); | 1392 has_non_escaping_obj = true; // Non GlobalEscape |
1393 uint e_cnt = ptn->edge_count(); | |
1394 for (uint ei = 0; ei < e_cnt; ei++) { | |
1395 uint npi = ptn->edge_target(ei); | |
1374 PointsToNode *np = ptnode_adr(npi); | 1396 PointsToNode *np = ptnode_adr(npi); |
1375 if (np->escape_state() < PointsToNode::ArgEscape) { | 1397 if (np->escape_state() < PointsToNode::ArgEscape) { |
1376 np->set_escape_state(PointsToNode::ArgEscape); | 1398 np->set_escape_state(PointsToNode::ArgEscape); |
1377 worklist.append_if_missing(npi); | 1399 worklist.push(npi); |
1378 } | 1400 } |
1379 } | 1401 } |
1380 } | 1402 } |
1403 | |
1404 GrowableArray<Node*> alloc_worklist; | |
1381 | 1405 |
1382 // push all NoEscape nodes on the worklist | 1406 // push all NoEscape nodes on the worklist |
1383 for( int next = 0; next < cg_worklist.length(); ++next ) { | 1407 for( uint next = 0; next < cg_length; ++next ) { |
1384 int nk = cg_worklist.at(next); | 1408 int nk = cg_worklist.at(next); |
1385 if (_nodes->adr_at(nk)->escape_state() == PointsToNode::NoEscape) | 1409 if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape) |
1386 worklist.push(nk); | 1410 worklist.push(nk); |
1387 } | 1411 } |
1388 // mark all node reachable from NoEscape nodes | 1412 // mark all nodes reachable from NoEscape nodes |
1389 while(worklist.length() > 0) { | 1413 while(worklist.length() > 0) { |
1390 PointsToNode n = _nodes->at(worklist.pop()); | 1414 PointsToNode* ptn = ptnode_adr(worklist.pop()); |
1391 for (uint ei = 0; ei < n.edge_count(); ei++) { | 1415 if (ptn->node_type() == PointsToNode::JavaObject) |
1392 uint npi = n.edge_target(ei); | 1416 has_non_escaping_obj = true; // Non GlobalEscape |
1417 Node* n = ptn->_node; | |
1418 if (n->is_Allocate() && ptn->_scalar_replaceable ) { | |
1419 // Push scalar replaceable alocations on alloc_worklist | |
1420 // for processing in split_unique_types(). | |
1421 alloc_worklist.append(n); | |
1422 } | |
1423 uint e_cnt = ptn->edge_count(); | |
1424 for (uint ei = 0; ei < e_cnt; ei++) { | |
1425 uint npi = ptn->edge_target(ei); | |
1393 PointsToNode *np = ptnode_adr(npi); | 1426 PointsToNode *np = ptnode_adr(npi); |
1394 if (np->escape_state() < PointsToNode::NoEscape) { | 1427 if (np->escape_state() < PointsToNode::NoEscape) { |
1395 np->set_escape_state(PointsToNode::NoEscape); | 1428 np->set_escape_state(PointsToNode::NoEscape); |
1396 worklist.append_if_missing(npi); | 1429 worklist.push(npi); |
1397 } | 1430 } |
1398 } | 1431 } |
1399 } | 1432 } |
1400 | 1433 |
1401 _collecting = false; | 1434 _collecting = false; |
1402 | 1435 assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build"); |
1403 has_allocations = false; // Are there scalar replaceable allocations? | 1436 |
1404 | 1437 bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0; |
1405 for( int next = 0; next < alloc_worklist.length(); ++next ) { | 1438 if ( has_scalar_replaceable_candidates && |
1406 Node* n = alloc_worklist.at(next); | 1439 C->AliasLevel() >= 3 && EliminateAllocations ) { |
1407 uint ni = n->_idx; | 1440 |
1408 PointsToNode* ptn = _nodes->adr_at(ni); | |
1409 PointsToNode::EscapeState es = ptn->escape_state(); | |
1410 if (ptn->escape_state() == PointsToNode::NoEscape && | |
1411 ptn->_scalar_replaceable) { | |
1412 has_allocations = true; | |
1413 break; | |
1414 } | |
1415 } | |
1416 if (!has_allocations) { | |
1417 return; // Nothing to do. | |
1418 } | |
1419 | |
1420 if(_compile->AliasLevel() >= 3 && EliminateAllocations) { | |
1421 // Now use the escape information to create unique types for | 1441 // Now use the escape information to create unique types for |
1422 // unescaped objects | 1442 // scalar replaceable objects. |
1423 split_unique_types(alloc_worklist); | 1443 split_unique_types(alloc_worklist); |
1424 if (_compile->failing()) return; | 1444 |
1445 if (C->failing()) return false; | |
1425 | 1446 |
1426 // Clean up after split unique types. | 1447 // Clean up after split unique types. |
1427 ResourceMark rm; | 1448 ResourceMark rm; |
1428 PhaseRemoveUseless pru(_compile->initial_gvn(), _compile->for_igvn()); | 1449 PhaseRemoveUseless pru(C->initial_gvn(), C->for_igvn()); |
1450 | |
1451 C->print_method("After Escape Analysis", 2); | |
1429 | 1452 |
1430 #ifdef ASSERT | 1453 #ifdef ASSERT |
1431 } else if (PrintEscapeAnalysis || PrintEliminateAllocations) { | 1454 } else if (Verbose && (PrintEscapeAnalysis || PrintEliminateAllocations)) { |
1432 tty->print("=== No allocations eliminated for "); | 1455 tty->print("=== No allocations eliminated for "); |
1433 C()->method()->print_short_name(); | 1456 C->method()->print_short_name(); |
1434 if(!EliminateAllocations) { | 1457 if(!EliminateAllocations) { |
1435 tty->print(" since EliminateAllocations is off ==="); | 1458 tty->print(" since EliminateAllocations is off ==="); |
1436 } else if(_compile->AliasLevel() < 3) { | 1459 } else if(!has_scalar_replaceable_candidates) { |
1460 tty->print(" since there are no scalar replaceable candidates ==="); | |
1461 } else if(C->AliasLevel() < 3) { | |
1437 tty->print(" since AliasLevel < 3 ==="); | 1462 tty->print(" since AliasLevel < 3 ==="); |
1438 } | 1463 } |
1439 tty->cr(); | 1464 tty->cr(); |
1440 #endif | 1465 #endif |
1441 } | 1466 } |
1467 return has_non_escaping_obj; | |
1442 } | 1468 } |
1443 | 1469 |
1444 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { | 1470 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { |
1445 | 1471 |
1446 switch (call->Opcode()) { | 1472 switch (call->Opcode()) { |
1536 } | 1562 } |
1537 } | 1563 } |
1538 } | 1564 } |
1539 } | 1565 } |
1540 if (copy_dependencies) | 1566 if (copy_dependencies) |
1541 call_analyzer->copy_dependencies(C()->dependencies()); | 1567 call_analyzer->copy_dependencies(_compile->dependencies()); |
1542 break; | 1568 break; |
1543 } | 1569 } |
1544 } | 1570 } |
1545 | 1571 |
1546 default: | 1572 default: |
1559 ptset.Clear(); | 1585 ptset.Clear(); |
1560 PointsTo(ptset, arg, phase); | 1586 PointsTo(ptset, arg, phase); |
1561 for( VectorSetI j(&ptset); j.test(); ++j ) { | 1587 for( VectorSetI j(&ptset); j.test(); ++j ) { |
1562 uint pt = j.elem; | 1588 uint pt = j.elem; |
1563 set_escape_state(pt, PointsToNode::GlobalEscape); | 1589 set_escape_state(pt, PointsToNode::GlobalEscape); |
1564 PointsToNode *ptadr = ptnode_adr(pt); | |
1565 } | 1590 } |
1566 } | 1591 } |
1567 } | 1592 } |
1568 } | 1593 } |
1569 } | 1594 } |
1570 } | 1595 } |
1571 void ConnectionGraph::process_call_result(ProjNode *resproj, PhaseTransform *phase) { | 1596 void ConnectionGraph::process_call_result(ProjNode *resproj, PhaseTransform *phase) { |
1572 PointsToNode *ptadr = ptnode_adr(resproj->_idx); | 1597 CallNode *call = resproj->in(0)->as_Call(); |
1573 | 1598 uint call_idx = call->_idx; |
1574 CallNode *call = resproj->in(0)->as_Call(); | 1599 uint resproj_idx = resproj->_idx; |
1600 | |
1575 switch (call->Opcode()) { | 1601 switch (call->Opcode()) { |
1576 case Op_Allocate: | 1602 case Op_Allocate: |
1577 { | 1603 { |
1578 Node *k = call->in(AllocateNode::KlassNode); | 1604 Node *k = call->in(AllocateNode::KlassNode); |
1579 const TypeKlassPtr *kt; | 1605 const TypeKlassPtr *kt; |
1585 } | 1611 } |
1586 assert(kt != NULL, "TypeKlassPtr required."); | 1612 assert(kt != NULL, "TypeKlassPtr required."); |
1587 ciKlass* cik = kt->klass(); | 1613 ciKlass* cik = kt->klass(); |
1588 ciInstanceKlass* ciik = cik->as_instance_klass(); | 1614 ciInstanceKlass* ciik = cik->as_instance_klass(); |
1589 | 1615 |
1590 PointsToNode *ptadr = ptnode_adr(call->_idx); | |
1591 PointsToNode::EscapeState es; | 1616 PointsToNode::EscapeState es; |
1592 uint edge_to; | 1617 uint edge_to; |
1593 if (cik->is_subclass_of(_compile->env()->Thread_klass()) || ciik->has_finalizer()) { | 1618 if (cik->is_subclass_of(_compile->env()->Thread_klass()) || ciik->has_finalizer()) { |
1594 es = PointsToNode::GlobalEscape; | 1619 es = PointsToNode::GlobalEscape; |
1595 edge_to = _phantom_object; // Could not be worse | 1620 edge_to = _phantom_object; // Could not be worse |
1596 } else { | 1621 } else { |
1597 es = PointsToNode::NoEscape; | 1622 es = PointsToNode::NoEscape; |
1598 edge_to = call->_idx; | 1623 edge_to = call_idx; |
1599 } | 1624 } |
1600 set_escape_state(call->_idx, es); | 1625 set_escape_state(call_idx, es); |
1601 add_pointsto_edge(resproj->_idx, edge_to); | 1626 add_pointsto_edge(resproj_idx, edge_to); |
1602 _processed.set(resproj->_idx); | 1627 _processed.set(resproj_idx); |
1603 break; | 1628 break; |
1604 } | 1629 } |
1605 | 1630 |
1606 case Op_AllocateArray: | 1631 case Op_AllocateArray: |
1607 { | 1632 { |
1608 PointsToNode *ptadr = ptnode_adr(call->_idx); | |
1609 int length = call->in(AllocateNode::ALength)->find_int_con(-1); | 1633 int length = call->in(AllocateNode::ALength)->find_int_con(-1); |
1610 if (length < 0 || length > EliminateAllocationArraySizeLimit) { | 1634 if (length < 0 || length > EliminateAllocationArraySizeLimit) { |
1611 // Not scalar replaceable if the length is not constant or too big. | 1635 // Not scalar replaceable if the length is not constant or too big. |
1612 ptadr->_scalar_replaceable = false; | 1636 ptnode_adr(call_idx)->_scalar_replaceable = false; |
1613 } | 1637 } |
1614 set_escape_state(call->_idx, PointsToNode::NoEscape); | 1638 set_escape_state(call_idx, PointsToNode::NoEscape); |
1615 add_pointsto_edge(resproj->_idx, call->_idx); | 1639 add_pointsto_edge(resproj_idx, call_idx); |
1616 _processed.set(resproj->_idx); | 1640 _processed.set(resproj_idx); |
1617 break; | 1641 break; |
1618 } | 1642 } |
1619 | 1643 |
1620 case Op_CallStaticJava: | 1644 case Op_CallStaticJava: |
1621 // For a static call, we know exactly what method is being called. | 1645 // For a static call, we know exactly what method is being called. |
1629 ret_type = r->field_at(TypeFunc::Parms); | 1653 ret_type = r->field_at(TypeFunc::Parms); |
1630 | 1654 |
1631 // Note: we use isa_ptr() instead of isa_oopptr() here because the | 1655 // Note: we use isa_ptr() instead of isa_oopptr() here because the |
1632 // _multianewarray functions return a TypeRawPtr. | 1656 // _multianewarray functions return a TypeRawPtr. |
1633 if (ret_type == NULL || ret_type->isa_ptr() == NULL) { | 1657 if (ret_type == NULL || ret_type->isa_ptr() == NULL) { |
1634 _processed.set(resproj->_idx); | 1658 _processed.set(resproj_idx); |
1635 break; // doesn't return a pointer type | 1659 break; // doesn't return a pointer type |
1636 } | 1660 } |
1637 ciMethod *meth = call->as_CallJava()->method(); | 1661 ciMethod *meth = call->as_CallJava()->method(); |
1638 const TypeTuple * d = call->tf()->domain(); | 1662 const TypeTuple * d = call->tf()->domain(); |
1639 if (meth == NULL) { | 1663 if (meth == NULL) { |
1640 // not a Java method, assume global escape | 1664 // not a Java method, assume global escape |
1641 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | 1665 set_escape_state(call_idx, PointsToNode::GlobalEscape); |
1642 if (resproj != NULL) | 1666 add_pointsto_edge(resproj_idx, _phantom_object); |
1643 add_pointsto_edge(resproj->_idx, _phantom_object); | |
1644 } else { | 1667 } else { |
1645 BCEscapeAnalyzer *call_analyzer = meth->get_bcea(); | 1668 BCEscapeAnalyzer *call_analyzer = meth->get_bcea(); |
1646 VectorSet ptset(Thread::current()->resource_area()); | |
1647 bool copy_dependencies = false; | 1669 bool copy_dependencies = false; |
1648 | 1670 |
1649 if (call_analyzer->is_return_allocated()) { | 1671 if (call_analyzer->is_return_allocated()) { |
1650 // Returns a newly allocated unescaped object, simply | 1672 // Returns a newly allocated unescaped object, simply |
1651 // update dependency information. | 1673 // update dependency information. |
1652 // Mark it as NoEscape so that objects referenced by | 1674 // Mark it as NoEscape so that objects referenced by |
1653 // it's fields will be marked as NoEscape at least. | 1675 // it's fields will be marked as NoEscape at least. |
1654 set_escape_state(call->_idx, PointsToNode::NoEscape); | 1676 set_escape_state(call_idx, PointsToNode::NoEscape); |
1655 if (resproj != NULL) | 1677 add_pointsto_edge(resproj_idx, call_idx); |
1656 add_pointsto_edge(resproj->_idx, call->_idx); | |
1657 copy_dependencies = true; | 1678 copy_dependencies = true; |
1658 } else if (call_analyzer->is_return_local() && resproj != NULL) { | 1679 } else if (call_analyzer->is_return_local()) { |
1659 // determine whether any arguments are returned | 1680 // determine whether any arguments are returned |
1660 set_escape_state(call->_idx, PointsToNode::NoEscape); | 1681 set_escape_state(call_idx, PointsToNode::NoEscape); |
1661 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { | 1682 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { |
1662 const Type* at = d->field_at(i); | 1683 const Type* at = d->field_at(i); |
1663 | 1684 |
1664 if (at->isa_oopptr() != NULL) { | 1685 if (at->isa_oopptr() != NULL) { |
1665 Node *arg = call->in(i)->uncast(); | 1686 Node *arg = call->in(i)->uncast(); |
1666 | 1687 |
1667 if (call_analyzer->is_arg_returned(i - TypeFunc::Parms)) { | 1688 if (call_analyzer->is_arg_returned(i - TypeFunc::Parms)) { |
1668 PointsToNode *arg_esp = _nodes->adr_at(arg->_idx); | 1689 PointsToNode *arg_esp = ptnode_adr(arg->_idx); |
1669 if (arg_esp->node_type() == PointsToNode::UnknownType) | 1690 if (arg_esp->node_type() == PointsToNode::UnknownType) |
1670 done = false; | 1691 done = false; |
1671 else if (arg_esp->node_type() == PointsToNode::JavaObject) | 1692 else if (arg_esp->node_type() == PointsToNode::JavaObject) |
1672 add_pointsto_edge(resproj->_idx, arg->_idx); | 1693 add_pointsto_edge(resproj_idx, arg->_idx); |
1673 else | 1694 else |
1674 add_deferred_edge(resproj->_idx, arg->_idx); | 1695 add_deferred_edge(resproj_idx, arg->_idx); |
1675 arg_esp->_hidden_alias = true; | 1696 arg_esp->_hidden_alias = true; |
1676 } | 1697 } |
1677 } | 1698 } |
1678 } | 1699 } |
1679 copy_dependencies = true; | 1700 copy_dependencies = true; |
1680 } else { | 1701 } else { |
1681 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | 1702 set_escape_state(call_idx, PointsToNode::GlobalEscape); |
1682 if (resproj != NULL) | 1703 add_pointsto_edge(resproj_idx, _phantom_object); |
1683 add_pointsto_edge(resproj->_idx, _phantom_object); | |
1684 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { | 1704 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { |
1685 const Type* at = d->field_at(i); | 1705 const Type* at = d->field_at(i); |
1686 if (at->isa_oopptr() != NULL) { | 1706 if (at->isa_oopptr() != NULL) { |
1687 Node *arg = call->in(i)->uncast(); | 1707 Node *arg = call->in(i)->uncast(); |
1688 PointsToNode *arg_esp = _nodes->adr_at(arg->_idx); | 1708 PointsToNode *arg_esp = ptnode_adr(arg->_idx); |
1689 arg_esp->_hidden_alias = true; | 1709 arg_esp->_hidden_alias = true; |
1690 } | 1710 } |
1691 } | 1711 } |
1692 } | 1712 } |
1693 if (copy_dependencies) | 1713 if (copy_dependencies) |
1694 call_analyzer->copy_dependencies(C()->dependencies()); | 1714 call_analyzer->copy_dependencies(_compile->dependencies()); |
1695 } | 1715 } |
1696 if (done) | 1716 if (done) |
1697 _processed.set(resproj->_idx); | 1717 _processed.set(resproj_idx); |
1698 break; | 1718 break; |
1699 } | 1719 } |
1700 | 1720 |
1701 default: | 1721 default: |
1702 // Some other type of call, assume the worst case that the | 1722 // Some other type of call, assume the worst case that the |
1707 const Type* ret_type = r->field_at(TypeFunc::Parms); | 1727 const Type* ret_type = r->field_at(TypeFunc::Parms); |
1708 | 1728 |
1709 // Note: we use isa_ptr() instead of isa_oopptr() here because the | 1729 // Note: we use isa_ptr() instead of isa_oopptr() here because the |
1710 // _multianewarray functions return a TypeRawPtr. | 1730 // _multianewarray functions return a TypeRawPtr. |
1711 if (ret_type->isa_ptr() != NULL) { | 1731 if (ret_type->isa_ptr() != NULL) { |
1712 PointsToNode *ptadr = ptnode_adr(call->_idx); | 1732 set_escape_state(call_idx, PointsToNode::GlobalEscape); |
1713 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | 1733 add_pointsto_edge(resproj_idx, _phantom_object); |
1714 if (resproj != NULL) | 1734 } |
1715 add_pointsto_edge(resproj->_idx, _phantom_object); | 1735 } |
1716 } | 1736 _processed.set(resproj_idx); |
1717 } | |
1718 _processed.set(resproj->_idx); | |
1719 } | 1737 } |
1720 } | 1738 } |
1721 } | 1739 } |
1722 | 1740 |
1723 // Populate Connection Graph with Ideal nodes and create simple | 1741 // Populate Connection Graph with Ideal nodes and create simple |
1741 // Have to process call's arguments first. | 1759 // Have to process call's arguments first. |
1742 PointsToNode::NodeType nt = PointsToNode::UnknownType; | 1760 PointsToNode::NodeType nt = PointsToNode::UnknownType; |
1743 | 1761 |
1744 // Check if a call returns an object. | 1762 // Check if a call returns an object. |
1745 const TypeTuple *r = n->as_Call()->tf()->range(); | 1763 const TypeTuple *r = n->as_Call()->tf()->range(); |
1746 if (r->cnt() > TypeFunc::Parms && | 1764 if (n->is_CallStaticJava() && r->cnt() > TypeFunc::Parms && |
1747 n->as_Call()->proj_out(TypeFunc::Parms) != NULL) { | 1765 n->as_Call()->proj_out(TypeFunc::Parms) != NULL) { |
1748 // Note: use isa_ptr() instead of isa_oopptr() here because | 1766 // Note: use isa_ptr() instead of isa_oopptr() here because |
1749 // the _multianewarray functions return a TypeRawPtr. | 1767 // the _multianewarray functions return a TypeRawPtr. |
1750 if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) { | 1768 if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) { |
1751 nt = PointsToNode::JavaObject; | 1769 nt = PointsToNode::JavaObject; |
1774 case Op_EncodeP: | 1792 case Op_EncodeP: |
1775 case Op_DecodeN: | 1793 case Op_DecodeN: |
1776 { | 1794 { |
1777 add_node(n, PointsToNode::LocalVar, PointsToNode::UnknownEscape, false); | 1795 add_node(n, PointsToNode::LocalVar, PointsToNode::UnknownEscape, false); |
1778 int ti = n->in(1)->_idx; | 1796 int ti = n->in(1)->_idx; |
1779 PointsToNode::NodeType nt = _nodes->adr_at(ti)->node_type(); | 1797 PointsToNode::NodeType nt = ptnode_adr(ti)->node_type(); |
1780 if (nt == PointsToNode::UnknownType) { | 1798 if (nt == PointsToNode::UnknownType) { |
1781 _delayed_worklist.push(n); // Process it later. | 1799 _delayed_worklist.push(n); // Process it later. |
1782 break; | 1800 break; |
1783 } else if (nt == PointsToNode::JavaObject) { | 1801 } else if (nt == PointsToNode::JavaObject) { |
1784 add_pointsto_edge(n->_idx, ti); | 1802 add_pointsto_edge(n->_idx, ti); |
1864 continue; // ignore NULL | 1882 continue; // ignore NULL |
1865 in = in->uncast(); | 1883 in = in->uncast(); |
1866 if (in->is_top() || in == n) | 1884 if (in->is_top() || in == n) |
1867 continue; // ignore top or inputs which go back this node | 1885 continue; // ignore top or inputs which go back this node |
1868 int ti = in->_idx; | 1886 int ti = in->_idx; |
1869 PointsToNode::NodeType nt = _nodes->adr_at(ti)->node_type(); | 1887 PointsToNode::NodeType nt = ptnode_adr(ti)->node_type(); |
1870 if (nt == PointsToNode::UnknownType) { | 1888 if (nt == PointsToNode::UnknownType) { |
1871 break; | 1889 break; |
1872 } else if (nt == PointsToNode::JavaObject) { | 1890 } else if (nt == PointsToNode::JavaObject) { |
1873 add_pointsto_edge(n->_idx, ti); | 1891 add_pointsto_edge(n->_idx, ti); |
1874 } else { | 1892 } else { |
1902 if( n->req() > TypeFunc::Parms && | 1920 if( n->req() > TypeFunc::Parms && |
1903 phase->type(n->in(TypeFunc::Parms))->isa_oopptr() ) { | 1921 phase->type(n->in(TypeFunc::Parms))->isa_oopptr() ) { |
1904 // Treat Return value as LocalVar with GlobalEscape escape state. | 1922 // Treat Return value as LocalVar with GlobalEscape escape state. |
1905 add_node(n, PointsToNode::LocalVar, PointsToNode::GlobalEscape, false); | 1923 add_node(n, PointsToNode::LocalVar, PointsToNode::GlobalEscape, false); |
1906 int ti = n->in(TypeFunc::Parms)->_idx; | 1924 int ti = n->in(TypeFunc::Parms)->_idx; |
1907 PointsToNode::NodeType nt = _nodes->adr_at(ti)->node_type(); | 1925 PointsToNode::NodeType nt = ptnode_adr(ti)->node_type(); |
1908 if (nt == PointsToNode::UnknownType) { | 1926 if (nt == PointsToNode::UnknownType) { |
1909 _delayed_worklist.push(n); // Process it later. | 1927 _delayed_worklist.push(n); // Process it later. |
1910 break; | 1928 break; |
1911 } else if (nt == PointsToNode::JavaObject) { | 1929 } else if (nt == PointsToNode::JavaObject) { |
1912 add_pointsto_edge(n->_idx, ti); | 1930 add_pointsto_edge(n->_idx, ti); |
1966 } | 1984 } |
1967 return; | 1985 return; |
1968 } | 1986 } |
1969 | 1987 |
1970 void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { | 1988 void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { |
1989 uint n_idx = n->_idx; | |
1990 | |
1971 // Don't set processed bit for AddP, LoadP, StoreP since | 1991 // Don't set processed bit for AddP, LoadP, StoreP since |
1972 // they may need more then one pass to process. | 1992 // they may need more then one pass to process. |
1973 if (_processed.test(n->_idx)) | 1993 if (_processed.test(n_idx)) |
1974 return; // No need to redefine node's state. | 1994 return; // No need to redefine node's state. |
1975 | |
1976 PointsToNode *ptadr = ptnode_adr(n->_idx); | |
1977 | 1995 |
1978 if (n->is_Call()) { | 1996 if (n->is_Call()) { |
1979 CallNode *call = n->as_Call(); | 1997 CallNode *call = n->as_Call(); |
1980 process_call_arguments(call, phase); | 1998 process_call_arguments(call, phase); |
1981 _processed.set(n->_idx); | 1999 _processed.set(n_idx); |
1982 return; | 2000 return; |
1983 } | 2001 } |
1984 | 2002 |
1985 switch (n->Opcode()) { | 2003 switch (n->Opcode()) { |
1986 case Op_AddP: | 2004 case Op_AddP: |
1989 // Create a field edge to this node from everything base could point to. | 2007 // Create a field edge to this node from everything base could point to. |
1990 VectorSet ptset(Thread::current()->resource_area()); | 2008 VectorSet ptset(Thread::current()->resource_area()); |
1991 PointsTo(ptset, base, phase); | 2009 PointsTo(ptset, base, phase); |
1992 for( VectorSetI i(&ptset); i.test(); ++i ) { | 2010 for( VectorSetI i(&ptset); i.test(); ++i ) { |
1993 uint pt = i.elem; | 2011 uint pt = i.elem; |
1994 add_field_edge(pt, n->_idx, address_offset(n, phase)); | 2012 add_field_edge(pt, n_idx, address_offset(n, phase)); |
1995 } | 2013 } |
1996 break; | 2014 break; |
1997 } | 2015 } |
1998 case Op_CastX2P: | 2016 case Op_CastX2P: |
1999 { | 2017 { |
2004 case Op_CheckCastPP: | 2022 case Op_CheckCastPP: |
2005 case Op_EncodeP: | 2023 case Op_EncodeP: |
2006 case Op_DecodeN: | 2024 case Op_DecodeN: |
2007 { | 2025 { |
2008 int ti = n->in(1)->_idx; | 2026 int ti = n->in(1)->_idx; |
2009 if (_nodes->adr_at(ti)->node_type() == PointsToNode::JavaObject) { | 2027 if (ptnode_adr(ti)->node_type() == PointsToNode::JavaObject) { |
2010 add_pointsto_edge(n->_idx, ti); | 2028 add_pointsto_edge(n_idx, ti); |
2011 } else { | 2029 } else { |
2012 add_deferred_edge(n->_idx, ti); | 2030 add_deferred_edge(n_idx, ti); |
2013 } | 2031 } |
2014 _processed.set(n->_idx); | 2032 _processed.set(n_idx); |
2015 break; | 2033 break; |
2016 } | 2034 } |
2017 case Op_ConP: | 2035 case Op_ConP: |
2018 { | 2036 { |
2019 assert(false, "Op_ConP"); | 2037 assert(false, "Op_ConP"); |
2058 VectorSet ptset(Thread::current()->resource_area()); | 2076 VectorSet ptset(Thread::current()->resource_area()); |
2059 PointsTo(ptset, adr_base, phase); | 2077 PointsTo(ptset, adr_base, phase); |
2060 int offset = address_offset(adr, phase); | 2078 int offset = address_offset(adr, phase); |
2061 for( VectorSetI i(&ptset); i.test(); ++i ) { | 2079 for( VectorSetI i(&ptset); i.test(); ++i ) { |
2062 uint pt = i.elem; | 2080 uint pt = i.elem; |
2063 add_deferred_edge_to_fields(n->_idx, pt, offset); | 2081 add_deferred_edge_to_fields(n_idx, pt, offset); |
2064 } | 2082 } |
2065 break; | 2083 break; |
2066 } | 2084 } |
2067 case Op_Parm: | 2085 case Op_Parm: |
2068 { | 2086 { |
2081 continue; // ignore NULL | 2099 continue; // ignore NULL |
2082 in = in->uncast(); | 2100 in = in->uncast(); |
2083 if (in->is_top() || in == n) | 2101 if (in->is_top() || in == n) |
2084 continue; // ignore top or inputs which go back this node | 2102 continue; // ignore top or inputs which go back this node |
2085 int ti = in->_idx; | 2103 int ti = in->_idx; |
2086 if (_nodes->adr_at(in->_idx)->node_type() == PointsToNode::JavaObject) { | 2104 if (ptnode_adr(in->_idx)->node_type() == PointsToNode::JavaObject) { |
2087 add_pointsto_edge(n->_idx, ti); | 2105 add_pointsto_edge(n_idx, ti); |
2088 } else { | 2106 } else { |
2089 add_deferred_edge(n->_idx, ti); | 2107 add_deferred_edge(n_idx, ti); |
2090 } | 2108 } |
2091 } | 2109 } |
2092 _processed.set(n->_idx); | 2110 _processed.set(n_idx); |
2093 break; | 2111 break; |
2094 } | 2112 } |
2095 case Op_Proj: | 2113 case Op_Proj: |
2096 { | 2114 { |
2097 // we are only interested in the result projection from a call | 2115 // we are only interested in the result projection from a call |
2098 if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() ) { | 2116 if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() ) { |
2099 process_call_result(n->as_Proj(), phase); | 2117 process_call_result(n->as_Proj(), phase); |
2100 assert(_processed.test(n->_idx), "all call results should be processed"); | 2118 assert(_processed.test(n_idx), "all call results should be processed"); |
2101 } else { | 2119 } else { |
2102 assert(false, "Op_Proj"); | 2120 assert(false, "Op_Proj"); |
2103 } | 2121 } |
2104 break; | 2122 break; |
2105 } | 2123 } |
2110 !phase->type(n->in(TypeFunc::Parms))->isa_oopptr() ) { | 2128 !phase->type(n->in(TypeFunc::Parms))->isa_oopptr() ) { |
2111 assert(false, "Op_Return"); | 2129 assert(false, "Op_Return"); |
2112 } | 2130 } |
2113 #endif | 2131 #endif |
2114 int ti = n->in(TypeFunc::Parms)->_idx; | 2132 int ti = n->in(TypeFunc::Parms)->_idx; |
2115 if (_nodes->adr_at(ti)->node_type() == PointsToNode::JavaObject) { | 2133 if (ptnode_adr(ti)->node_type() == PointsToNode::JavaObject) { |
2116 add_pointsto_edge(n->_idx, ti); | 2134 add_pointsto_edge(n_idx, ti); |
2117 } else { | 2135 } else { |
2118 add_deferred_edge(n->_idx, ti); | 2136 add_deferred_edge(n_idx, ti); |
2119 } | 2137 } |
2120 _processed.set(n->_idx); | 2138 _processed.set(n_idx); |
2121 break; | 2139 break; |
2122 } | 2140 } |
2123 case Op_StoreP: | 2141 case Op_StoreP: |
2124 case Op_StoreN: | 2142 case Op_StoreN: |
2125 case Op_StorePConditional: | 2143 case Op_StorePConditional: |
2160 #ifndef PRODUCT | 2178 #ifndef PRODUCT |
2161 void ConnectionGraph::dump() { | 2179 void ConnectionGraph::dump() { |
2162 PhaseGVN *igvn = _compile->initial_gvn(); | 2180 PhaseGVN *igvn = _compile->initial_gvn(); |
2163 bool first = true; | 2181 bool first = true; |
2164 | 2182 |
2165 uint size = (uint)_nodes->length(); | 2183 uint size = nodes_size(); |
2166 for (uint ni = 0; ni < size; ni++) { | 2184 for (uint ni = 0; ni < size; ni++) { |
2167 PointsToNode *ptn = _nodes->adr_at(ni); | 2185 PointsToNode *ptn = ptnode_adr(ni); |
2168 PointsToNode::NodeType ptn_type = ptn->node_type(); | 2186 PointsToNode::NodeType ptn_type = ptn->node_type(); |
2169 | 2187 |
2170 if (ptn_type != PointsToNode::JavaObject || ptn->_node == NULL) | 2188 if (ptn_type != PointsToNode::JavaObject || ptn->_node == NULL) |
2171 continue; | 2189 continue; |
2172 PointsToNode::EscapeState es = escape_state(ptn->_node, igvn); | 2190 PointsToNode::EscapeState es = escape_state(ptn->_node, igvn); |
2173 if (ptn->_node->is_Allocate() && (es == PointsToNode::NoEscape || Verbose)) { | 2191 if (ptn->_node->is_Allocate() && (es == PointsToNode::NoEscape || Verbose)) { |
2174 if (first) { | 2192 if (first) { |
2175 tty->cr(); | 2193 tty->cr(); |
2176 tty->print("======== Connection graph for "); | 2194 tty->print("======== Connection graph for "); |
2177 C()->method()->print_short_name(); | 2195 _compile->method()->print_short_name(); |
2178 tty->cr(); | 2196 tty->cr(); |
2179 first = false; | 2197 first = false; |
2180 } | 2198 } |
2181 tty->print("%6d ", ni); | 2199 tty->print("%6d ", ni); |
2182 ptn->dump(); | 2200 ptn->dump(); |
2183 // Print all locals which reference this allocation | 2201 // Print all locals which reference this allocation |
2184 for (uint li = ni; li < size; li++) { | 2202 for (uint li = ni; li < size; li++) { |
2185 PointsToNode *ptn_loc = _nodes->adr_at(li); | 2203 PointsToNode *ptn_loc = ptnode_adr(li); |
2186 PointsToNode::NodeType ptn_loc_type = ptn_loc->node_type(); | 2204 PointsToNode::NodeType ptn_loc_type = ptn_loc->node_type(); |
2187 if ( ptn_loc_type == PointsToNode::LocalVar && ptn_loc->_node != NULL && | 2205 if ( ptn_loc_type == PointsToNode::LocalVar && ptn_loc->_node != NULL && |
2188 ptn_loc->edge_count() == 1 && ptn_loc->edge_target(0) == ni ) { | 2206 ptn_loc->edge_count() == 1 && ptn_loc->edge_target(0) == ni ) { |
2189 tty->print("%6d LocalVar [[%d]]", li, ni); | 2207 tty->print("%6d LocalVar [[%d]]", li, ni); |
2190 _nodes->adr_at(li)->_node->dump(); | 2208 ptnode_adr(li)->_node->dump(); |
2191 } | 2209 } |
2192 } | 2210 } |
2193 if (Verbose) { | 2211 if (Verbose) { |
2194 // Print all fields which reference this allocation | 2212 // Print all fields which reference this allocation |
2195 for (uint i = 0; i < ptn->edge_count(); i++) { | 2213 for (uint i = 0; i < ptn->edge_count(); i++) { |
2196 uint ei = ptn->edge_target(i); | 2214 uint ei = ptn->edge_target(i); |
2197 tty->print("%6d Field [[%d]]", ei, ni); | 2215 tty->print("%6d Field [[%d]]", ei, ni); |
2198 _nodes->adr_at(ei)->_node->dump(); | 2216 ptnode_adr(ei)->_node->dump(); |
2199 } | 2217 } |
2200 } | 2218 } |
2201 tty->cr(); | 2219 tty->cr(); |
2202 } | 2220 } |
2203 } | 2221 } |