--- a/hotspot/src/share/vm/opto/escape.cpp Fri Jul 02 15:01:47 2010 -0700
+++ b/hotspot/src/share/vm/opto/escape.cpp Fri Jul 02 17:30:30 2010 -0700
@@ -81,18 +81,18 @@
}
#endif
-ConnectionGraph::ConnectionGraph(Compile * C) :
+ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
_nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()),
_processed(C->comp_arena()),
_collecting(true),
_compile(C),
+ _igvn(igvn),
_node_map(C->comp_arena()) {
_phantom_object = C->top()->_idx,
add_node(C->top(), PointsToNode::JavaObject, PointsToNode::GlobalEscape,true);
// Add ConP(#NULL) and ConN(#NULL) nodes.
- PhaseGVN* igvn = C->initial_gvn();
Node* oop_null = igvn->zerocon(T_OBJECT);
_oop_null = oop_null->_idx;
assert(_oop_null < C->unique(), "should be created already");
@@ -182,7 +182,7 @@
_processed.set(n->_idx);
}
-PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n, PhaseTransform *phase) {
+PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n) {
uint idx = n->_idx;
PointsToNode::EscapeState es;
@@ -207,22 +207,26 @@
if (n->uncast()->_idx >= nodes_size())
return PointsToNode::UnknownEscape;
+ PointsToNode::EscapeState orig_es = es;
+
// compute max escape state of anything this node could point to
VectorSet ptset(Thread::current()->resource_area());
- PointsTo(ptset, n, phase);
+ PointsTo(ptset, n);
for(VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i) {
uint pt = i.elem;
PointsToNode::EscapeState pes = ptnode_adr(pt)->escape_state();
if (pes > es)
es = pes;
}
- // cache the computed escape state
- assert(es != PointsToNode::UnknownEscape, "should have computed an escape state");
- ptnode_adr(idx)->set_escape_state(es);
+ if (orig_es != es) {
+ // cache the computed escape state
+ assert(es != PointsToNode::UnknownEscape, "should have computed an escape state");
+ ptnode_adr(idx)->set_escape_state(es);
+ } // orig_es could be PointsToNode::UnknownEscape
return es;
}
-void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase) {
+void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n) {
VectorSet visited(Thread::current()->resource_area());
GrowableArray<uint> worklist;
@@ -990,7 +994,7 @@
GrowableArray<Node *> memnode_worklist;
GrowableArray<PhiNode *> orig_phis;
- PhaseGVN *igvn = _compile->initial_gvn();
+ PhaseGVN *igvn = _igvn;
uint new_index_start = (uint) _compile->num_alias_types();
Arena* arena = Thread::current()->resource_area();
VectorSet visited(arena);
@@ -1012,7 +1016,7 @@
CallNode *alloc = n->as_Call();
// copy escape information to call node
PointsToNode* ptn = ptnode_adr(alloc->_idx);
- PointsToNode::EscapeState es = escape_state(alloc, igvn);
+ PointsToNode::EscapeState es = escape_state(alloc);
// We have an allocation or call which returns a Java object,
// see if it is unescaped.
if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable)
@@ -1123,7 +1127,7 @@
}
} else if (n->is_AddP()) {
ptset.Clear();
- PointsTo(ptset, get_addp_base(n), igvn);
+ PointsTo(ptset, get_addp_base(n));
assert(ptset.Size() == 1, "AddP address is unique");
uint elem = ptset.getelem(); // Allocation node's index
if (elem == _phantom_object) {
@@ -1143,7 +1147,7 @@
continue; // already processed
}
ptset.Clear();
- PointsTo(ptset, n, igvn);
+ PointsTo(ptset, n);
if (ptset.Size() == 1) {
uint elem = ptset.getelem(); // Allocation node's index
if (elem == _phantom_object) {
@@ -1478,6 +1482,26 @@
return false;
}
+void ConnectionGraph::do_analysis(Compile *C, PhaseIterGVN *igvn) {
+ // Add ConP#NULL and ConN#NULL nodes before ConnectionGraph construction
+ // to create space for them in ConnectionGraph::_nodes[].
+ Node* oop_null = igvn->zerocon(T_OBJECT);
+ Node* noop_null = igvn->zerocon(T_NARROWOOP);
+
+ ConnectionGraph* congraph = new(C->comp_arena()) ConnectionGraph(C, igvn);
+ // Perform escape analysis
+ if (congraph->compute_escape()) {
+ // There are non escaping objects.
+ C->set_congraph(congraph);
+ }
+
+ // Cleanup.
+ if (oop_null->outcnt() == 0)
+ igvn->hash_delete(oop_null);
+ if (noop_null->outcnt() == 0)
+ igvn->hash_delete(noop_null);
+}
+
bool ConnectionGraph::compute_escape() {
Compile* C = _compile;
@@ -1492,7 +1516,7 @@
}
GrowableArray<int> cg_worklist;
- PhaseGVN* igvn = C->initial_gvn();
+ PhaseGVN* igvn = _igvn;
bool has_allocations = false;
// Push all useful nodes onto CG list and set their type.
@@ -1661,6 +1685,12 @@
_collecting = false;
assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build");
+#ifndef PRODUCT
+ if (PrintEscapeAnalysis) {
+ dump(); // Dump ConnectionGraph
+ }
+#endif
+
bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0;
if ( has_scalar_replaceable_candidates &&
C->AliasLevel() >= 3 && EliminateAllocations ) {
@@ -1671,10 +1701,6 @@
if (C->failing()) return false;
- // Clean up after split unique types.
- ResourceMark rm;
- PhaseRemoveUseless pru(C->initial_gvn(), C->for_igvn());
-
C->print_method("After Escape Analysis", 2);
#ifdef ASSERT
@@ -1711,7 +1737,7 @@
int offset = ptn->offset();
Node* base = get_addp_base(n);
ptset.Clear();
- PointsTo(ptset, base, phase);
+ PointsTo(ptset, base);
int ptset_size = ptset.Size();
// Check if a oop field's initializing value is recorded and add
@@ -1889,7 +1915,7 @@
arg = get_addp_base(arg);
}
ptset.Clear();
- PointsTo(ptset, arg, phase);
+ PointsTo(ptset, arg);
for( VectorSetI j(&ptset); j.test(); ++j ) {
uint pt = j.elem;
set_escape_state(pt, PointsToNode::ArgEscape);
@@ -1934,7 +1960,7 @@
}
ptset.Clear();
- PointsTo(ptset, arg, phase);
+ PointsTo(ptset, arg);
for( VectorSetI j(&ptset); j.test(); ++j ) {
uint pt = j.elem;
if (global_escapes) {
@@ -1970,7 +1996,7 @@
Node *arg = call->in(i)->uncast();
set_escape_state(arg->_idx, PointsToNode::GlobalEscape);
ptset.Clear();
- PointsTo(ptset, arg, phase);
+ PointsTo(ptset, arg);
for( VectorSetI j(&ptset); j.test(); ++j ) {
uint pt = j.elem;
set_escape_state(pt, PointsToNode::GlobalEscape);
@@ -2433,7 +2459,7 @@
Node *base = get_addp_base(n);
// Create a field edge to this node from everything base could point to.
VectorSet ptset(Thread::current()->resource_area());
- PointsTo(ptset, base, phase);
+ PointsTo(ptset, base);
for( VectorSetI i(&ptset); i.test(); ++i ) {
uint pt = i.elem;
add_field_edge(pt, n_idx, address_offset(n, phase));
@@ -2501,7 +2527,7 @@
// For everything "adr_base" could point to, create a deferred edge from
// this node to each field with the same offset.
VectorSet ptset(Thread::current()->resource_area());
- PointsTo(ptset, adr_base, phase);
+ PointsTo(ptset, adr_base);
int offset = address_offset(adr, phase);
for( VectorSetI i(&ptset); i.test(); ++i ) {
uint pt = i.elem;
@@ -2594,7 +2620,7 @@
// For everything "adr_base" could point to, create a deferred edge
// to "val" from each field with the same offset.
VectorSet ptset(Thread::current()->resource_area());
- PointsTo(ptset, adr_base, phase);
+ PointsTo(ptset, adr_base);
for( VectorSetI i(&ptset); i.test(); ++i ) {
uint pt = i.elem;
add_edge_from_fields(pt, val->_idx, address_offset(adr, phase));
@@ -2638,7 +2664,6 @@
#ifndef PRODUCT
void ConnectionGraph::dump() {
- PhaseGVN *igvn = _compile->initial_gvn();
bool first = true;
uint size = nodes_size();
@@ -2648,7 +2673,7 @@
if (ptn_type != PointsToNode::JavaObject || ptn->_node == NULL)
continue;
- PointsToNode::EscapeState es = escape_state(ptn->_node, igvn);
+ PointsToNode::EscapeState es = escape_state(ptn->_node);
if (ptn->_node->is_Allocate() && (es == PointsToNode::NoEscape || Verbose)) {
if (first) {
tty->cr();
--- a/hotspot/src/share/vm/opto/escape.hpp Fri Jul 02 15:01:47 2010 -0700
+++ b/hotspot/src/share/vm/opto/escape.hpp Fri Jul 02 17:30:30 2010 -0700
@@ -227,6 +227,7 @@
uint _noop_null; // ConN(#NULL)
Compile * _compile; // Compile object for current compilation
+ PhaseIterGVN * _igvn; // Value numbering
// Address of an element in _nodes. Used when the element is to be modified
PointsToNode *ptnode_adr(uint idx) const {
@@ -257,7 +258,7 @@
// walk the connection graph starting at the node corresponding to "n" and
// add the index of everything it could point to, to "ptset". This may cause
// Phi's encountered to get (re)processed (which requires "phase".)
- void PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase);
+ void PointsTo(VectorSet &ptset, Node * n);
// Edge manipulation. The "from_i" and "to_i" arguments are the
// node indices of the source and destination of the edge
@@ -310,7 +311,7 @@
// Node: This assumes that escape analysis is run before
// PhaseIterGVN creation
void record_for_optimizer(Node *n) {
- _compile->record_for_igvn(n);
+ _igvn->_worklist.push(n);
}
// Set the escape state of a node
@@ -320,16 +321,20 @@
void verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase);
public:
- ConnectionGraph(Compile *C);
+ ConnectionGraph(Compile *C, PhaseIterGVN *igvn);
// Check for non-escaping candidates
static bool has_candidates(Compile *C);
+ // Perform escape analysis
+ static void do_analysis(Compile *C, PhaseIterGVN *igvn);
+
// Compute the escape information
bool compute_escape();
// escape state of a node
- PointsToNode::EscapeState escape_state(Node *n, PhaseTransform *phase);
+ PointsToNode::EscapeState escape_state(Node *n);
+
// other information we have collected
bool is_scalar_replaceable(Node *n) {
if (_collecting || (n->_idx >= nodes_size()))