提交 25b77489 编写于 作者: K kvn

6991188: C2 Crashes while compiling method

Summary: Do several iterations to build EA Connection Graph.
Reviewed-by: never, twisti, ysr
上级 bc08383d
...@@ -85,6 +85,7 @@ ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) : ...@@ -85,6 +85,7 @@ ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
_nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()), _nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()),
_processed(C->comp_arena()), _processed(C->comp_arena()),
_collecting(true), _collecting(true),
_progress(false),
_compile(C), _compile(C),
_igvn(igvn), _igvn(igvn),
_node_map(C->comp_arena()) { _node_map(C->comp_arena()) {
...@@ -113,7 +114,7 @@ void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) { ...@@ -113,7 +114,7 @@ void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) {
assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); 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(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"); 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) { void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) {
...@@ -126,7 +127,7 @@ void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) { ...@@ -126,7 +127,7 @@ void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) {
// don't add a self-referential edge, this can occur during removal of // don't add a self-referential edge, this can occur during removal of
// deferred edges // deferred edges
if (from_i != to_i) 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) { int ConnectionGraph::address_offset(Node* adr, PhaseTransform *phase) {
...@@ -157,7 +158,7 @@ void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) { ...@@ -157,7 +158,7 @@ void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) {
assert (t->offset() == -1 || t->offset() == offset, "conflicting field offsets"); assert (t->offset() == -1 || t->offset() == offset, "conflicting field offsets");
t->set_offset(offset); 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) { void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) {
...@@ -995,7 +996,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) ...@@ -995,7 +996,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
GrowableArray<Node *> memnode_worklist; GrowableArray<Node *> memnode_worklist;
GrowableArray<PhiNode *> orig_phis; GrowableArray<PhiNode *> orig_phis;
PhaseGVN *igvn = _igvn; PhaseIterGVN *igvn = _igvn;
uint new_index_start = (uint) _compile->num_alias_types(); uint new_index_start = (uint) _compile->num_alias_types();
Arena* arena = Thread::current()->resource_area(); Arena* arena = Thread::current()->resource_area();
VectorSet visited(arena); VectorSet visited(arena);
...@@ -1531,14 +1532,9 @@ bool ConnectionGraph::compute_escape() { ...@@ -1531,14 +1532,9 @@ bool ConnectionGraph::compute_escape() {
has_allocations = true; has_allocations = true;
} }
if(n->is_AddP()) { if(n->is_AddP()) {
// Collect address nodes which directly reference an allocation. // Collect address nodes. Use them during stage 3 below
// Use them during stage 3 below to build initial connection graph // to build initial connection graph field edges.
// field edges. Other field edges could be added after StoreP/LoadP cg_worklist.append(n->_idx);
// 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);
}
} else if (n->is_MergeMem()) { } else if (n->is_MergeMem()) {
// Collect all MergeMem nodes to add memory slices for // Collect all MergeMem nodes to add memory slices for
// scalar replaceable objects in split_unique_types(). // scalar replaceable objects in split_unique_types().
...@@ -1562,18 +1558,28 @@ bool ConnectionGraph::compute_escape() { ...@@ -1562,18 +1558,28 @@ bool ConnectionGraph::compute_escape() {
build_connection_graph(n, igvn); 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(); uint cg_length = cg_worklist.length();
for( uint next = 0; next < cg_length; ++next ) { for( uint next = 0; next < cg_length; ++next ) {
int ni = cg_worklist.at(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.clear();
cg_worklist.append(_phantom_object); cg_worklist.append(_phantom_object);
GrowableArray<uint> worklist;
// 4. Build Connection Graph which need // 4. Build Connection Graph which need
// to walk the connection graph. // to walk the connection graph.
_progress = false;
for (uint ni = 0; ni < nodes_size(); ni++) { for (uint ni = 0; ni < nodes_size(); ni++) {
PointsToNode* ptn = ptnode_adr(ni); PointsToNode* ptn = ptnode_adr(ni);
Node *n = ptn->_node; Node *n = ptn->_node;
...@@ -1581,13 +1587,52 @@ bool ConnectionGraph::compute_escape() { ...@@ -1581,13 +1587,52 @@ bool ConnectionGraph::compute_escape() {
build_connection_graph(n, igvn); build_connection_graph(n, igvn);
if (ptn->node_type() != PointsToNode::UnknownType) if (ptn->node_type() != PointsToNode::UnknownType)
cg_worklist.append(n->_idx); // Collect CG nodes 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(); Arena* arena = Thread::current()->resource_area();
VectorSet ptset(arena); VectorSet ptset(arena);
GrowableArray<uint> deferred_edges;
VectorSet visited(arena); VectorSet visited(arena);
worklist.clear();
// 5. Remove deferred edges from the graph and adjust // 5. Remove deferred edges from the graph and adjust
// escape state of nonescaping objects. // escape state of nonescaping objects.
...@@ -1597,7 +1642,7 @@ bool ConnectionGraph::compute_escape() { ...@@ -1597,7 +1642,7 @@ bool ConnectionGraph::compute_escape() {
PointsToNode* ptn = ptnode_adr(ni); PointsToNode* ptn = ptnode_adr(ni);
PointsToNode::NodeType nt = ptn->node_type(); PointsToNode::NodeType nt = ptn->node_type();
if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
remove_deferred(ni, &deferred_edges, &visited); remove_deferred(ni, &worklist, &visited);
Node *n = ptn->_node; Node *n = ptn->_node;
if (n->is_AddP()) { if (n->is_AddP()) {
// Search for objects which are not scalar replaceable // Search for objects which are not scalar replaceable
...@@ -1608,7 +1653,7 @@ bool ConnectionGraph::compute_escape() { ...@@ -1608,7 +1653,7 @@ bool ConnectionGraph::compute_escape() {
} }
// 6. Propagate escape states. // 6. Propagate escape states.
GrowableArray<int> worklist; worklist.clear();
bool has_non_escaping_obj = false; bool has_non_escaping_obj = false;
// push all GlobalEscape nodes on the worklist // push all GlobalEscape nodes on the worklist
...@@ -2444,13 +2489,14 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { ...@@ -2444,13 +2489,14 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
// Don't set processed bit for AddP, LoadP, StoreP since // Don't set processed bit for AddP, LoadP, StoreP since
// they may need more then one pass to process. // 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)) if (_processed.test(n_idx))
return; // No need to redefine node's state. return; // No need to redefine node's state.
if (n->is_Call()) { if (n->is_Call()) {
CallNode *call = n->as_Call(); CallNode *call = n->as_Call();
process_call_arguments(call, phase); process_call_arguments(call, phase);
_processed.set(n_idx);
return; return;
} }
......
...@@ -219,6 +219,9 @@ private: ...@@ -219,6 +219,9 @@ private:
// is still being collected. If false, // is still being collected. If false,
// no new nodes will be processed. // no new nodes will be processed.
bool _progress; // Indicates whether new Graph's edges
// were created.
uint _phantom_object; // Index of globally escaping object uint _phantom_object; // Index of globally escaping object
// that pointer values loaded from // that pointer values loaded from
// a field which has not been set // a field which has not been set
...@@ -266,6 +269,13 @@ private: ...@@ -266,6 +269,13 @@ private:
void add_deferred_edge(uint from_i, uint to_i); void add_deferred_edge(uint from_i, uint to_i);
void add_field_edge(uint from_i, uint to_i, int offs); 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 // 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 // matches "offset" A deferred edge is added if to_i is a LocalVar, and
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册