Mercurial > hg > graal-compiler
comparison src/share/vm/opto/escape.cpp @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | b789bcaf2dd9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a61af66fc99e |
---|---|
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 } | |
398 | |
399 orig_phi_worklist.append_if_missing(orig_phi); | |
400 result = PhiNode::make(orig_phi->in(0), NULL, Type::MEMORY, atype); | |
401 set_map_phi(orig_phi->_idx, result); | |
402 igvn->set_type(result, result->bottom_type()); | |
403 record_for_optimizer(result); | |
404 new_created = true; | |
405 return result; | |
406 } | |
407 | |
408 // | |
409 // Return a new version of Memory Phi "orig_phi" with the inputs having the | |
410 // specified alias index. | |
411 // | |
412 PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn) { | |
413 | |
414 assert(alias_idx != Compile::AliasIdxBot, "can't split out bottom memory"); | |
415 Compile *C = _compile; | |
416 bool new_phi_created; | |
417 PhiNode *result = create_split_phi(orig_phi, alias_idx, orig_phi_worklist, igvn, new_phi_created); | |
418 if (!new_phi_created) { | |
419 return result; | |
420 } | |
421 | |
422 GrowableArray<PhiNode *> phi_list; | |
423 GrowableArray<uint> cur_input; | |
424 | |
425 PhiNode *phi = orig_phi; | |
426 uint idx = 1; | |
427 bool finished = false; | |
428 while(!finished) { | |
429 while (idx < phi->req()) { | |
430 Node *mem = find_mem(phi->in(idx), alias_idx, igvn); | |
431 if (mem != NULL && mem->is_Phi()) { | |
432 PhiNode *nphi = create_split_phi(mem->as_Phi(), alias_idx, orig_phi_worklist, igvn, new_phi_created); | |
433 if (new_phi_created) { | |
434 // found an phi for which we created a new split, push current one on worklist and begin | |
435 // processing new one | |
436 phi_list.push(phi); | |
437 cur_input.push(idx); | |
438 phi = mem->as_Phi(); | |
439 result = nphi; | |
440 idx = 1; | |
441 continue; | |
442 } else { | |
443 mem = nphi; | |
444 } | |
445 } | |
446 result->set_req(idx++, mem); | |
447 } | |
448 #ifdef ASSERT | |
449 // verify that the new Phi has an input for each input of the original | |
450 assert( phi->req() == result->req(), "must have same number of inputs."); | |
451 assert( result->in(0) != NULL && result->in(0) == phi->in(0), "regions must match"); | |
452 for (uint i = 1; i < phi->req(); i++) { | |
453 assert((phi->in(i) == NULL) == (result->in(i) == NULL), "inputs must correspond."); | |
454 } | |
455 #endif | |
456 // we have finished processing a Phi, see if there are any more to do | |
457 finished = (phi_list.length() == 0 ); | |
458 if (!finished) { | |
459 phi = phi_list.pop(); | |
460 idx = cur_input.pop(); | |
461 PhiNode *prev_phi = get_map_phi(phi->_idx); | |
462 prev_phi->set_req(idx++, result); | |
463 result = prev_phi; | |
464 } | |
465 } | |
466 return result; | |
467 } | |
468 | |
469 // | |
470 // Convert the types of unescaped object to instance types where possible, | |
471 // propagate the new type information through the graph, and update memory | |
472 // edges and MergeMem inputs to reflect the new type. | |
473 // | |
474 // We start with allocations (and calls which may be allocations) on alloc_worklist. | |
475 // The processing is done in 4 phases: | |
476 // | |
477 // Phase 1: Process possible allocations from alloc_worklist. Create instance | |
478 // types for the CheckCastPP for allocations where possible. | |
479 // Propagate the the new types through users as follows: | |
480 // casts and Phi: push users on alloc_worklist | |
481 // AddP: cast Base and Address inputs to the instance type | |
482 // push any AddP users on alloc_worklist and push any memnode | |
483 // users onto memnode_worklist. | |
484 // Phase 2: Process MemNode's from memnode_worklist. compute new address type and | |
485 // search the Memory chain for a store with the appropriate type | |
486 // address type. If a Phi is found, create a new version with | |
487 // the approriate memory slices from each of the Phi inputs. | |
488 // For stores, process the users as follows: | |
489 // MemNode: push on memnode_worklist | |
490 // MergeMem: push on mergemem_worklist | |
491 // Phase 3: Process MergeMem nodes from mergemem_worklist. Walk each memory slice | |
492 // moving the first node encountered of each instance type to the | |
493 // the input corresponding to its alias index. | |
494 // appropriate memory slice. | |
495 // Phase 4: Update the inputs of non-instance memory Phis and the Memory input of memnodes. | |
496 // | |
497 // In the following example, the CheckCastPP nodes are the cast of allocation | |
498 // results and the allocation of node 29 is unescaped and eligible to be an | |
499 // instance type. | |
500 // | |
501 // We start with: | |
502 // | |
503 // 7 Parm #memory | |
504 // 10 ConI "12" | |
505 // 19 CheckCastPP "Foo" | |
506 // 20 AddP _ 19 19 10 Foo+12 alias_index=4 | |
507 // 29 CheckCastPP "Foo" | |
508 // 30 AddP _ 29 29 10 Foo+12 alias_index=4 | |
509 // | |
510 // 40 StoreP 25 7 20 ... alias_index=4 | |
511 // 50 StoreP 35 40 30 ... alias_index=4 | |
512 // 60 StoreP 45 50 20 ... alias_index=4 | |
513 // 70 LoadP _ 60 30 ... alias_index=4 | |
514 // 80 Phi 75 50 60 Memory alias_index=4 | |
515 // 90 LoadP _ 80 30 ... alias_index=4 | |
516 // 100 LoadP _ 80 20 ... alias_index=4 | |
517 // | |
518 // | |
519 // Phase 1 creates an instance type for node 29 assigning it an instance id of 24 | |
520 // and creating a new alias index for node 30. This gives: | |
521 // | |
522 // 7 Parm #memory | |
523 // 10 ConI "12" | |
524 // 19 CheckCastPP "Foo" | |
525 // 20 AddP _ 19 19 10 Foo+12 alias_index=4 | |
526 // 29 CheckCastPP "Foo" iid=24 | |
527 // 30 AddP _ 29 29 10 Foo+12 alias_index=6 iid=24 | |
528 // | |
529 // 40 StoreP 25 7 20 ... alias_index=4 | |
530 // 50 StoreP 35 40 30 ... alias_index=6 | |
531 // 60 StoreP 45 50 20 ... alias_index=4 | |
532 // 70 LoadP _ 60 30 ... alias_index=6 | |
533 // 80 Phi 75 50 60 Memory alias_index=4 | |
534 // 90 LoadP _ 80 30 ... alias_index=6 | |
535 // 100 LoadP _ 80 20 ... alias_index=4 | |
536 // | |
537 // In phase 2, new memory inputs are computed for the loads and stores, | |
538 // And a new version of the phi is created. In phase 4, the inputs to | |
539 // node 80 are updated and then the memory nodes are updated with the | |
540 // values computed in phase 2. This results in: | |
541 // | |
542 // 7 Parm #memory | |
543 // 10 ConI "12" | |
544 // 19 CheckCastPP "Foo" | |
545 // 20 AddP _ 19 19 10 Foo+12 alias_index=4 | |
546 // 29 CheckCastPP "Foo" iid=24 | |
547 // 30 AddP _ 29 29 10 Foo+12 alias_index=6 iid=24 | |
548 // | |
549 // 40 StoreP 25 7 20 ... alias_index=4 | |
550 // 50 StoreP 35 7 30 ... alias_index=6 | |
551 // 60 StoreP 45 40 20 ... alias_index=4 | |
552 // 70 LoadP _ 50 30 ... alias_index=6 | |
553 // 80 Phi 75 40 60 Memory alias_index=4 | |
554 // 120 Phi 75 50 50 Memory alias_index=6 | |
555 // 90 LoadP _ 120 30 ... alias_index=6 | |
556 // 100 LoadP _ 80 20 ... alias_index=4 | |
557 // | |
558 void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) { | |
559 GrowableArray<Node *> memnode_worklist; | |
560 GrowableArray<Node *> mergemem_worklist; | |
561 GrowableArray<PhiNode *> orig_phis; | |
562 PhaseGVN *igvn = _compile->initial_gvn(); | |
563 uint new_index_start = (uint) _compile->num_alias_types(); | |
564 VectorSet visited(Thread::current()->resource_area()); | |
565 VectorSet ptset(Thread::current()->resource_area()); | |
566 | |
567 // Phase 1: Process possible allocations from alloc_worklist. Create instance | |
568 // types for the CheckCastPP for allocations where possible. | |
569 while (alloc_worklist.length() != 0) { | |
570 Node *n = alloc_worklist.pop(); | |
571 uint ni = n->_idx; | |
572 if (n->is_Call()) { | |
573 CallNode *alloc = n->as_Call(); | |
574 // copy escape information to call node | |
575 PointsToNode ptn = _nodes->at(alloc->_idx); | |
576 PointsToNode::EscapeState es = escape_state(alloc, igvn); | |
577 alloc->_escape_state = es; | |
578 // find CheckCastPP of call return value | |
579 n = alloc->proj_out(TypeFunc::Parms); | |
580 if (n != NULL && n->outcnt() == 1) { | |
581 n = n->unique_out(); | |
582 if (n->Opcode() != Op_CheckCastPP) { | |
583 continue; | |
584 } | |
585 } else { | |
586 continue; | |
587 } | |
588 // we have an allocation or call which returns a Java object, see if it is unescaped | |
589 if (es != PointsToNode::NoEscape || !ptn._unique_type) { | |
590 continue; // can't make a unique type | |
591 } | |
592 set_map(alloc->_idx, n); | |
593 set_map(n->_idx, alloc); | |
594 const TypeInstPtr *t = igvn->type(n)->isa_instptr(); | |
595 // Unique types which are arrays are not currently supported. | |
596 // The check for AllocateArray is needed in case an array | |
597 // allocation is immediately cast to Object | |
598 if (t == NULL || alloc->is_AllocateArray()) | |
599 continue; // not a TypeInstPtr | |
600 const TypeOopPtr *tinst = t->cast_to_instance(ni); | |
601 igvn->hash_delete(n); | |
602 igvn->set_type(n, tinst); | |
603 n->raise_bottom_type(tinst); | |
604 igvn->hash_insert(n); | |
605 } else if (n->is_AddP()) { | |
606 ptset.Clear(); | |
607 PointsTo(ptset, n->in(AddPNode::Address), igvn); | |
608 assert(ptset.Size() == 1, "AddP address is unique"); | |
609 Node *base = get_map(ptset.getelem()); | |
610 split_AddP(n, base, igvn); | |
611 } else if (n->is_Phi() || n->Opcode() == Op_CastPP || n->Opcode() == Op_CheckCastPP) { | |
612 if (visited.test_set(n->_idx)) { | |
613 assert(n->is_Phi(), "loops only through Phi's"); | |
614 continue; // already processed | |
615 } | |
616 ptset.Clear(); | |
617 PointsTo(ptset, n, igvn); | |
618 if (ptset.Size() == 1) { | |
619 TypeNode *tn = n->as_Type(); | |
620 Node *val = get_map(ptset.getelem()); | |
621 const TypeInstPtr *val_t = igvn->type(val)->isa_instptr();; | |
622 assert(val_t != NULL && val_t->is_instance(), "instance type expected."); | |
623 const TypeInstPtr *tn_t = igvn->type(tn)->isa_instptr();; | |
624 | |
625 if (tn_t != NULL && val_t->cast_to_instance(TypeOopPtr::UNKNOWN_INSTANCE)->higher_equal(tn_t)) { | |
626 igvn->hash_delete(tn); | |
627 igvn->set_type(tn, val_t); | |
628 tn->set_type(val_t); | |
629 igvn->hash_insert(tn); | |
630 } | |
631 } | |
632 } else { | |
633 continue; | |
634 } | |
635 // push users on appropriate worklist | |
636 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { | |
637 Node *use = n->fast_out(i); | |
638 if(use->is_Mem() && use->in(MemNode::Address) == n) { | |
639 memnode_worklist.push(use); | |
640 } else if (use->is_AddP() || use->is_Phi() || use->Opcode() == Op_CastPP || use->Opcode() == Op_CheckCastPP) { | |
641 alloc_worklist.push(use); | |
642 } | |
643 } | |
644 | |
645 } | |
646 uint new_index_end = (uint) _compile->num_alias_types(); | |
647 | |
648 // Phase 2: Process MemNode's from memnode_worklist. compute new address type and | |
649 // compute new values for Memory inputs (the Memory inputs are not | |
650 // actually updated until phase 4.) | |
651 if (memnode_worklist.length() == 0) | |
652 return; // nothing to do | |
653 | |
654 | |
655 while (memnode_worklist.length() != 0) { | |
656 Node *n = memnode_worklist.pop(); | |
657 if (n->is_Phi()) { | |
658 assert(n->as_Phi()->adr_type() != TypePtr::BOTTOM, "narrow memory slice required"); | |
659 // we don't need to do anything, but the users must be pushed if we haven't processed | |
660 // this Phi before | |
661 if (visited.test_set(n->_idx)) | |
662 continue; | |
663 } else { | |
664 assert(n->is_Mem(), "memory node required."); | |
665 Node *addr = n->in(MemNode::Address); | |
666 const Type *addr_t = igvn->type(addr); | |
667 if (addr_t == Type::TOP) | |
668 continue; | |
669 assert (addr_t->isa_ptr() != NULL, "pointer type required."); | |
670 int alias_idx = _compile->get_alias_index(addr_t->is_ptr()); | |
671 Node *mem = find_mem(n->in(MemNode::Memory), alias_idx, igvn); | |
672 if (mem->is_Phi()) { | |
673 mem = split_memory_phi(mem->as_Phi(), alias_idx, orig_phis, igvn); | |
674 } | |
675 if (mem != n->in(MemNode::Memory)) | |
676 set_map(n->_idx, mem); | |
677 if (n->is_Load()) { | |
678 continue; // don't push users | |
679 } else if (n->is_LoadStore()) { | |
680 // get the memory projection | |
681 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { | |
682 Node *use = n->fast_out(i); | |
683 if (use->Opcode() == Op_SCMemProj) { | |
684 n = use; | |
685 break; | |
686 } | |
687 } | |
688 assert(n->Opcode() == Op_SCMemProj, "memory projection required"); | |
689 } | |
690 } | |
691 // push user on appropriate worklist | |
692 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { | |
693 Node *use = n->fast_out(i); | |
694 if (use->is_Phi()) { | |
695 memnode_worklist.push(use); | |
696 } else if(use->is_Mem() && use->in(MemNode::Memory) == n) { | |
697 memnode_worklist.push(use); | |
698 } else if (use->is_MergeMem()) { | |
699 mergemem_worklist.push(use); | |
700 } | |
701 } | |
702 } | |
703 | |
704 // Phase 3: Process MergeMem nodes from mergemem_worklist. Walk each memory slice | |
705 // moving the first node encountered of each instance type to the | |
706 // the input corresponding to its alias index. | |
707 while (mergemem_worklist.length() != 0) { | |
708 Node *n = mergemem_worklist.pop(); | |
709 assert(n->is_MergeMem(), "MergeMem node required."); | |
710 MergeMemNode *nmm = n->as_MergeMem(); | |
711 // Note: we don't want to use MergeMemStream here because we only want to | |
712 // scan inputs which exist at the start, not ones we add during processing | |
713 uint nslices = nmm->req(); | |
714 igvn->hash_delete(nmm); | |
715 for (uint i = Compile::AliasIdxRaw+1; i < nslices; i++) { | |
716 Node * mem = nmm->in(i); | |
717 Node * cur = NULL; | |
718 if (mem == NULL || mem->is_top()) | |
719 continue; | |
720 while (mem->is_Mem()) { | |
721 const Type *at = igvn->type(mem->in(MemNode::Address)); | |
722 if (at != Type::TOP) { | |
723 assert (at->isa_ptr() != NULL, "pointer type required."); | |
724 uint idx = (uint)_compile->get_alias_index(at->is_ptr()); | |
725 if (idx == i) { | |
726 if (cur == NULL) | |
727 cur = mem; | |
728 } else { | |
729 if (idx >= nmm->req() || nmm->is_empty_memory(nmm->in(idx))) { | |
730 nmm->set_memory_at(idx, mem); | |
731 } | |
732 } | |
733 } | |
734 mem = mem->in(MemNode::Memory); | |
735 } | |
736 nmm->set_memory_at(i, (cur != NULL) ? cur : mem); | |
737 if (mem->is_Phi()) { | |
738 // We have encountered a Phi, we need to split the Phi for | |
739 // any instance of the current type if we haven't encountered | |
740 // a value of the instance along the chain. | |
741 for (uint ni = new_index_start; ni < new_index_end; ni++) { | |
742 if((uint)_compile->get_general_index(ni) == i) { | |
743 Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni); | |
744 if (nmm->is_empty_memory(m)) { | |
745 nmm->set_memory_at(ni, split_memory_phi(mem->as_Phi(), ni, orig_phis, igvn)); | |
746 } | |
747 } | |
748 } | |
749 } | |
750 } | |
751 igvn->hash_insert(nmm); | |
752 record_for_optimizer(nmm); | |
753 } | |
754 | |
755 // Phase 4: Update the inputs of non-instance memory Phis and the Memory input of memnodes | |
756 // | |
757 // First update the inputs of any non-instance Phi's from | |
758 // which we split out an instance Phi. Note we don't have | |
759 // to recursively process Phi's encounted on the input memory | |
760 // chains as is done in split_memory_phi() since they will | |
761 // also be processed here. | |
762 while (orig_phis.length() != 0) { | |
763 PhiNode *phi = orig_phis.pop(); | |
764 int alias_idx = _compile->get_alias_index(phi->adr_type()); | |
765 igvn->hash_delete(phi); | |
766 for (uint i = 1; i < phi->req(); i++) { | |
767 Node *mem = phi->in(i); | |
768 Node *new_mem = find_mem(mem, alias_idx, igvn); | |
769 if (mem != new_mem) { | |
770 phi->set_req(i, new_mem); | |
771 } | |
772 } | |
773 igvn->hash_insert(phi); | |
774 record_for_optimizer(phi); | |
775 } | |
776 | |
777 // Update the memory inputs of MemNodes with the value we computed | |
778 // in Phase 2. | |
779 for (int i = 0; i < _nodes->length(); i++) { | |
780 Node *nmem = get_map(i); | |
781 if (nmem != NULL) { | |
782 Node *n = _nodes->at(i)._node; | |
783 if (n != NULL && n->is_Mem()) { | |
784 igvn->hash_delete(n); | |
785 n->set_req(MemNode::Memory, nmem); | |
786 igvn->hash_insert(n); | |
787 record_for_optimizer(n); | |
788 } | |
789 } | |
790 } | |
791 } | |
792 | |
793 void ConnectionGraph::compute_escape() { | |
794 GrowableArray<int> worklist; | |
795 GrowableArray<Node *> alloc_worklist; | |
796 VectorSet visited(Thread::current()->resource_area()); | |
797 PhaseGVN *igvn = _compile->initial_gvn(); | |
798 | |
799 // process Phi nodes from the deferred list, they may not have | |
800 while(_deferred.size() > 0) { | |
801 Node * n = _deferred.pop(); | |
802 PhiNode * phi = n->as_Phi(); | |
803 | |
804 process_phi_escape(phi, igvn); | |
805 } | |
806 | |
807 VectorSet ptset(Thread::current()->resource_area()); | |
808 | |
809 // remove deferred edges from the graph and collect | |
810 // information we will need for type splitting | |
811 for (uint ni = 0; ni < (uint)_nodes->length(); ni++) { | |
812 PointsToNode * ptn = _nodes->adr_at(ni); | |
813 PointsToNode::NodeType nt = ptn->node_type(); | |
814 | |
815 if (nt == PointsToNode::UnknownType) { | |
816 continue; // not a node we are interested in | |
817 } | |
818 Node *n = ptn->_node; | |
819 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { | |
820 remove_deferred(ni); | |
821 if (n->is_AddP()) { | |
822 // if this AddP computes an address which may point to more that one | |
823 // object, nothing the address points to can be a unique type. | |
824 Node *base = n->in(AddPNode::Base); | |
825 ptset.Clear(); | |
826 PointsTo(ptset, base, igvn); | |
827 if (ptset.Size() > 1) { | |
828 for( VectorSetI j(&ptset); j.test(); ++j ) { | |
829 PointsToNode *ptaddr = _nodes->adr_at(j.elem); | |
830 ptaddr->_unique_type = false; | |
831 } | |
832 } | |
833 } | |
834 } else if (n->is_Call()) { | |
835 // initialize _escape_state of calls to GlobalEscape | |
836 n->as_Call()->_escape_state = PointsToNode::GlobalEscape; | |
837 // push call on alloc_worlist (alocations are calls) | |
838 // for processing by split_unique_types() | |
839 alloc_worklist.push(n); | |
840 } | |
841 } | |
842 // push all GlobalEscape nodes on the worklist | |
843 for (uint nj = 0; nj < (uint)_nodes->length(); nj++) { | |
844 if (_nodes->at(nj).escape_state() == PointsToNode::GlobalEscape) { | |
845 worklist.append(nj); | |
846 } | |
847 } | |
848 // mark all node reachable from GlobalEscape nodes | |
849 while(worklist.length() > 0) { | |
850 PointsToNode n = _nodes->at(worklist.pop()); | |
851 for (uint ei = 0; ei < n.edge_count(); ei++) { | |
852 uint npi = n.edge_target(ei); | |
853 PointsToNode *np = ptnode_adr(npi); | |
854 if (np->escape_state() != PointsToNode::GlobalEscape) { | |
855 np->set_escape_state(PointsToNode::GlobalEscape); | |
856 worklist.append_if_missing(npi); | |
857 } | |
858 } | |
859 } | |
860 | |
861 // push all ArgEscape nodes on the worklist | |
862 for (uint nk = 0; nk < (uint)_nodes->length(); nk++) { | |
863 if (_nodes->at(nk).escape_state() == PointsToNode::ArgEscape) | |
864 worklist.push(nk); | |
865 } | |
866 // mark all node reachable from ArgEscape nodes | |
867 while(worklist.length() > 0) { | |
868 PointsToNode n = _nodes->at(worklist.pop()); | |
869 | |
870 for (uint ei = 0; ei < n.edge_count(); ei++) { | |
871 uint npi = n.edge_target(ei); | |
872 PointsToNode *np = ptnode_adr(npi); | |
873 if (np->escape_state() != PointsToNode::ArgEscape) { | |
874 np->set_escape_state(PointsToNode::ArgEscape); | |
875 worklist.append_if_missing(npi); | |
876 } | |
877 } | |
878 } | |
879 _collecting = false; | |
880 | |
881 // Now use the escape information to create unique types for | |
882 // unescaped objects | |
883 split_unique_types(alloc_worklist); | |
884 } | |
885 | |
886 Node * ConnectionGraph::skip_casts(Node *n) { | |
887 while(n->Opcode() == Op_CastPP || n->Opcode() == Op_CheckCastPP) { | |
888 n = n->in(1); | |
889 } | |
890 return n; | |
891 } | |
892 | |
893 void ConnectionGraph::process_phi_escape(PhiNode *phi, PhaseTransform *phase) { | |
894 | |
895 if (phi->type()->isa_oopptr() == NULL) | |
896 return; // nothing to do if not an oop | |
897 | |
898 PointsToNode *ptadr = ptnode_adr(phi->_idx); | |
899 int incount = phi->req(); | |
900 int non_null_inputs = 0; | |
901 | |
902 for (int i = 1; i < incount ; i++) { | |
903 if (phi->in(i) != NULL) | |
904 non_null_inputs++; | |
905 } | |
906 if (non_null_inputs == ptadr->_inputs_processed) | |
907 return; // no new inputs since the last time this node was processed, | |
908 // the current information is valid | |
909 | |
910 ptadr->_inputs_processed = non_null_inputs; // prevent recursive processing of this node | |
911 for (int j = 1; j < incount ; j++) { | |
912 Node * n = phi->in(j); | |
913 if (n == NULL) | |
914 continue; // ignore NULL | |
915 n = skip_casts(n); | |
916 if (n->is_top() || n == phi) | |
917 continue; // ignore top or inputs which go back this node | |
918 int nopc = n->Opcode(); | |
919 PointsToNode npt = _nodes->at(n->_idx); | |
920 if (_nodes->at(n->_idx).node_type() == PointsToNode::JavaObject) { | |
921 add_pointsto_edge(phi->_idx, n->_idx); | |
922 } else { | |
923 add_deferred_edge(phi->_idx, n->_idx); | |
924 } | |
925 } | |
926 } | |
927 | |
928 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { | |
929 | |
930 _processed.set(call->_idx); | |
931 switch (call->Opcode()) { | |
932 | |
933 // arguments to allocation and locking don't escape | |
934 case Op_Allocate: | |
935 case Op_AllocateArray: | |
936 case Op_Lock: | |
937 case Op_Unlock: | |
938 break; | |
939 | |
940 case Op_CallStaticJava: | |
941 // For a static call, we know exactly what method is being called. | |
942 // Use bytecode estimator to record the call's escape affects | |
943 { | |
944 ciMethod *meth = call->as_CallJava()->method(); | |
945 if (meth != NULL) { | |
946 const TypeTuple * d = call->tf()->domain(); | |
947 BCEscapeAnalyzer call_analyzer(meth); | |
948 VectorSet ptset(Thread::current()->resource_area()); | |
949 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { | |
950 const Type* at = d->field_at(i); | |
951 int k = i - TypeFunc::Parms; | |
952 | |
953 if (at->isa_oopptr() != NULL) { | |
954 Node *arg = skip_casts(call->in(i)); | |
955 | |
956 if (!call_analyzer.is_arg_stack(k)) { | |
957 // The argument global escapes, mark everything it could point to | |
958 ptset.Clear(); | |
959 PointsTo(ptset, arg, phase); | |
960 for( VectorSetI j(&ptset); j.test(); ++j ) { | |
961 uint pt = j.elem; | |
962 | |
963 set_escape_state(pt, PointsToNode::GlobalEscape); | |
964 } | |
965 } else if (!call_analyzer.is_arg_local(k)) { | |
966 // The argument itself doesn't escape, but any fields might | |
967 ptset.Clear(); | |
968 PointsTo(ptset, arg, phase); | |
969 for( VectorSetI j(&ptset); j.test(); ++j ) { | |
970 uint pt = j.elem; | |
971 add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); | |
972 } | |
973 } | |
974 } | |
975 } | |
976 call_analyzer.copy_dependencies(C()->dependencies()); | |
977 break; | |
978 } | |
979 // fall-through if not a Java method | |
980 } | |
981 | |
982 default: | |
983 // Some other type of call, assume the worst case: all arguments | |
984 // globally escape. | |
985 { | |
986 // adjust escape state for outgoing arguments | |
987 const TypeTuple * d = call->tf()->domain(); | |
988 VectorSet ptset(Thread::current()->resource_area()); | |
989 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { | |
990 const Type* at = d->field_at(i); | |
991 | |
992 if (at->isa_oopptr() != NULL) { | |
993 Node *arg = skip_casts(call->in(i)); | |
994 ptset.Clear(); | |
995 PointsTo(ptset, arg, phase); | |
996 for( VectorSetI j(&ptset); j.test(); ++j ) { | |
997 uint pt = j.elem; | |
998 | |
999 set_escape_state(pt, PointsToNode::GlobalEscape); | |
1000 } | |
1001 } | |
1002 } | |
1003 } | |
1004 } | |
1005 } | |
1006 void ConnectionGraph::process_call_result(ProjNode *resproj, PhaseTransform *phase) { | |
1007 CallNode *call = resproj->in(0)->as_Call(); | |
1008 | |
1009 PointsToNode *ptadr = ptnode_adr(resproj->_idx); | |
1010 | |
1011 ptadr->_node = resproj; | |
1012 ptadr->set_node_type(PointsToNode::LocalVar); | |
1013 set_escape_state(resproj->_idx, PointsToNode::UnknownEscape); | |
1014 _processed.set(resproj->_idx); | |
1015 | |
1016 switch (call->Opcode()) { | |
1017 case Op_Allocate: | |
1018 { | |
1019 Node *k = call->in(AllocateNode::KlassNode); | |
1020 const TypeKlassPtr *kt; | |
1021 if (k->Opcode() == Op_LoadKlass) { | |
1022 kt = k->as_Load()->type()->isa_klassptr(); | |
1023 } else { | |
1024 kt = k->as_Type()->type()->isa_klassptr(); | |
1025 } | |
1026 assert(kt != NULL, "TypeKlassPtr required."); | |
1027 ciKlass* cik = kt->klass(); | |
1028 ciInstanceKlass* ciik = cik->as_instance_klass(); | |
1029 | |
1030 PointsToNode *ptadr = ptnode_adr(call->_idx); | |
1031 ptadr->set_node_type(PointsToNode::JavaObject); | |
1032 if (cik->is_subclass_of(_compile->env()->Thread_klass()) || ciik->has_finalizer()) { | |
1033 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | |
1034 add_pointsto_edge(resproj->_idx, _phantom_object); | |
1035 } else { | |
1036 set_escape_state(call->_idx, PointsToNode::NoEscape); | |
1037 add_pointsto_edge(resproj->_idx, call->_idx); | |
1038 } | |
1039 _processed.set(call->_idx); | |
1040 break; | |
1041 } | |
1042 | |
1043 case Op_AllocateArray: | |
1044 { | |
1045 PointsToNode *ptadr = ptnode_adr(call->_idx); | |
1046 ptadr->set_node_type(PointsToNode::JavaObject); | |
1047 set_escape_state(call->_idx, PointsToNode::NoEscape); | |
1048 _processed.set(call->_idx); | |
1049 add_pointsto_edge(resproj->_idx, call->_idx); | |
1050 break; | |
1051 } | |
1052 | |
1053 case Op_Lock: | |
1054 case Op_Unlock: | |
1055 break; | |
1056 | |
1057 case Op_CallStaticJava: | |
1058 // For a static call, we know exactly what method is being called. | |
1059 // Use bytecode estimator to record whether the call's return value escapes | |
1060 { | |
1061 const TypeTuple *r = call->tf()->range(); | |
1062 const Type* ret_type = NULL; | |
1063 | |
1064 if (r->cnt() > TypeFunc::Parms) | |
1065 ret_type = r->field_at(TypeFunc::Parms); | |
1066 | |
1067 // Note: we use isa_ptr() instead of isa_oopptr() here because the | |
1068 // _multianewarray functions return a TypeRawPtr. | |
1069 if (ret_type == NULL || ret_type->isa_ptr() == NULL) | |
1070 break; // doesn't return a pointer type | |
1071 | |
1072 ciMethod *meth = call->as_CallJava()->method(); | |
1073 if (meth == NULL) { | |
1074 // not a Java method, assume global escape | |
1075 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | |
1076 if (resproj != NULL) | |
1077 add_pointsto_edge(resproj->_idx, _phantom_object); | |
1078 } else { | |
1079 BCEscapeAnalyzer call_analyzer(meth); | |
1080 VectorSet ptset(Thread::current()->resource_area()); | |
1081 | |
1082 if (call_analyzer.is_return_local() && resproj != NULL) { | |
1083 // determine whether any arguments are returned | |
1084 const TypeTuple * d = call->tf()->domain(); | |
1085 set_escape_state(call->_idx, PointsToNode::NoEscape); | |
1086 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { | |
1087 const Type* at = d->field_at(i); | |
1088 | |
1089 if (at->isa_oopptr() != NULL) { | |
1090 Node *arg = skip_casts(call->in(i)); | |
1091 | |
1092 if (call_analyzer.is_arg_returned(i - TypeFunc::Parms)) { | |
1093 PointsToNode *arg_esp = _nodes->adr_at(arg->_idx); | |
1094 if (arg_esp->node_type() == PointsToNode::JavaObject) | |
1095 add_pointsto_edge(resproj->_idx, arg->_idx); | |
1096 else | |
1097 add_deferred_edge(resproj->_idx, arg->_idx); | |
1098 arg_esp->_hidden_alias = true; | |
1099 } | |
1100 } | |
1101 } | |
1102 } else { | |
1103 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | |
1104 if (resproj != NULL) | |
1105 add_pointsto_edge(resproj->_idx, _phantom_object); | |
1106 } | |
1107 call_analyzer.copy_dependencies(C()->dependencies()); | |
1108 } | |
1109 break; | |
1110 } | |
1111 | |
1112 default: | |
1113 // Some other type of call, assume the worst case that the | |
1114 // returned value, if any, globally escapes. | |
1115 { | |
1116 const TypeTuple *r = call->tf()->range(); | |
1117 | |
1118 if (r->cnt() > TypeFunc::Parms) { | |
1119 const Type* ret_type = r->field_at(TypeFunc::Parms); | |
1120 | |
1121 // Note: we use isa_ptr() instead of isa_oopptr() here because the | |
1122 // _multianewarray functions return a TypeRawPtr. | |
1123 if (ret_type->isa_ptr() != NULL) { | |
1124 PointsToNode *ptadr = ptnode_adr(call->_idx); | |
1125 ptadr->set_node_type(PointsToNode::JavaObject); | |
1126 set_escape_state(call->_idx, PointsToNode::GlobalEscape); | |
1127 if (resproj != NULL) | |
1128 add_pointsto_edge(resproj->_idx, _phantom_object); | |
1129 } | |
1130 } | |
1131 } | |
1132 } | |
1133 } | |
1134 | |
1135 void ConnectionGraph::record_for_escape_analysis(Node *n) { | |
1136 if (_collecting) { | |
1137 if (n->is_Phi()) { | |
1138 PhiNode *phi = n->as_Phi(); | |
1139 const Type *pt = phi->type(); | |
1140 if ((pt->isa_oopptr() != NULL) || pt == TypePtr::NULL_PTR) { | |
1141 PointsToNode *ptn = ptnode_adr(phi->_idx); | |
1142 ptn->set_node_type(PointsToNode::LocalVar); | |
1143 ptn->_node = n; | |
1144 _deferred.push(n); | |
1145 } | |
1146 } | |
1147 } | |
1148 } | |
1149 | |
1150 void ConnectionGraph::record_escape_work(Node *n, PhaseTransform *phase) { | |
1151 | |
1152 int opc = n->Opcode(); | |
1153 PointsToNode *ptadr = ptnode_adr(n->_idx); | |
1154 | |
1155 if (_processed.test(n->_idx)) | |
1156 return; | |
1157 | |
1158 ptadr->_node = n; | |
1159 if (n->is_Call()) { | |
1160 CallNode *call = n->as_Call(); | |
1161 process_call_arguments(call, phase); | |
1162 return; | |
1163 } | |
1164 | |
1165 switch (opc) { | |
1166 case Op_AddP: | |
1167 { | |
1168 Node *base = skip_casts(n->in(AddPNode::Base)); | |
1169 ptadr->set_node_type(PointsToNode::Field); | |
1170 | |
1171 // create a field edge to this node from everything adr could point to | |
1172 VectorSet ptset(Thread::current()->resource_area()); | |
1173 PointsTo(ptset, base, phase); | |
1174 for( VectorSetI i(&ptset); i.test(); ++i ) { | |
1175 uint pt = i.elem; | |
1176 add_field_edge(pt, n->_idx, type_to_offset(phase->type(n))); | |
1177 } | |
1178 break; | |
1179 } | |
1180 case Op_Parm: | |
1181 { | |
1182 ProjNode *nproj = n->as_Proj(); | |
1183 uint con = nproj->_con; | |
1184 if (con < TypeFunc::Parms) | |
1185 return; | |
1186 const Type *t = nproj->in(0)->as_Start()->_domain->field_at(con); | |
1187 if (t->isa_ptr() == NULL) | |
1188 return; | |
1189 ptadr->set_node_type(PointsToNode::JavaObject); | |
1190 if (t->isa_oopptr() != NULL) { | |
1191 set_escape_state(n->_idx, PointsToNode::ArgEscape); | |
1192 } else { | |
1193 // this must be the incoming state of an OSR compile, we have to assume anything | |
1194 // passed in globally escapes | |
1195 assert(_compile->is_osr_compilation(), "bad argument type for non-osr compilation"); | |
1196 set_escape_state(n->_idx, PointsToNode::GlobalEscape); | |
1197 } | |
1198 _processed.set(n->_idx); | |
1199 break; | |
1200 } | |
1201 case Op_Phi: | |
1202 { | |
1203 PhiNode *phi = n->as_Phi(); | |
1204 if (phi->type()->isa_oopptr() == NULL) | |
1205 return; // nothing to do if not an oop | |
1206 ptadr->set_node_type(PointsToNode::LocalVar); | |
1207 process_phi_escape(phi, phase); | |
1208 break; | |
1209 } | |
1210 case Op_CreateEx: | |
1211 { | |
1212 // assume that all exception objects globally escape | |
1213 ptadr->set_node_type(PointsToNode::JavaObject); | |
1214 set_escape_state(n->_idx, PointsToNode::GlobalEscape); | |
1215 _processed.set(n->_idx); | |
1216 break; | |
1217 } | |
1218 case Op_ConP: | |
1219 { | |
1220 const Type *t = phase->type(n); | |
1221 ptadr->set_node_type(PointsToNode::JavaObject); | |
1222 // assume all pointer constants globally escape except for null | |
1223 if (t == TypePtr::NULL_PTR) | |
1224 set_escape_state(n->_idx, PointsToNode::NoEscape); | |
1225 else | |
1226 set_escape_state(n->_idx, PointsToNode::GlobalEscape); | |
1227 _processed.set(n->_idx); | |
1228 break; | |
1229 } | |
1230 case Op_LoadKlass: | |
1231 { | |
1232 ptadr->set_node_type(PointsToNode::JavaObject); | |
1233 set_escape_state(n->_idx, PointsToNode::GlobalEscape); | |
1234 _processed.set(n->_idx); | |
1235 break; | |
1236 } | |
1237 case Op_LoadP: | |
1238 { | |
1239 const Type *t = phase->type(n); | |
1240 if (!t->isa_oopptr()) | |
1241 return; | |
1242 ptadr->set_node_type(PointsToNode::LocalVar); | |
1243 set_escape_state(n->_idx, PointsToNode::UnknownEscape); | |
1244 | |
1245 Node *adr = skip_casts(n->in(MemNode::Address)); | |
1246 const Type *adr_type = phase->type(adr); | |
1247 Node *adr_base = skip_casts((adr->Opcode() == Op_AddP) ? adr->in(AddPNode::Base) : adr); | |
1248 | |
1249 // For everything "adr" could point to, create a deferred edge from | |
1250 // this node to each field with the same offset as "adr_type" | |
1251 VectorSet ptset(Thread::current()->resource_area()); | |
1252 PointsTo(ptset, adr_base, phase); | |
1253 // If ptset is empty, then this value must have been set outside | |
1254 // this method, so we add the phantom node | |
1255 if (ptset.Size() == 0) | |
1256 ptset.set(_phantom_object); | |
1257 for( VectorSetI i(&ptset); i.test(); ++i ) { | |
1258 uint pt = i.elem; | |
1259 add_deferred_edge_to_fields(n->_idx, pt, type_to_offset(adr_type)); | |
1260 } | |
1261 break; | |
1262 } | |
1263 case Op_StoreP: | |
1264 case Op_StorePConditional: | |
1265 case Op_CompareAndSwapP: | |
1266 { | |
1267 Node *adr = n->in(MemNode::Address); | |
1268 Node *val = skip_casts(n->in(MemNode::ValueIn)); | |
1269 const Type *adr_type = phase->type(adr); | |
1270 if (!adr_type->isa_oopptr()) | |
1271 return; | |
1272 | |
1273 assert(adr->Opcode() == Op_AddP, "expecting an AddP"); | |
1274 Node *adr_base = adr->in(AddPNode::Base); | |
1275 | |
1276 // For everything "adr_base" could point to, create a deferred edge to "val" from each field | |
1277 // with the same offset as "adr_type" | |
1278 VectorSet ptset(Thread::current()->resource_area()); | |
1279 PointsTo(ptset, adr_base, phase); | |
1280 for( VectorSetI i(&ptset); i.test(); ++i ) { | |
1281 uint pt = i.elem; | |
1282 add_edge_from_fields(pt, val->_idx, type_to_offset(adr_type)); | |
1283 } | |
1284 break; | |
1285 } | |
1286 case Op_Proj: | |
1287 { | |
1288 ProjNode *nproj = n->as_Proj(); | |
1289 Node *n0 = nproj->in(0); | |
1290 // we are only interested in the result projection from a call | |
1291 if (nproj->_con == TypeFunc::Parms && n0->is_Call() ) { | |
1292 process_call_result(nproj, phase); | |
1293 } | |
1294 | |
1295 break; | |
1296 } | |
1297 case Op_CastPP: | |
1298 case Op_CheckCastPP: | |
1299 { | |
1300 ptadr->set_node_type(PointsToNode::LocalVar); | |
1301 int ti = n->in(1)->_idx; | |
1302 if (_nodes->at(ti).node_type() == PointsToNode::JavaObject) { | |
1303 add_pointsto_edge(n->_idx, ti); | |
1304 } else { | |
1305 add_deferred_edge(n->_idx, ti); | |
1306 } | |
1307 break; | |
1308 } | |
1309 default: | |
1310 ; | |
1311 // nothing to do | |
1312 } | |
1313 } | |
1314 | |
1315 void ConnectionGraph::record_escape(Node *n, PhaseTransform *phase) { | |
1316 if (_collecting) | |
1317 record_escape_work(n, phase); | |
1318 } | |
1319 | |
1320 #ifndef PRODUCT | |
1321 void ConnectionGraph::dump() { | |
1322 PhaseGVN *igvn = _compile->initial_gvn(); | |
1323 bool first = true; | |
1324 | |
1325 for (uint ni = 0; ni < (uint)_nodes->length(); ni++) { | |
1326 PointsToNode *esp = _nodes->adr_at(ni); | |
1327 if (esp->node_type() == PointsToNode::UnknownType || esp->_node == NULL) | |
1328 continue; | |
1329 PointsToNode::EscapeState es = escape_state(esp->_node, igvn); | |
1330 if (es == PointsToNode::NoEscape || (Verbose && | |
1331 (es != PointsToNode::UnknownEscape || esp->edge_count() != 0))) { | |
1332 // don't print null pointer node which almost every method has | |
1333 if (esp->_node->Opcode() != Op_ConP || igvn->type(esp->_node) != TypePtr::NULL_PTR) { | |
1334 if (first) { | |
1335 tty->print("======== Connection graph for "); | |
1336 C()->method()->print_short_name(); | |
1337 tty->cr(); | |
1338 first = false; | |
1339 } | |
1340 tty->print("%4d ", ni); | |
1341 esp->dump(); | |
1342 } | |
1343 } | |
1344 } | |
1345 } | |
1346 #endif |