Mercurial > hg > truffle
annotate src/share/vm/opto/escape.cpp @ 39:76256d272075
6667612: (Escape Analysis) disable loop cloning if it has a scalar replaceable allocation
Summary: Cloning an allocation will not allow scalar replacement since memory operations could not be associated with one allocation.
Reviewed-by: rasbold
author | kvn |
---|---|
date | Thu, 06 Mar 2008 10:53:33 -0800 |
parents | b789bcaf2dd9 |
children | 99269dbf4ba8 |
rev | line source |
---|---|
0 | 1 /* |
2 * Copyright 2005-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any questions. | |
22 * | |
23 */ | |
24 | |
25 #include "incls/_precompiled.incl" | |
26 #include "incls/_escape.cpp.incl" | |
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) { | |
39 uint v = (targIdx << EdgeShift) + ((uint) et); | |
40 if (_edges == NULL) { | |
41 Arena *a = Compile::current()->comp_arena(); | |
42 _edges = new(a) GrowableArray<uint>(a, INITIAL_EDGE_COUNT, 0, 0); | |
43 } | |
44 _edges->append_if_missing(v); | |
45 } | |
46 | |
47 void PointsToNode::remove_edge(uint targIdx, PointsToNode::EdgeType et) { | |
48 uint v = (targIdx << EdgeShift) + ((uint) et); | |
49 | |
50 _edges->remove(v); | |
51 } | |
52 | |
53 #ifndef PRODUCT | |
54 static char *node_type_names[] = { | |
55 "UnknownType", | |
56 "JavaObject", | |
57 "LocalVar", | |
58 "Field" | |
59 }; | |
60 | |
61 static char *esc_names[] = { | |
62 "UnknownEscape", | |
63 "NoEscape ", | |
64 "ArgEscape ", | |
65 "GlobalEscape " | |
66 }; | |
67 | |
68 static char *edge_type_suffix[] = { | |
69 "?", // UnknownEdge | |
70 "P", // PointsToEdge | |
71 "D", // DeferredEdge | |
72 "F" // FieldEdge | |
73 }; | |
74 | |
75 void PointsToNode::dump() const { | |
76 NodeType nt = node_type(); | |
77 EscapeState es = escape_state(); | |
78 tty->print("%s %s [[", node_type_names[(int) nt], esc_names[(int) es]); | |
79 for (uint i = 0; i < edge_count(); i++) { | |
80 tty->print(" %d%s", edge_target(i), edge_type_suffix[(int) edge_type(i)]); | |
81 } | |
82 tty->print("]] "); | |
83 if (_node == NULL) | |
84 tty->print_cr("<null>"); | |
85 else | |
86 _node->dump(); | |
87 } | |
88 #endif | |
89 | |
90 ConnectionGraph::ConnectionGraph(Compile * C) : _processed(C->comp_arena()), _node_map(C->comp_arena()) { | |
91 _collecting = true; | |
92 this->_compile = C; | |
93 const PointsToNode &dummy = PointsToNode(); | |
94 _nodes = new(C->comp_arena()) GrowableArray<PointsToNode>(C->comp_arena(), (int) INITIAL_NODE_COUNT, 0, dummy); | |
95 _phantom_object = C->top()->_idx; | |
96 PointsToNode *phn = ptnode_adr(_phantom_object); | |
97 phn->set_node_type(PointsToNode::JavaObject); | |
98 phn->set_escape_state(PointsToNode::GlobalEscape); | |
99 } | |
100 | |
101 void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) { | |
102 PointsToNode *f = ptnode_adr(from_i); | |
103 PointsToNode *t = ptnode_adr(to_i); | |
104 | |
105 assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); | |
106 assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of PointsTo edge"); | |
107 assert(t->node_type() == PointsToNode::JavaObject, "invalid destination of PointsTo edge"); | |
108 f->add_edge(to_i, PointsToNode::PointsToEdge); | |
109 } | |
110 | |
111 void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) { | |
112 PointsToNode *f = ptnode_adr(from_i); | |
113 PointsToNode *t = ptnode_adr(to_i); | |
114 | |
115 assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); | |
116 assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of Deferred edge"); | |
117 assert(t->node_type() == PointsToNode::LocalVar || t->node_type() == PointsToNode::Field, "invalid destination of Deferred edge"); | |
118 // don't add a self-referential edge, this can occur during removal of | |
119 // deferred edges | |
120 if (from_i != to_i) | |
121 f->add_edge(to_i, PointsToNode::DeferredEdge); | |
122 } | |
123 | |
124 int ConnectionGraph::type_to_offset(const Type *t) { | |
125 const TypePtr *t_ptr = t->isa_ptr(); | |
126 assert(t_ptr != NULL, "must be a pointer type"); | |
127 return t_ptr->offset(); | |
128 } | |
129 | |
130 void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) { | |
131 PointsToNode *f = ptnode_adr(from_i); | |
132 PointsToNode *t = ptnode_adr(to_i); | |
133 | |
134 assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); | |
135 assert(f->node_type() == PointsToNode::JavaObject, "invalid destination of Field edge"); | |
136 assert(t->node_type() == PointsToNode::Field, "invalid destination of Field edge"); | |
137 assert (t->offset() == -1 || t->offset() == offset, "conflicting field offsets"); | |
138 t->set_offset(offset); | |
139 | |
140 f->add_edge(to_i, PointsToNode::FieldEdge); | |
141 } | |
142 | |
143 void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) { | |
144 PointsToNode *npt = ptnode_adr(ni); | |
145 PointsToNode::EscapeState old_es = npt->escape_state(); | |
146 if (es > old_es) | |
147 npt->set_escape_state(es); | |
148 } | |
149 | |
150 PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n, PhaseTransform *phase) { | |
151 uint idx = n->_idx; | |
152 PointsToNode::EscapeState es; | |
153 | |
154 // If we are still collecting we don't know the answer yet | |
155 if (_collecting) | |
156 return PointsToNode::UnknownEscape; | |
157 | |
158 // if the node was created after the escape computation, return | |
159 // UnknownEscape | |
160 if (idx >= (uint)_nodes->length()) | |
161 return PointsToNode::UnknownEscape; | |
162 | |
163 es = _nodes->at_grow(idx).escape_state(); | |
164 | |
165 // if we have already computed a value, return it | |
166 if (es != PointsToNode::UnknownEscape) | |
167 return es; | |
168 | |
169 // compute max escape state of anything this node could point to | |
170 VectorSet ptset(Thread::current()->resource_area()); | |
171 PointsTo(ptset, n, phase); | |
172 for( VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i ) { | |
173 uint pt = i.elem; | |
174 PointsToNode::EscapeState pes = _nodes->at(pt).escape_state(); | |
175 if (pes > es) | |
176 es = pes; | |
177 } | |
178 // cache the computed escape state | |
179 assert(es != PointsToNode::UnknownEscape, "should have computed an escape state"); | |
180 _nodes->adr_at(idx)->set_escape_state(es); | |
181 return es; | |
182 } | |
183 | |
184 void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase) { | |
185 VectorSet visited(Thread::current()->resource_area()); | |
186 GrowableArray<uint> worklist; | |
187 | |
188 n = skip_casts(n); | |
189 PointsToNode npt = _nodes->at_grow(n->_idx); | |
190 | |
191 // If we have a JavaObject, return just that object | |
192 if (npt.node_type() == PointsToNode::JavaObject) { | |
193 ptset.set(n->_idx); | |
194 return; | |
195 } | |
196 // we may have a Phi which has not been processed | |
197 if (npt._node == NULL) { | |
198 assert(n->is_Phi(), "unprocessed node must be a Phi"); | |
199 record_for_escape_analysis(n); | |
200 npt = _nodes->at(n->_idx); | |
201 } | |
202 worklist.push(n->_idx); | |
203 while(worklist.length() > 0) { | |
204 int ni = worklist.pop(); | |
205 PointsToNode pn = _nodes->at_grow(ni); | |
206 if (!visited.test(ni)) { | |
207 visited.set(ni); | |
208 | |
209 // ensure that all inputs of a Phi have been processed | |
210 if (_collecting && pn._node->is_Phi()) { | |
211 PhiNode *phi = pn._node->as_Phi(); | |
212 process_phi_escape(phi, phase); | |
213 } | |
214 | |
215 int edges_processed = 0; | |
216 for (uint e = 0; e < pn.edge_count(); e++) { | |
217 PointsToNode::EdgeType et = pn.edge_type(e); | |
218 if (et == PointsToNode::PointsToEdge) { | |
219 ptset.set(pn.edge_target(e)); | |
220 edges_processed++; | |
221 } else if (et == PointsToNode::DeferredEdge) { | |
222 worklist.push(pn.edge_target(e)); | |
223 edges_processed++; | |
224 } | |
225 } | |
226 if (edges_processed == 0) { | |
227 // no deferred or pointsto edges found. Assume the value was set outside | |
228 // this method. Add the phantom object to the pointsto set. | |
229 ptset.set(_phantom_object); | |
230 } | |
231 } | |
232 } | |
233 } | |
234 | |
235 void ConnectionGraph::remove_deferred(uint ni) { | |
236 VectorSet visited(Thread::current()->resource_area()); | |
237 | |
238 uint i = 0; | |
239 PointsToNode *ptn = ptnode_adr(ni); | |
240 | |
241 while(i < ptn->edge_count()) { | |
242 if (ptn->edge_type(i) != PointsToNode::DeferredEdge) { | |
243 i++; | |
244 } else { | |
245 uint t = ptn->edge_target(i); | |
246 PointsToNode *ptt = ptnode_adr(t); | |
247 ptn->remove_edge(t, PointsToNode::DeferredEdge); | |
248 if(!visited.test(t)) { | |
249 visited.set(t); | |
250 for (uint j = 0; j < ptt->edge_count(); j++) { | |
251 uint n1 = ptt->edge_target(j); | |
252 PointsToNode *pt1 = ptnode_adr(n1); | |
253 switch(ptt->edge_type(j)) { | |
254 case PointsToNode::PointsToEdge: | |
255 add_pointsto_edge(ni, n1); | |
256 break; | |
257 case PointsToNode::DeferredEdge: | |
258 add_deferred_edge(ni, n1); | |
259 break; | |
260 case PointsToNode::FieldEdge: | |
261 assert(false, "invalid connection graph"); | |
262 break; | |
263 } | |
264 } | |
265 } | |
266 } | |
267 } | |
268 } | |
269 | |
270 | |
271 // Add an edge to node given by "to_i" from any field of adr_i whose offset | |
272 // matches "offset" A deferred edge is added if to_i is a LocalVar, and | |
273 // a pointsto edge is added if it is a JavaObject | |
274 | |
275 void ConnectionGraph::add_edge_from_fields(uint adr_i, uint to_i, int offs) { | |
276 PointsToNode an = _nodes->at_grow(adr_i); | |
277 PointsToNode to = _nodes->at_grow(to_i); | |
278 bool deferred = (to.node_type() == PointsToNode::LocalVar); | |
279 | |
280 for (uint fe = 0; fe < an.edge_count(); fe++) { | |
281 assert(an.edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); | |
282 int fi = an.edge_target(fe); | |
283 PointsToNode pf = _nodes->at_grow(fi); | |
284 int po = pf.offset(); | |
285 if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { | |
286 if (deferred) | |
287 add_deferred_edge(fi, to_i); | |
288 else | |
289 add_pointsto_edge(fi, to_i); | |
290 } | |
291 } | |
292 } | |
293 | |
294 // Add a deferred edge from node given by "from_i" to any field of adr_i whose offset | |
295 // matches "offset" | |
296 void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) { | |
297 PointsToNode an = _nodes->at_grow(adr_i); | |
298 for (uint fe = 0; fe < an.edge_count(); fe++) { | |
299 assert(an.edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); | |
300 int fi = an.edge_target(fe); | |
301 PointsToNode pf = _nodes->at_grow(fi); | |
302 int po = pf.offset(); | |
303 if (pf.edge_count() == 0) { | |
304 // we have not seen any stores to this field, assume it was set outside this method | |
305 add_pointsto_edge(fi, _phantom_object); | |
306 } | |
307 if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { | |
308 add_deferred_edge(from_i, fi); | |
309 } | |
310 } | |
311 } | |
312 | |
313 // | |
314 // Search memory chain of "mem" to find a MemNode whose address | |
315 // is the specified alias index. Returns the MemNode found or the | |
316 // first non-MemNode encountered. | |
317 // | |
318 Node *ConnectionGraph::find_mem(Node *mem, int alias_idx, PhaseGVN *igvn) { | |
319 if (mem == NULL) | |
320 return mem; | |
321 while (mem->is_Mem()) { | |
322 const Type *at = igvn->type(mem->in(MemNode::Address)); | |
323 if (at != Type::TOP) { | |
324 assert (at->isa_ptr() != NULL, "pointer type required."); | |
325 int idx = _compile->get_alias_index(at->is_ptr()); | |
326 if (idx == alias_idx) | |
327 break; | |
328 } | |
329 mem = mem->in(MemNode::Memory); | |
330 } | |
331 return mem; | |
332 } | |
333 | |
334 // | |
335 // Adjust the type and inputs of an AddP which computes the | |
336 // address of a field of an instance | |
337 // | |
338 void ConnectionGraph::split_AddP(Node *addp, Node *base, PhaseGVN *igvn) { | |
339 const TypeOopPtr *t = igvn->type(addp)->isa_oopptr(); | |
340 const TypeOopPtr *base_t = igvn->type(base)->isa_oopptr(); | |
341 assert(t != NULL, "expecting oopptr"); | |
342 assert(base_t != NULL && base_t->is_instance(), "expecting instance oopptr"); | |
343 uint inst_id = base_t->instance_id(); | |
344 assert(!t->is_instance() || t->instance_id() == inst_id, | |
345 "old type must be non-instance or match new type"); | |
346 const TypeOopPtr *tinst = base_t->add_offset(t->offset())->is_oopptr(); | |
347 // ensure an alias index is allocated for the instance type | |
348 int alias_idx = _compile->get_alias_index(tinst); | |
349 igvn->set_type(addp, tinst); | |
350 // record the allocation in the node map | |
351 set_map(addp->_idx, get_map(base->_idx)); | |
352 // if the Address input is not the appropriate instance type (due to intervening | |
353 // casts,) insert a cast | |
354 Node *adr = addp->in(AddPNode::Address); | |
355 const TypeOopPtr *atype = igvn->type(adr)->isa_oopptr(); | |
356 if (atype->instance_id() != inst_id) { | |
357 assert(!atype->is_instance(), "no conflicting instances"); | |
358 const TypeOopPtr *new_atype = base_t->add_offset(atype->offset())->isa_oopptr(); | |
359 Node *acast = new (_compile, 2) CastPPNode(adr, new_atype); | |
360 acast->set_req(0, adr->in(0)); | |
361 igvn->set_type(acast, new_atype); | |
362 record_for_optimizer(acast); | |
363 Node *bcast = acast; | |
364 Node *abase = addp->in(AddPNode::Base); | |
365 if (abase != adr) { | |
366 bcast = new (_compile, 2) CastPPNode(abase, base_t); | |
367 bcast->set_req(0, abase->in(0)); | |
368 igvn->set_type(bcast, base_t); | |
369 record_for_optimizer(bcast); | |
370 } | |
371 igvn->hash_delete(addp); | |
372 addp->set_req(AddPNode::Base, bcast); | |
373 addp->set_req(AddPNode::Address, acast); | |
374 igvn->hash_insert(addp); | |
375 record_for_optimizer(addp); | |
376 } | |
377 } | |
378 | |
379 // | |
380 // Create a new version of orig_phi if necessary. Returns either the newly | |
381 // created phi or an existing phi. Sets create_new to indicate wheter a new | |
382 // phi was created. Cache the last newly created phi in the node map. | |
383 // | |
384 PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn, bool &new_created) { | |
385 Compile *C = _compile; | |
386 new_created = false; | |
387 int phi_alias_idx = C->get_alias_index(orig_phi->adr_type()); | |
388 // nothing to do if orig_phi is bottom memory or matches alias_idx | |
389 if (phi_alias_idx == Compile::AliasIdxBot || phi_alias_idx == alias_idx) { | |
390 return orig_phi; | |
391 } | |
392 // have we already created a Phi for this alias index? | |
393 PhiNode *result = get_map_phi(orig_phi->_idx); | |
394 const TypePtr *atype = C->get_adr_type(alias_idx); | |
395 if (result != NULL && C->get_alias_index(result->adr_type()) == alias_idx) { | |
396 return result; | |
397 } | |
38
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
398 if ((int)C->unique() + 2*NodeLimitFudgeFactor > MaxNodeLimit) { |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
399 if (C->do_escape_analysis() == true && !C->failing()) { |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
400 // Retry compilation without escape analysis. |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
401 // If this is the first failure, the sentinel string will "stick" |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
402 // to the Compile object, and the C2Compiler will see it and retry. |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
403 C->record_failure(C2Compiler::retry_no_escape_analysis()); |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
404 } |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
405 return NULL; |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
406 } |
0 | 407 |
408 orig_phi_worklist.append_if_missing(orig_phi); | |
409 result = PhiNode::make(orig_phi->in(0), NULL, Type::MEMORY, atype); | |
410 set_map_phi(orig_phi->_idx, result); | |
411 igvn->set_type(result, result->bottom_type()); | |
412 record_for_optimizer(result); | |
413 new_created = true; | |
414 return result; | |
415 } | |
416 | |
417 // | |
418 // Return a new version of Memory Phi "orig_phi" with the inputs having the | |
419 // specified alias index. | |
420 // | |
421 PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn) { | |
422 | |
423 assert(alias_idx != Compile::AliasIdxBot, "can't split out bottom memory"); | |
424 Compile *C = _compile; | |
425 bool new_phi_created; | |
426 PhiNode *result = create_split_phi(orig_phi, alias_idx, orig_phi_worklist, igvn, new_phi_created); | |
427 if (!new_phi_created) { | |
428 return result; | |
429 } | |
430 | |
431 GrowableArray<PhiNode *> phi_list; | |
432 GrowableArray<uint> cur_input; | |
433 | |
434 PhiNode *phi = orig_phi; | |
435 uint idx = 1; | |
436 bool finished = false; | |
437 while(!finished) { | |
438 while (idx < phi->req()) { | |
439 Node *mem = find_mem(phi->in(idx), alias_idx, igvn); | |
440 if (mem != NULL && mem->is_Phi()) { | |
441 PhiNode *nphi = create_split_phi(mem->as_Phi(), alias_idx, orig_phi_worklist, igvn, new_phi_created); | |
442 if (new_phi_created) { | |
443 // found an phi for which we created a new split, push current one on worklist and begin | |
444 // processing new one | |
445 phi_list.push(phi); | |
446 cur_input.push(idx); | |
447 phi = mem->as_Phi(); | |
448 result = nphi; | |
449 idx = 1; | |
450 continue; | |
451 } else { | |
452 mem = nphi; | |
453 } | |
454 } | |
38
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
455 if (C->failing()) { |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
456 return NULL; |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
457 } |
0 | 458 result->set_req(idx++, mem); |
459 } | |
460 #ifdef ASSERT | |
461 // verify that the new Phi has an input for each input of the original | |
462 assert( phi->req() == result->req(), "must have same number of inputs."); | |
463 assert( result->in(0) != NULL && result->in(0) == phi->in(0), "regions must match"); | |
464 for (uint i = 1; i < phi->req(); i++) { | |
465 assert((phi->in(i) == NULL) == (result->in(i) == NULL), "inputs must correspond."); | |
466 } | |
467 #endif | |
468 // we have finished processing a Phi, see if there are any more to do | |
469 finished = (phi_list.length() == 0 ); | |
470 if (!finished) { | |
471 phi = phi_list.pop(); | |
472 idx = cur_input.pop(); | |
473 PhiNode *prev_phi = get_map_phi(phi->_idx); | |
474 prev_phi->set_req(idx++, result); | |
475 result = prev_phi; | |
476 } | |
477 } | |
478 return result; | |
479 } | |
480 | |
481 // | |
482 // Convert the types of unescaped object to instance types where possible, | |
483 // propagate the new type information through the graph, and update memory | |
484 // edges and MergeMem inputs to reflect the new type. | |
485 // | |
486 // We start with allocations (and calls which may be allocations) on alloc_worklist. | |
487 // The processing is done in 4 phases: | |
488 // | |
489 // Phase 1: Process possible allocations from alloc_worklist. Create instance | |
490 // types for the CheckCastPP for allocations where possible. | |
491 // Propagate the the new types through users as follows: | |
492 // casts and Phi: push users on alloc_worklist | |
493 // AddP: cast Base and Address inputs to the instance type | |
494 // push any AddP users on alloc_worklist and push any memnode | |
495 // users onto memnode_worklist. | |
496 // Phase 2: Process MemNode's from memnode_worklist. compute new address type and | |
497 // search the Memory chain for a store with the appropriate type | |
498 // address type. If a Phi is found, create a new version with | |
499 // the approriate memory slices from each of the Phi inputs. | |
500 // For stores, process the users as follows: | |
501 // MemNode: push on memnode_worklist | |
502 // MergeMem: push on mergemem_worklist | |
503 // Phase 3: Process MergeMem nodes from mergemem_worklist. Walk each memory slice | |
504 // moving the first node encountered of each instance type to the | |
505 // the input corresponding to its alias index. | |
506 // appropriate memory slice. | |
507 // Phase 4: Update the inputs of non-instance memory Phis and the Memory input of memnodes. | |
508 // | |
509 // In the following example, the CheckCastPP nodes are the cast of allocation | |
510 // results and the allocation of node 29 is unescaped and eligible to be an | |
511 // instance type. | |
512 // | |
513 // We start with: | |
514 // | |
515 // 7 Parm #memory | |
516 // 10 ConI "12" | |
517 // 19 CheckCastPP "Foo" | |
518 // 20 AddP _ 19 19 10 Foo+12 alias_index=4 | |
519 // 29 CheckCastPP "Foo" | |
520 // 30 AddP _ 29 29 10 Foo+12 alias_index=4 | |
521 // | |
522 // 40 StoreP 25 7 20 ... alias_index=4 | |
523 // 50 StoreP 35 40 30 ... alias_index=4 | |
524 // 60 StoreP 45 50 20 ... alias_index=4 | |
525 // 70 LoadP _ 60 30 ... alias_index=4 | |
526 // 80 Phi 75 50 60 Memory alias_index=4 | |
527 // 90 LoadP _ 80 30 ... alias_index=4 | |
528 // 100 LoadP _ 80 20 ... alias_index=4 | |
529 // | |
530 // | |
531 // Phase 1 creates an instance type for node 29 assigning it an instance id of 24 | |
532 // and creating a new alias index for node 30. This gives: | |
533 // | |
534 // 7 Parm #memory | |
535 // 10 ConI "12" | |
536 // 19 CheckCastPP "Foo" | |
537 // 20 AddP _ 19 19 10 Foo+12 alias_index=4 | |
538 // 29 CheckCastPP "Foo" iid=24 | |
539 // 30 AddP _ 29 29 10 Foo+12 alias_index=6 iid=24 | |
540 // | |
541 // 40 StoreP 25 7 20 ... alias_index=4 | |
542 // 50 StoreP 35 40 30 ... alias_index=6 | |
543 // 60 StoreP 45 50 20 ... alias_index=4 | |
544 // 70 LoadP _ 60 30 ... alias_index=6 | |
545 // 80 Phi 75 50 60 Memory alias_index=4 | |
546 // 90 LoadP _ 80 30 ... alias_index=6 | |
547 // 100 LoadP _ 80 20 ... alias_index=4 | |
548 // | |
549 // In phase 2, new memory inputs are computed for the loads and stores, | |
550 // And a new version of the phi is created. In phase 4, the inputs to | |
551 // node 80 are updated and then the memory nodes are updated with the | |
552 // values computed in phase 2. This results in: | |
553 // | |
554 // 7 Parm #memory | |
555 // 10 ConI "12" | |
556 // 19 CheckCastPP "Foo" | |
557 // 20 AddP _ 19 19 10 Foo+12 alias_index=4 | |
558 // 29 CheckCastPP "Foo" iid=24 | |
559 // 30 AddP _ 29 29 10 Foo+12 alias_index=6 iid=24 | |
560 // | |
561 // 40 StoreP 25 7 20 ... alias_index=4 | |
562 // 50 StoreP 35 7 30 ... alias_index=6 | |
563 // 60 StoreP 45 40 20 ... alias_index=4 | |
564 // 70 LoadP _ 50 30 ... alias_index=6 | |
565 // 80 Phi 75 40 60 Memory alias_index=4 | |
566 // 120 Phi 75 50 50 Memory alias_index=6 | |
567 // 90 LoadP _ 120 30 ... alias_index=6 | |
568 // 100 LoadP _ 80 20 ... alias_index=4 | |
569 // | |
570 void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) { | |
571 GrowableArray<Node *> memnode_worklist; | |
572 GrowableArray<Node *> mergemem_worklist; | |
573 GrowableArray<PhiNode *> orig_phis; | |
574 PhaseGVN *igvn = _compile->initial_gvn(); | |
575 uint new_index_start = (uint) _compile->num_alias_types(); | |
576 VectorSet visited(Thread::current()->resource_area()); | |
577 VectorSet ptset(Thread::current()->resource_area()); | |
578 | |
579 // Phase 1: Process possible allocations from alloc_worklist. Create instance | |
580 // types for the CheckCastPP for allocations where possible. | |
581 while (alloc_worklist.length() != 0) { | |
582 Node *n = alloc_worklist.pop(); | |
583 uint ni = n->_idx; | |
584 if (n->is_Call()) { | |
585 CallNode *alloc = n->as_Call(); | |
586 // copy escape information to call node | |
587 PointsToNode ptn = _nodes->at(alloc->_idx); | |
588 PointsToNode::EscapeState es = escape_state(alloc, igvn); | |
589 alloc->_escape_state = es; | |
590 // find CheckCastPP of call return value | |
591 n = alloc->proj_out(TypeFunc::Parms); | |
592 if (n != NULL && n->outcnt() == 1) { | |
593 n = n->unique_out(); | |
594 if (n->Opcode() != Op_CheckCastPP) { | |
595 continue; | |
596 } | |
597 } else { | |
598 continue; | |
599 } | |
600 // we have an allocation or call which returns a Java object, see if it is unescaped | |
601 if (es != PointsToNode::NoEscape || !ptn._unique_type) { | |
602 continue; // can't make a unique type | |
603 } | |
39
76256d272075
6667612: (Escape Analysis) disable loop cloning if it has a scalar replaceable allocation
kvn
parents:
38
diff
changeset
|
604 if (alloc->is_Allocate()) { |
76256d272075
6667612: (Escape Analysis) disable loop cloning if it has a scalar replaceable allocation
kvn
parents:
38
diff
changeset
|
605 // Set the scalar_replaceable flag before the next check. |
76256d272075
6667612: (Escape Analysis) disable loop cloning if it has a scalar replaceable allocation
kvn
parents:
38
diff
changeset
|
606 alloc->as_Allocate()->_is_scalar_replaceable = true; |
76256d272075
6667612: (Escape Analysis) disable loop cloning if it has a scalar replaceable allocation
kvn
parents:
38
diff
changeset
|
607 } |
76256d272075
6667612: (Escape Analysis) disable loop cloning if it has a scalar replaceable allocation
kvn
parents:
38
diff
changeset
|
608 |
0 | 609 set_map(alloc->_idx, n); |
610 set_map(n->_idx, alloc); | |
611 const TypeInstPtr *t = igvn->type(n)->isa_instptr(); | |
612 // Unique types which are arrays are not currently supported. | |
613 // The check for AllocateArray is needed in case an array | |
614 // allocation is immediately cast to Object | |
615 if (t == NULL || alloc->is_AllocateArray()) | |
616 continue; // not a TypeInstPtr | |
617 const TypeOopPtr *tinst = t->cast_to_instance(ni); | |
618 igvn->hash_delete(n); | |
619 igvn->set_type(n, tinst); | |
620 n->raise_bottom_type(tinst); | |
621 igvn->hash_insert(n); | |
622 } else if (n->is_AddP()) { | |
623 ptset.Clear(); | |
624 PointsTo(ptset, n->in(AddPNode::Address), igvn); | |
625 assert(ptset.Size() == 1, "AddP address is unique"); | |
626 Node *base = get_map(ptset.getelem()); | |
627 split_AddP(n, base, igvn); | |
628 } else if (n->is_Phi() || n->Opcode() == Op_CastPP || n->Opcode() == Op_CheckCastPP) { | |
629 if (visited.test_set(n->_idx)) { | |
630 assert(n->is_Phi(), "loops only through Phi's"); | |
631 continue; // already processed | |
632 } | |
633 ptset.Clear(); | |
634 PointsTo(ptset, n, igvn); | |
635 if (ptset.Size() == 1) { | |
636 TypeNode *tn = n->as_Type(); | |
637 Node *val = get_map(ptset.getelem()); | |
638 const TypeInstPtr *val_t = igvn->type(val)->isa_instptr();; | |
639 assert(val_t != NULL && val_t->is_instance(), "instance type expected."); | |
640 const TypeInstPtr *tn_t = igvn->type(tn)->isa_instptr();; | |
641 | |
642 if (tn_t != NULL && val_t->cast_to_instance(TypeOopPtr::UNKNOWN_INSTANCE)->higher_equal(tn_t)) { | |
643 igvn->hash_delete(tn); | |
644 igvn->set_type(tn, val_t); | |
645 tn->set_type(val_t); | |
646 igvn->hash_insert(tn); | |
647 } | |
648 } | |
649 } else { | |
650 continue; | |
651 } | |
652 // push users on appropriate worklist | |
653 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { | |
654 Node *use = n->fast_out(i); | |
655 if(use->is_Mem() && use->in(MemNode::Address) == n) { | |
656 memnode_worklist.push(use); | |
657 } else if (use->is_AddP() || use->is_Phi() || use->Opcode() == Op_CastPP || use->Opcode() == Op_CheckCastPP) { | |
658 alloc_worklist.push(use); | |
659 } | |
660 } | |
661 | |
662 } | |
663 uint new_index_end = (uint) _compile->num_alias_types(); | |
664 | |
665 // Phase 2: Process MemNode's from memnode_worklist. compute new address type and | |
666 // compute new values for Memory inputs (the Memory inputs are not | |
667 // actually updated until phase 4.) | |
668 if (memnode_worklist.length() == 0) | |
669 return; // nothing to do | |
670 | |
671 | |
672 while (memnode_worklist.length() != 0) { | |
673 Node *n = memnode_worklist.pop(); | |
674 if (n->is_Phi()) { | |
675 assert(n->as_Phi()->adr_type() != TypePtr::BOTTOM, "narrow memory slice required"); | |
676 // we don't need to do anything, but the users must be pushed if we haven't processed | |
677 // this Phi before | |
678 if (visited.test_set(n->_idx)) | |
679 continue; | |
680 } else { | |
681 assert(n->is_Mem(), "memory node required."); | |
682 Node *addr = n->in(MemNode::Address); | |
683 const Type *addr_t = igvn->type(addr); | |
684 if (addr_t == Type::TOP) | |
685 continue; | |
686 assert (addr_t->isa_ptr() != NULL, "pointer type required."); | |
687 int alias_idx = _compile->get_alias_index(addr_t->is_ptr()); | |
688 Node *mem = find_mem(n->in(MemNode::Memory), alias_idx, igvn); | |
689 if (mem->is_Phi()) { | |
690 mem = split_memory_phi(mem->as_Phi(), alias_idx, orig_phis, igvn); | |
691 } | |
38
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
692 if (_compile->failing()) { |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
693 return; |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
694 } |
0 | 695 if (mem != n->in(MemNode::Memory)) |
696 set_map(n->_idx, mem); | |
697 if (n->is_Load()) { | |
698 continue; // don't push users | |
699 } else if (n->is_LoadStore()) { | |
700 // get the memory projection | |
701 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { | |
702 Node *use = n->fast_out(i); | |
703 if (use->Opcode() == Op_SCMemProj) { | |
704 n = use; | |
705 break; | |
706 } | |
707 } | |
708 assert(n->Opcode() == Op_SCMemProj, "memory projection required"); | |
709 } | |
710 } | |
711 // push user on appropriate worklist | |
712 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { | |
713 Node *use = n->fast_out(i); | |
714 if (use->is_Phi()) { | |
715 memnode_worklist.push(use); | |
716 } else if(use->is_Mem() && use->in(MemNode::Memory) == n) { | |
717 memnode_worklist.push(use); | |
718 } else if (use->is_MergeMem()) { | |
719 mergemem_worklist.push(use); | |
720 } | |
721 } | |
722 } | |
723 | |
724 // Phase 3: Process MergeMem nodes from mergemem_worklist. Walk each memory slice | |
725 // moving the first node encountered of each instance type to the | |
726 // the input corresponding to its alias index. | |
727 while (mergemem_worklist.length() != 0) { | |
728 Node *n = mergemem_worklist.pop(); | |
729 assert(n->is_MergeMem(), "MergeMem node required."); | |
730 MergeMemNode *nmm = n->as_MergeMem(); | |
731 // Note: we don't want to use MergeMemStream here because we only want to | |
732 // scan inputs which exist at the start, not ones we add during processing | |
733 uint nslices = nmm->req(); | |
734 igvn->hash_delete(nmm); | |
735 for (uint i = Compile::AliasIdxRaw+1; i < nslices; i++) { | |
736 Node * mem = nmm->in(i); | |
737 Node * cur = NULL; | |
738 if (mem == NULL || mem->is_top()) | |
739 continue; | |
740 while (mem->is_Mem()) { | |
741 const Type *at = igvn->type(mem->in(MemNode::Address)); | |
742 if (at != Type::TOP) { | |
743 assert (at->isa_ptr() != NULL, "pointer type required."); | |
744 uint idx = (uint)_compile->get_alias_index(at->is_ptr()); | |
745 if (idx == i) { | |
746 if (cur == NULL) | |
747 cur = mem; | |
748 } else { | |
749 if (idx >= nmm->req() || nmm->is_empty_memory(nmm->in(idx))) { | |
750 nmm->set_memory_at(idx, mem); | |
751 } | |
752 } | |
753 } | |
754 mem = mem->in(MemNode::Memory); | |
755 } | |
756 nmm->set_memory_at(i, (cur != NULL) ? cur : mem); | |
757 if (mem->is_Phi()) { | |
758 // We have encountered a Phi, we need to split the Phi for | |
759 // any instance of the current type if we haven't encountered | |
760 // a value of the instance along the chain. | |
761 for (uint ni = new_index_start; ni < new_index_end; ni++) { | |
762 if((uint)_compile->get_general_index(ni) == i) { | |
763 Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni); | |
764 if (nmm->is_empty_memory(m)) { | |
38
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
765 m = split_memory_phi(mem->as_Phi(), ni, orig_phis, igvn); |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
766 if (_compile->failing()) { |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
767 return; |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
768 } |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
769 nmm->set_memory_at(ni, m); |
0 | 770 } |
771 } | |
772 } | |
773 } | |
774 } | |
775 igvn->hash_insert(nmm); | |
776 record_for_optimizer(nmm); | |
777 } | |
778 | |
779 // Phase 4: Update the inputs of non-instance memory Phis and the Memory input of memnodes | |
780 // | |
781 // First update the inputs of any non-instance Phi's from | |
782 // which we split out an instance Phi. Note we don't have | |
783 // to recursively process Phi's encounted on the input memory | |
784 // chains as is done in split_memory_phi() since they will | |
785 // also be processed here. | |
786 while (orig_phis.length() != 0) { | |
787 PhiNode *phi = orig_phis.pop(); | |
788 int alias_idx = _compile->get_alias_index(phi->adr_type()); | |
789 igvn->hash_delete(phi); | |
790 for (uint i = 1; i < phi->req(); i++) { | |
791 Node *mem = phi->in(i); | |
792 Node *new_mem = find_mem(mem, alias_idx, igvn); | |
793 if (mem != new_mem) { | |
794 phi->set_req(i, new_mem); | |
795 } | |
796 } | |
797 igvn->hash_insert(phi); | |
798 record_for_optimizer(phi); | |
799 } | |
800 | |
801 // Update the memory inputs of MemNodes with the value we computed | |
802 // in Phase 2. | |
803 for (int i = 0; i < _nodes->length(); i++) { | |
804 Node *nmem = get_map(i); | |
805 if (nmem != NULL) { | |
806 Node *n = _nodes->at(i)._node; | |
807 if (n != NULL && n->is_Mem()) { | |
808 igvn->hash_delete(n); | |
809 n->set_req(MemNode::Memory, nmem); | |
810 igvn->hash_insert(n); | |
811 record_for_optimizer(n); | |
812 } | |
813 } | |
814 } | |
815 } | |
816 | |
817 void ConnectionGraph::compute_escape() { | |
818 GrowableArray<int> worklist; | |
819 GrowableArray<Node *> alloc_worklist; | |
820 VectorSet visited(Thread::current()->resource_area()); | |
821 PhaseGVN *igvn = _compile->initial_gvn(); | |
822 | |
823 // process Phi nodes from the deferred list, they may not have | |
824 while(_deferred.size() > 0) { | |
825 Node * n = _deferred.pop(); | |
826 PhiNode * phi = n->as_Phi(); | |
827 | |
828 process_phi_escape(phi, igvn); | |
829 } | |
830 | |
831 VectorSet ptset(Thread::current()->resource_area()); | |
832 | |
833 // remove deferred edges from the graph and collect | |
834 // information we will need for type splitting | |
835 for (uint ni = 0; ni < (uint)_nodes->length(); ni++) { | |
836 PointsToNode * ptn = _nodes->adr_at(ni); | |
837 PointsToNode::NodeType nt = ptn->node_type(); | |
838 | |
839 if (nt == PointsToNode::UnknownType) { | |
840 continue; // not a node we are interested in | |
841 } | |
842 Node *n = ptn->_node; | |
843 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { | |
844 remove_deferred(ni); | |
845 if (n->is_AddP()) { | |
846 // if this AddP computes an address which may point to more that one | |
847 // object, nothing the address points to can be a unique type. | |
848 Node *base = n->in(AddPNode::Base); | |
849 ptset.Clear(); | |
850 PointsTo(ptset, base, igvn); | |
851 if (ptset.Size() > 1) { | |
852 for( VectorSetI j(&ptset); j.test(); ++j ) { | |
853 PointsToNode *ptaddr = _nodes->adr_at(j.elem); | |
854 ptaddr->_unique_type = false; | |
855 } | |
856 } | |
857 } | |
858 } else if (n->is_Call()) { | |
859 // initialize _escape_state of calls to GlobalEscape | |
860 n->as_Call()->_escape_state = PointsToNode::GlobalEscape; | |
861 // push call on alloc_worlist (alocations are calls) | |
862 // for processing by split_unique_types() | |
863 alloc_worklist.push(n); | |
864 } | |
865 } | |
866 // push all GlobalEscape nodes on the worklist | |
867 for (uint nj = 0; nj < (uint)_nodes->length(); nj++) { | |
868 if (_nodes->at(nj).escape_state() == PointsToNode::GlobalEscape) { | |
869 worklist.append(nj); | |
870 } | |
871 } | |
872 // mark all node reachable from GlobalEscape nodes | |
873 while(worklist.length() > 0) { | |
874 PointsToNode n = _nodes->at(worklist.pop()); | |
875 for (uint ei = 0; ei < n.edge_count(); ei++) { | |
876 uint npi = n.edge_target(ei); | |
877 PointsToNode *np = ptnode_adr(npi); | |
878 if (np->escape_state() != PointsToNode::GlobalEscape) { | |
879 np->set_escape_state(PointsToNode::GlobalEscape); | |
880 worklist.append_if_missing(npi); | |
881 } | |
882 } | |
883 } | |
884 | |
885 // push all ArgEscape nodes on the worklist | |
886 for (uint nk = 0; nk < (uint)_nodes->length(); nk++) { | |
887 if (_nodes->at(nk).escape_state() == PointsToNode::ArgEscape) | |
888 worklist.push(nk); | |
889 } | |
890 // mark all node reachable from ArgEscape nodes | |
891 while(worklist.length() > 0) { | |
892 PointsToNode n = _nodes->at(worklist.pop()); | |
893 | |
894 for (uint ei = 0; ei < n.edge_count(); ei++) { | |
895 uint npi = n.edge_target(ei); | |
896 PointsToNode *np = ptnode_adr(npi); | |
897 if (np->escape_state() != PointsToNode::ArgEscape) { | |
898 np->set_escape_state(PointsToNode::ArgEscape); | |
899 worklist.append_if_missing(npi); | |
900 } | |
901 } | |
902 } | |
903 _collecting = false; | |
904 | |
905 // Now use the escape information to create unique types for | |
906 // unescaped objects | |
907 split_unique_types(alloc_worklist); | |
38
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
908 if (_compile->failing()) return; |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
909 |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
910 // Clean up after split unique types. |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
911 ResourceMark rm; |
b789bcaf2dd9
6667610: (Escape Analysis) retry compilation without EA if it fails
kvn
parents:
0
diff
changeset
|
912 PhaseRemoveUseless pru(_compile->initial_gvn(), _compile->for_igvn()); |
0 | 913 } |
914 | |
915 Node * ConnectionGraph::skip_casts(Node *n) { | |
916 while(n->Opcode() == Op_CastPP || n->Opcode() == Op_CheckCastPP) { | |
917 n = n->in(1); | |
918 } | |
919 return n; | |
920 } | |
921 | |
922 void ConnectionGraph::process_phi_escape(PhiNode *phi, PhaseTransform *phase) { | |
923 | |
924 if (phi->type()->isa_oopptr() == NULL) | |
925 return; // nothing to do if not an oop | |
926 | |
927 PointsToNode *ptadr = ptnode_adr(phi->_idx); | |
928 int incount = phi->req(); | |
929 int non_null_inputs = 0; | |
930 | |
931 for (int i = 1; i < incount ; i++) { | |
932 if (phi->in(i) != NULL) | |
933 non_null_inputs++; | |
934 } | |
935 if (non_null_inputs == ptadr->_inputs_processed) | |
936 return; // no new inputs since the last time this node was processed, | |
937 // the current information is valid | |
938 | |
939 ptadr->_inputs_processed = non_null_inputs; // prevent recursive processing of this node | |
940 for (int j = 1; j < incount ; j++) { | |
941 Node * n = phi->in(j); | |
942 if (n == NULL) | |
943 continue; // ignore NULL | |
944 n = skip_casts(n); | |
945 if (n->is_top() || n == phi) | |
946 continue; // ignore top or inputs which go back this node | |
947 int nopc = n->Opcode(); | |
948 PointsToNode npt = _nodes->at(n->_idx); | |
949 if (_nodes->at(n->_idx).node_type() == PointsToNode::JavaObject) { | |
950 add_pointsto_edge(phi->_idx, n->_idx); | |
951 } else { | |
952 add_deferred_edge(phi->_idx, n->_idx); | |
953 } | |
954 } | |
955 } | |
956 | |
957 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { | |
958 | |
959 _processed.set(call->_idx); | |
960 switch (call->Opcode()) { | |
961 | |
962 // arguments to allocation and locking don't escape | |
963 case Op_Allocate: | |
964 case Op_AllocateArray: | |
965 case Op_Lock: | |
966 case Op_Unlock: | |
967 break; | |
968 | |
969 case Op_CallStaticJava: | |
970 // For a static call, we know exactly what method is being called. | |
971 // Use bytecode estimator to record the call's escape affects | |
972 { | |
973 ciMethod *meth = call->as_CallJava()->method(); | |
974 if (meth != NULL) { | |
975 const TypeTuple * d = call->tf()->domain(); | |
976 BCEscapeAnalyzer call_analyzer(meth); | |
977 VectorSet ptset(Thread::current()->resource_area()); | |
978 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { | |
979 const Type* at = d->field_at(i); | |
980 int k = i - TypeFunc::Parms; | |
981 | |
982 if (at->isa_oopptr() != NULL) { | |
983 Node *arg = skip_casts(call->in(i)); | |
984 | |
985 if (!call_analyzer.is_arg_stack(k)) { | |
986 // The argument global escapes, mark everything it could point to | |
987 ptset.Clear(); | |
988 PointsTo(ptset, arg, phase); | |
989 for( VectorSetI j(&ptset); j.test(); ++j ) { | |
990 uint pt = j.elem; | |
991 | |
992 set_escape_state(pt, PointsToNode::GlobalEscape); | |
993 } | |
994 } else if (!call_analyzer.is_arg_local(k)) { | |
995 // The argument itself doesn't escape, but any fields might | |
996 ptset.Clear(); | |
997 PointsTo(ptset, arg, phase); | |
998 for( VectorSetI j(&ptset); j.test(); ++j ) { | |
999 uint pt = j.elem; | |
1000 add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); | |
1001 } | |
1002 } | |
1003 } | |
1004 } | |
1005 call_analyzer.copy_dependencies(C()->dependencies()); | |
1006 break; | |
1007 } | |
1008 // fall-through if not a Java method | |
1009 } | |
1010 | |
1011 default: | |
1012 // Some other type of call, assume the worst case: all arguments | |
1013 // globally escape. | |
1014 { | |
1015 // adjust escape state for outgoing arguments | |
1016 const TypeTuple * d = call->tf()->domain(); | |
1017 VectorSet ptset(Thread::current()->resource_area()); | |
1018 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { | |
1019 const Type* at = d->field_at(i); | |
1020 | |
1021 if (at->isa_oopptr() != NULL) { | |
1022 Node *arg = skip_casts(call->in(i)); | |
1023 ptset.Clear(); | |
1024 PointsTo(ptset, arg, phase); | |
1025 for( VectorSetI j(&ptset); j.test(); ++j ) { | |
1026 uint pt = j.elem; | |
1027 | |
1028 set_escape_state(pt, PointsToNode::GlobalEscape); | |
1029 } | |
1030 } | |
1031 } | |
1032 } | |
1033 } | |
1034 } | |
1035 void ConnectionGraph::process_call_result(ProjNode *resproj, PhaseTransform *phase) { | |
1036 CallNode *call = resproj->in(0)->as_Call(); | |
1037 | |
1038 PointsToNode *ptadr = ptnode_adr(resproj->_idx); | |
1039 | |
1040 ptadr->_node = resproj; | |
1041 ptadr->set_node_type(PointsToNode::LocalVar); | |
1042 set_escape_state(resproj->_idx, PointsToNode::UnknownEscape); | |
1043 _processed.set(resproj->_idx); | |
1044 | |
1045 switch (call->Opcode()) { | |
1046 case Op_Allocate: | |
1047 { | |
1048 Node *k = call->in(AllocateNode::KlassNode); | |
1049 const TypeKlassPtr *kt; | |
1050 if (k->Opcode() == Op_LoadKlass) { | |
1051 kt = k->as_Load()->type()->isa_klassptr(); | |
1052 } else { | |
1053 kt = k->as_Type()->type()->isa_klassptr(); | |
1054 } | |
1055 assert(kt != NULL, "TypeKlassPtr required."); | |
1056 ciKlass* cik = kt->klass(); | |
1057 ciInstanceKlass* ciik = cik->as_instance_klass(); | |
1058 | |
1059 PointsToNode *ptadr = ptnode_adr(call->_idx); | |
1060 ptadr->set_node_type(PointsToNode::JavaObject); | |
1061 if (cik->is_subclass_of(_compile->env()->Thread_klass()) || ciik->has_finalizer()) { | |
1062 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | |
1063 add_pointsto_edge(resproj->_idx, _phantom_object); | |
1064 } else { | |
1065 set_escape_state(call->_idx, PointsToNode::NoEscape); | |
1066 add_pointsto_edge(resproj->_idx, call->_idx); | |
1067 } | |
1068 _processed.set(call->_idx); | |
1069 break; | |
1070 } | |
1071 | |
1072 case Op_AllocateArray: | |
1073 { | |
1074 PointsToNode *ptadr = ptnode_adr(call->_idx); | |
1075 ptadr->set_node_type(PointsToNode::JavaObject); | |
1076 set_escape_state(call->_idx, PointsToNode::NoEscape); | |
1077 _processed.set(call->_idx); | |
1078 add_pointsto_edge(resproj->_idx, call->_idx); | |
1079 break; | |
1080 } | |
1081 | |
1082 case Op_Lock: | |
1083 case Op_Unlock: | |
1084 break; | |
1085 | |
1086 case Op_CallStaticJava: | |
1087 // For a static call, we know exactly what method is being called. | |
1088 // Use bytecode estimator to record whether the call's return value escapes | |
1089 { | |
1090 const TypeTuple *r = call->tf()->range(); | |
1091 const Type* ret_type = NULL; | |
1092 | |
1093 if (r->cnt() > TypeFunc::Parms) | |
1094 ret_type = r->field_at(TypeFunc::Parms); | |
1095 | |
1096 // Note: we use isa_ptr() instead of isa_oopptr() here because the | |
1097 // _multianewarray functions return a TypeRawPtr. | |
1098 if (ret_type == NULL || ret_type->isa_ptr() == NULL) | |
1099 break; // doesn't return a pointer type | |
1100 | |
1101 ciMethod *meth = call->as_CallJava()->method(); | |
1102 if (meth == NULL) { | |
1103 // not a Java method, assume global escape | |
1104 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | |
1105 if (resproj != NULL) | |
1106 add_pointsto_edge(resproj->_idx, _phantom_object); | |
1107 } else { | |
1108 BCEscapeAnalyzer call_analyzer(meth); | |
1109 VectorSet ptset(Thread::current()->resource_area()); | |
1110 | |
1111 if (call_analyzer.is_return_local() && resproj != NULL) { | |
1112 // determine whether any arguments are returned | |
1113 const TypeTuple * d = call->tf()->domain(); | |
1114 set_escape_state(call->_idx, PointsToNode::NoEscape); | |
1115 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { | |
1116 const Type* at = d->field_at(i); | |
1117 | |
1118 if (at->isa_oopptr() != NULL) { | |
1119 Node *arg = skip_casts(call->in(i)); | |
1120 | |
1121 if (call_analyzer.is_arg_returned(i - TypeFunc::Parms)) { | |
1122 PointsToNode *arg_esp = _nodes->adr_at(arg->_idx); | |
1123 if (arg_esp->node_type() == PointsToNode::JavaObject) | |
1124 add_pointsto_edge(resproj->_idx, arg->_idx); | |
1125 else | |
1126 add_deferred_edge(resproj->_idx, arg->_idx); | |
1127 arg_esp->_hidden_alias = true; | |
1128 } | |
1129 } | |
1130 } | |
1131 } else { | |
1132 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | |
1133 if (resproj != NULL) | |
1134 add_pointsto_edge(resproj->_idx, _phantom_object); | |
1135 } | |
1136 call_analyzer.copy_dependencies(C()->dependencies()); | |
1137 } | |
1138 break; | |
1139 } | |
1140 | |
1141 default: | |
1142 // Some other type of call, assume the worst case that the | |
1143 // returned value, if any, globally escapes. | |
1144 { | |
1145 const TypeTuple *r = call->tf()->range(); | |
1146 | |
1147 if (r->cnt() > TypeFunc::Parms) { | |
1148 const Type* ret_type = r->field_at(TypeFunc::Parms); | |
1149 | |
1150 // Note: we use isa_ptr() instead of isa_oopptr() here because the | |
1151 // _multianewarray functions return a TypeRawPtr. | |
1152 if (ret_type->isa_ptr() != NULL) { | |
1153 PointsToNode *ptadr = ptnode_adr(call->_idx); | |
1154 ptadr->set_node_type(PointsToNode::JavaObject); | |
1155 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | |
1156 if (resproj != NULL) | |
1157 add_pointsto_edge(resproj->_idx, _phantom_object); | |
1158 } | |
1159 } | |
1160 } | |
1161 } | |
1162 } | |
1163 | |
1164 void ConnectionGraph::record_for_escape_analysis(Node *n) { | |
1165 if (_collecting) { | |
1166 if (n->is_Phi()) { | |
1167 PhiNode *phi = n->as_Phi(); | |
1168 const Type *pt = phi->type(); | |
1169 if ((pt->isa_oopptr() != NULL) || pt == TypePtr::NULL_PTR) { | |
1170 PointsToNode *ptn = ptnode_adr(phi->_idx); | |
1171 ptn->set_node_type(PointsToNode::LocalVar); | |
1172 ptn->_node = n; | |
1173 _deferred.push(n); | |
1174 } | |
1175 } | |
1176 } | |
1177 } | |
1178 | |
1179 void ConnectionGraph::record_escape_work(Node *n, PhaseTransform *phase) { | |
1180 | |
1181 int opc = n->Opcode(); | |
1182 PointsToNode *ptadr = ptnode_adr(n->_idx); | |
1183 | |
1184 if (_processed.test(n->_idx)) | |
1185 return; | |
1186 | |
1187 ptadr->_node = n; | |
1188 if (n->is_Call()) { | |
1189 CallNode *call = n->as_Call(); | |
1190 process_call_arguments(call, phase); | |
1191 return; | |
1192 } | |
1193 | |
1194 switch (opc) { | |
1195 case Op_AddP: | |
1196 { | |
1197 Node *base = skip_casts(n->in(AddPNode::Base)); | |
1198 ptadr->set_node_type(PointsToNode::Field); | |
1199 | |
1200 // create a field edge to this node from everything adr could point to | |
1201 VectorSet ptset(Thread::current()->resource_area()); | |
1202 PointsTo(ptset, base, phase); | |
1203 for( VectorSetI i(&ptset); i.test(); ++i ) { | |
1204 uint pt = i.elem; | |
1205 add_field_edge(pt, n->_idx, type_to_offset(phase->type(n))); | |
1206 } | |
1207 break; | |
1208 } | |
1209 case Op_Parm: | |
1210 { | |
1211 ProjNode *nproj = n->as_Proj(); | |
1212 uint con = nproj->_con; | |
1213 if (con < TypeFunc::Parms) | |
1214 return; | |
1215 const Type *t = nproj->in(0)->as_Start()->_domain->field_at(con); | |
1216 if (t->isa_ptr() == NULL) | |
1217 return; | |
1218 ptadr->set_node_type(PointsToNode::JavaObject); | |
1219 if (t->isa_oopptr() != NULL) { | |
1220 set_escape_state(n->_idx, PointsToNode::ArgEscape); | |
1221 } else { | |
1222 // this must be the incoming state of an OSR compile, we have to assume anything | |
1223 // passed in globally escapes | |
1224 assert(_compile->is_osr_compilation(), "bad argument type for non-osr compilation"); | |
1225 set_escape_state(n->_idx, PointsToNode::GlobalEscape); | |
1226 } | |
1227 _processed.set(n->_idx); | |
1228 break; | |
1229 } | |
1230 case Op_Phi: | |
1231 { | |
1232 PhiNode *phi = n->as_Phi(); | |
1233 if (phi->type()->isa_oopptr() == NULL) | |
1234 return; // nothing to do if not an oop | |
1235 ptadr->set_node_type(PointsToNode::LocalVar); | |
1236 process_phi_escape(phi, phase); | |
1237 break; | |
1238 } | |
1239 case Op_CreateEx: | |
1240 { | |
1241 // assume that all exception objects globally escape | |
1242 ptadr->set_node_type(PointsToNode::JavaObject); | |
1243 set_escape_state(n->_idx, PointsToNode::GlobalEscape); | |
1244 _processed.set(n->_idx); | |
1245 break; | |
1246 } | |
1247 case Op_ConP: | |
1248 { | |
1249 const Type *t = phase->type(n); | |
1250 ptadr->set_node_type(PointsToNode::JavaObject); | |
1251 // assume all pointer constants globally escape except for null | |
1252 if (t == TypePtr::NULL_PTR) | |
1253 set_escape_state(n->_idx, PointsToNode::NoEscape); | |
1254 else | |
1255 set_escape_state(n->_idx, PointsToNode::GlobalEscape); | |
1256 _processed.set(n->_idx); | |
1257 break; | |
1258 } | |
1259 case Op_LoadKlass: | |
1260 { | |
1261 ptadr->set_node_type(PointsToNode::JavaObject); | |
1262 set_escape_state(n->_idx, PointsToNode::GlobalEscape); | |
1263 _processed.set(n->_idx); | |
1264 break; | |
1265 } | |
1266 case Op_LoadP: | |
1267 { | |
1268 const Type *t = phase->type(n); | |
1269 if (!t->isa_oopptr()) | |
1270 return; | |
1271 ptadr->set_node_type(PointsToNode::LocalVar); | |
1272 set_escape_state(n->_idx, PointsToNode::UnknownEscape); | |
1273 | |
1274 Node *adr = skip_casts(n->in(MemNode::Address)); | |
1275 const Type *adr_type = phase->type(adr); | |
1276 Node *adr_base = skip_casts((adr->Opcode() == Op_AddP) ? adr->in(AddPNode::Base) : adr); | |
1277 | |
1278 // For everything "adr" could point to, create a deferred edge from | |
1279 // this node to each field with the same offset as "adr_type" | |
1280 VectorSet ptset(Thread::current()->resource_area()); | |
1281 PointsTo(ptset, adr_base, phase); | |
1282 // If ptset is empty, then this value must have been set outside | |
1283 // this method, so we add the phantom node | |
1284 if (ptset.Size() == 0) | |
1285 ptset.set(_phantom_object); | |
1286 for( VectorSetI i(&ptset); i.test(); ++i ) { | |
1287 uint pt = i.elem; | |
1288 add_deferred_edge_to_fields(n->_idx, pt, type_to_offset(adr_type)); | |
1289 } | |
1290 break; | |
1291 } | |
1292 case Op_StoreP: | |
1293 case Op_StorePConditional: | |
1294 case Op_CompareAndSwapP: | |
1295 { | |
1296 Node *adr = n->in(MemNode::Address); | |
1297 Node *val = skip_casts(n->in(MemNode::ValueIn)); | |
1298 const Type *adr_type = phase->type(adr); | |
1299 if (!adr_type->isa_oopptr()) | |
1300 return; | |
1301 | |
1302 assert(adr->Opcode() == Op_AddP, "expecting an AddP"); | |
1303 Node *adr_base = adr->in(AddPNode::Base); | |
1304 | |
1305 // For everything "adr_base" could point to, create a deferred edge to "val" from each field | |
1306 // with the same offset as "adr_type" | |
1307 VectorSet ptset(Thread::current()->resource_area()); | |
1308 PointsTo(ptset, adr_base, phase); | |
1309 for( VectorSetI i(&ptset); i.test(); ++i ) { | |
1310 uint pt = i.elem; | |
1311 add_edge_from_fields(pt, val->_idx, type_to_offset(adr_type)); | |
1312 } | |
1313 break; | |
1314 } | |
1315 case Op_Proj: | |
1316 { | |
1317 ProjNode *nproj = n->as_Proj(); | |
1318 Node *n0 = nproj->in(0); | |
1319 // we are only interested in the result projection from a call | |
1320 if (nproj->_con == TypeFunc::Parms && n0->is_Call() ) { | |
1321 process_call_result(nproj, phase); | |
1322 } | |
1323 | |
1324 break; | |
1325 } | |
1326 case Op_CastPP: | |
1327 case Op_CheckCastPP: | |
1328 { | |
1329 ptadr->set_node_type(PointsToNode::LocalVar); | |
1330 int ti = n->in(1)->_idx; | |
1331 if (_nodes->at(ti).node_type() == PointsToNode::JavaObject) { | |
1332 add_pointsto_edge(n->_idx, ti); | |
1333 } else { | |
1334 add_deferred_edge(n->_idx, ti); | |
1335 } | |
1336 break; | |
1337 } | |
1338 default: | |
1339 ; | |
1340 // nothing to do | |
1341 } | |
1342 } | |
1343 | |
1344 void ConnectionGraph::record_escape(Node *n, PhaseTransform *phase) { | |
1345 if (_collecting) | |
1346 record_escape_work(n, phase); | |
1347 } | |
1348 | |
1349 #ifndef PRODUCT | |
1350 void ConnectionGraph::dump() { | |
1351 PhaseGVN *igvn = _compile->initial_gvn(); | |
1352 bool first = true; | |
1353 | |
1354 for (uint ni = 0; ni < (uint)_nodes->length(); ni++) { | |
1355 PointsToNode *esp = _nodes->adr_at(ni); | |
1356 if (esp->node_type() == PointsToNode::UnknownType || esp->_node == NULL) | |
1357 continue; | |
1358 PointsToNode::EscapeState es = escape_state(esp->_node, igvn); | |
1359 if (es == PointsToNode::NoEscape || (Verbose && | |
1360 (es != PointsToNode::UnknownEscape || esp->edge_count() != 0))) { | |
1361 // don't print null pointer node which almost every method has | |
1362 if (esp->_node->Opcode() != Op_ConP || igvn->type(esp->_node) != TypePtr::NULL_PTR) { | |
1363 if (first) { | |
1364 tty->print("======== Connection graph for "); | |
1365 C()->method()->print_short_name(); | |
1366 tty->cr(); | |
1367 first = false; | |
1368 } | |
1369 tty->print("%4d ", ni); | |
1370 esp->dump(); | |
1371 } | |
1372 } | |
1373 } | |
1374 } | |
1375 #endif |