--- a/hotspot/src/share/vm/opto/escape.cpp Sat Nov 06 18:52:07 2010 -0700
+++ b/hotspot/src/share/vm/opto/escape.cpp Sat Nov 06 20:35:36 2010 -0700
@@ -85,6 +85,7 @@
_nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()),
_processed(C->comp_arena()),
_collecting(true),
+ _progress(false),
_compile(C),
_igvn(igvn),
_node_map(C->comp_arena()) {
@@ -113,7 +114,7 @@
assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set");
assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of PointsTo edge");
assert(t->node_type() == PointsToNode::JavaObject, "invalid destination of PointsTo edge");
- f->add_edge(to_i, PointsToNode::PointsToEdge);
+ add_edge(f, to_i, PointsToNode::PointsToEdge);
}
void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) {
@@ -126,7 +127,7 @@
// don't add a self-referential edge, this can occur during removal of
// deferred edges
if (from_i != to_i)
- f->add_edge(to_i, PointsToNode::DeferredEdge);
+ add_edge(f, to_i, PointsToNode::DeferredEdge);
}
int ConnectionGraph::address_offset(Node* adr, PhaseTransform *phase) {
@@ -157,7 +158,7 @@
assert (t->offset() == -1 || t->offset() == offset, "conflicting field offsets");
t->set_offset(offset);
- f->add_edge(to_i, PointsToNode::FieldEdge);
+ add_edge(f, to_i, PointsToNode::FieldEdge);
}
void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) {
@@ -995,7 +996,7 @@
GrowableArray<Node *> memnode_worklist;
GrowableArray<PhiNode *> orig_phis;
- PhaseGVN *igvn = _igvn;
+ PhaseIterGVN *igvn = _igvn;
uint new_index_start = (uint) _compile->num_alias_types();
Arena* arena = Thread::current()->resource_area();
VectorSet visited(arena);
@@ -1531,14 +1532,9 @@
has_allocations = true;
}
if(n->is_AddP()) {
- // Collect address nodes which directly reference an allocation.
- // Use them during stage 3 below to build initial connection graph
- // field edges. Other field edges could be added after StoreP/LoadP
- // nodes are processed during stage 4 below.
- Node* base = get_addp_base(n);
- if(base->is_Proj() && base->in(0)->is_Allocate()) {
- cg_worklist.append(n->_idx);
- }
+ // Collect address nodes. Use them during stage 3 below
+ // to build initial connection graph field edges.
+ cg_worklist.append(n->_idx);
} else if (n->is_MergeMem()) {
// Collect all MergeMem nodes to add memory slices for
// scalar replaceable objects in split_unique_types().
@@ -1562,18 +1558,28 @@
build_connection_graph(n, igvn);
}
- // 3. Pass to create fields edges (Allocate -F-> AddP).
+ // 3. Pass to create initial fields edges (JavaObject -F-> AddP)
+ // to reduce number of iterations during stage 4 below.
uint cg_length = cg_worklist.length();
for( uint next = 0; next < cg_length; ++next ) {
int ni = cg_worklist.at(next);
- build_connection_graph(ptnode_adr(ni)->_node, igvn);
+ Node* n = ptnode_adr(ni)->_node;
+ Node* base = get_addp_base(n);
+ if (base->is_Proj())
+ base = base->in(0);
+ PointsToNode::NodeType nt = ptnode_adr(base->_idx)->node_type();
+ if (nt == PointsToNode::JavaObject) {
+ build_connection_graph(n, igvn);
+ }
}
cg_worklist.clear();
cg_worklist.append(_phantom_object);
+ GrowableArray<uint> worklist;
// 4. Build Connection Graph which need
// to walk the connection graph.
+ _progress = false;
for (uint ni = 0; ni < nodes_size(); ni++) {
PointsToNode* ptn = ptnode_adr(ni);
Node *n = ptn->_node;
@@ -1581,13 +1587,52 @@
build_connection_graph(n, igvn);
if (ptn->node_type() != PointsToNode::UnknownType)
cg_worklist.append(n->_idx); // Collect CG nodes
+ if (!_processed.test(n->_idx))
+ worklist.append(n->_idx); // Collect C/A/L/S nodes
}
}
+ // After IGVN user nodes may have smaller _idx than
+ // their inputs so they will be processed first in
+ // previous loop. Because of that not all Graph
+ // edges will be created. Walk over interesting
+ // nodes again until no new edges are created.
+ //
+ // Normally only 1-3 passes needed to build
+ // Connection Graph depending on graph complexity.
+ // Set limit to 10 to catch situation when something
+ // did go wrong and recompile the method without EA.
+
+#define CG_BUILD_ITER_LIMIT 10
+
+ uint length = worklist.length();
+ int iterations = 0;
+ while(_progress && (iterations++ < CG_BUILD_ITER_LIMIT)) {
+ _progress = false;
+ for( uint next = 0; next < length; ++next ) {
+ int ni = worklist.at(next);
+ PointsToNode* ptn = ptnode_adr(ni);
+ Node* n = ptn->_node;
+ assert(n != NULL, "should be known node");
+ build_connection_graph(n, igvn);
+ }
+ }
+ if (iterations >= CG_BUILD_ITER_LIMIT) {
+ assert(iterations < CG_BUILD_ITER_LIMIT,
+ err_msg("infinite EA connection graph build with %d nodes and worklist size %d",
+ nodes_size(), length));
+ // Possible infinite build_connection_graph loop,
+ // retry compilation without escape analysis.
+ C->record_failure(C2Compiler::retry_no_escape_analysis());
+ _collecting = false;
+ return false;
+ }
+#undef CG_BUILD_ITER_LIMIT
+
Arena* arena = Thread::current()->resource_area();
VectorSet ptset(arena);
- GrowableArray<uint> deferred_edges;
VectorSet visited(arena);
+ worklist.clear();
// 5. Remove deferred edges from the graph and adjust
// escape state of nonescaping objects.
@@ -1597,7 +1642,7 @@
PointsToNode* ptn = ptnode_adr(ni);
PointsToNode::NodeType nt = ptn->node_type();
if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
- remove_deferred(ni, &deferred_edges, &visited);
+ remove_deferred(ni, &worklist, &visited);
Node *n = ptn->_node;
if (n->is_AddP()) {
// Search for objects which are not scalar replaceable
@@ -1608,7 +1653,7 @@
}
// 6. Propagate escape states.
- GrowableArray<int> worklist;
+ worklist.clear();
bool has_non_escaping_obj = false;
// push all GlobalEscape nodes on the worklist
@@ -2444,13 +2489,14 @@
// Don't set processed bit for AddP, LoadP, StoreP since
// they may need more then one pass to process.
+ // Also don't mark as processed Call nodes since their
+ // arguments may need more then one pass to process.
if (_processed.test(n_idx))
return; // No need to redefine node's state.
if (n->is_Call()) {
CallNode *call = n->as_Call();
process_call_arguments(call, phase);
- _processed.set(n_idx);
return;
}
--- a/hotspot/src/share/vm/opto/escape.hpp Sat Nov 06 18:52:07 2010 -0700
+++ b/hotspot/src/share/vm/opto/escape.hpp Sat Nov 06 20:35:36 2010 -0700
@@ -219,6 +219,9 @@
// is still being collected. If false,
// no new nodes will be processed.
+ bool _progress; // Indicates whether new Graph's edges
+ // were created.
+
uint _phantom_object; // Index of globally escaping object
// that pointer values loaded from
// a field which has not been set
@@ -266,6 +269,13 @@
void add_deferred_edge(uint from_i, uint to_i);
void add_field_edge(uint from_i, uint to_i, int offs);
+ // Add an edge of the specified type pointing to the specified target.
+ // Set _progress if new edge is added.
+ void add_edge(PointsToNode *f, uint to_i, PointsToNode::EdgeType et) {
+ uint e_cnt = f->edge_count();
+ f->add_edge(to_i, et);
+ _progress |= (f->edge_count() != e_cnt);
+ }
// Add an edge to node given by "to_i" from any field of adr_i whose offset
// matches "offset" A deferred edge is added if to_i is a LocalVar, and