src/share/vm/opto/escape.cpp
Index
Unified diffs
Context diffs
Sdiffs
Wdiffs
Patch
New
Old
Previous File
Next File
7105605 Cdiff src/share/vm/opto/escape.cpp
src/share/vm/opto/escape.cpp
Print this page
*** 117,126 ****
--- 117,137 ----
assert(_noop_null < nodes_size(), "should be created already");
add_node(noop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true);
} else {
_noop_null = _oop_null; // Should be initialized
}
+ if (OptimizePtrCompare) {
+ // Add ConI(#CC_GT) and ConI(#CC_EQ).
+ _pcmp_neq = igvn->makecon(TypeInt::CC_GT);
+ assert(_pcmp_neq->_idx < C->unique(), "should be created already");
+
+ _pcmp_eq = igvn->makecon(TypeInt::CC_EQ);
+ assert(_pcmp_eq->_idx < C->unique(), "should be created already");
+ } else {
+ _pcmp_neq = NULL; // Should be initialized
+ _pcmp_eq = NULL;
+ }
}
void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) {
PointsToNode *f = ptnode_adr(from_i);
PointsToNode *t = ptnode_adr(to_i);
*** 1509,1518 ****
--- 1520,1533 ----
// 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);
+ // Add ConI(#CC_GT) and ConI(#CC_EQ) if needed.
+ Node* pcmp_neq = OptimizePtrCompare ? igvn->makecon(TypeInt::CC_GT) : NULL;
+ Node* pcmp_eq = OptimizePtrCompare ? igvn->makecon(TypeInt::CC_EQ) : NULL;
+
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);
*** 1521,1530 ****
--- 1536,1549 ----
// Cleanup.
if (oop_null->outcnt() == 0)
igvn->hash_delete(oop_null);
if (noop_null->outcnt() == 0)
igvn->hash_delete(noop_null);
+ if (pcmp_neq != NULL && pcmp_neq->outcnt() == 0)
+ igvn->hash_delete(pcmp_neq);
+ if (pcmp_eq != NULL && pcmp_eq->outcnt() == 0)
+ igvn->hash_delete(pcmp_eq);
}
bool ConnectionGraph::compute_escape() {
Compile* C = _compile;
*** 1538,1547 ****
--- 1557,1567 ----
worklist_init.push(C->root());
}
GrowableArray<Node*> alloc_worklist;
GrowableArray<Node*> addp_worklist;
+ GrowableArray<Node*> ptr_cmp_worklist;
PhaseGVN* igvn = _igvn;
bool has_allocations = false;
// Push all useful nodes onto CG list and set their type.
for( uint next = 0; next < worklist_init.size(); ++next ) {
*** 1552,1570 ****
if (n->is_Allocate() || n->is_CallStaticJava() &&
ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) {
has_allocations = true;
if (n->is_Allocate())
alloc_worklist.append(n);
! }
! if(n->is_AddP()) {
// Collect address nodes. Use them during stage 3 below
// to build initial connection graph field edges.
addp_worklist.append(n);
} else if (n->is_MergeMem()) {
// Collect all MergeMem nodes to add memory slices for
// scalar replaceable objects in split_unique_types().
_mergemem_worklist.append(n->as_MergeMem());
}
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node* m = n->fast_out(i); // Get user
worklist_init.push(m);
}
--- 1572,1593 ----
if (n->is_Allocate() || n->is_CallStaticJava() &&
ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) {
has_allocations = true;
if (n->is_Allocate())
alloc_worklist.append(n);
! } else if(n->is_AddP()) {
// Collect address nodes. Use them during stage 3 below
// to build initial connection graph field edges.
addp_worklist.append(n);
} else if (n->is_MergeMem()) {
// Collect all MergeMem nodes to add memory slices for
// scalar replaceable objects in split_unique_types().
_mergemem_worklist.append(n->as_MergeMem());
+ } else if (OptimizePtrCompare && n->is_Cmp() &&
+ (n->Opcode() == Op_CmpP || n->Opcode() == Op_CmpN)) {
+ // Compare pointers nodes
+ ptr_cmp_worklist.append(n);
}
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node* m = n->fast_out(i); // Get user
worklist_init.push(m);
}
*** 1759,1769 ****
--- 1782,1811 ----
}
}
}
}
+ if (OptimizePtrCompare && has_non_escaping_obj) {
+ // Optimize objects compare.
+ while (ptr_cmp_worklist.length() != 0) {
+ Node *n = ptr_cmp_worklist.pop();
+ Node *res = optimize_ptr_compare(n);
+ if (res != NULL) {
#ifndef PRODUCT
+ if (PrintOptimizePtrCompare) {
+ tty->print_cr("++++ Replaced: %d %s(%d,%d) --> %s", n->_idx, (n->Opcode() == Op_CmpP ? "CmpP" : "CmpN"), n->in(1)->_idx, n->in(2)->_idx, (res == _pcmp_eq ? "EQ" : "NotEQ"));
+ if (Verbose) {
+ n->dump(1);
+ }
+ }
+ #endif
+ _igvn->replace_node(n, res);
+ }
+ }
+ }
+
+ #ifndef PRODUCT
if (PrintEscapeAnalysis) {
dump(); // Dump ConnectionGraph
}
#endif
*** 2006,2015 ****
--- 2048,2148 ----
}
// Has not escaping java objects
return has_java_obj && (esc_state < PointsToNode::GlobalEscape);
}
+ // Optimize objects compare.
+ Node* ConnectionGraph::optimize_ptr_compare(Node* n) {
+ assert(OptimizePtrCompare, "sanity");
+ // Clone returned Set since PointsTo() returns pointer
+ // to the same structure ConnectionGraph.pt_ptset.
+ VectorSet ptset1 = *PointsTo(n->in(1));
+ VectorSet ptset2 = *PointsTo(n->in(2));
+
+ // Check simple cases first.
+ if (ptset1.Size() == 1) {
+ uint pt1 = ptset1.getelem();
+ PointsToNode* ptn1 = ptnode_adr(pt1);
+ if (ptn1->escape_state() == PointsToNode::NoEscape) {
+ uint pt2 = ptset2.getelem();
+ if (ptset2.Size() == 1 && ptset2.getelem() == pt1) {
+ // Comparing the same not escaping object.
+ return _pcmp_eq;
+ }
+ Node* obj = ptn1->_node;
+ // Comparing not escaping allocation.
+ if ((obj->is_Allocate() || obj->is_CallStaticJava()) &&
+ !ptset2.test(pt1)) {
+ return _pcmp_neq; // This includes nullness check.
+ }
+ }
+ } else if (ptset2.Size() == 1) {
+ uint pt2 = ptset2.getelem();
+ PointsToNode* ptn2 = ptnode_adr(pt2);
+ if (ptn2->escape_state() == PointsToNode::NoEscape) {
+ Node* obj = ptn2->_node;
+ // Comparing not escaping allocation.
+ if ((obj->is_Allocate() || obj->is_CallStaticJava()) &&
+ !ptset1.test(pt2)) {
+ return _pcmp_neq; // This includes nullness check.
+ }
+ }
+ }
+
+ if (!ptset1.disjoint(ptset2)) {
+ // References point to the same object and something else.
+ return NULL;
+ }
+
+ bool set1_has_unknown_ptr = ptset1.test(_phantom_object) != 0;
+ bool set2_has_unknown_ptr = ptset2.test(_phantom_object) != 0;
+ bool set1_has_null_ptr = (ptset1.test(_oop_null) | ptset1.test(_noop_null)) != 0;
+ bool set2_has_null_ptr = (ptset2.test(_oop_null) | ptset2.test(_noop_null)) != 0;
+
+ if (set1_has_unknown_ptr && set2_has_unknown_ptr ||
+ set1_has_unknown_ptr && set2_has_null_ptr ||
+ set2_has_unknown_ptr && set1_has_null_ptr) {
+ // Comparing unknown objects or check nullness of unknown object.
+ return NULL;
+ }
+
+ // Check if one set has only not escaping allocations.
+ if (!set1_has_unknown_ptr && !set1_has_null_ptr) {
+ bool has_only_non_escaping_alloc = true;
+ for (VectorSetI i(&ptset1); i.test(); ++i) {
+ uint pt = i.elem;
+ PointsToNode* ptn = ptnode_adr(pt);
+ Node* obj = ptn->_node;
+ if (ptn->escape_state() != PointsToNode::NoEscape ||
+ !(obj->is_Allocate() || obj->is_CallStaticJava())) {
+ has_only_non_escaping_alloc = false;
+ break;
+ }
+ }
+ if (has_only_non_escaping_alloc) {
+ return _pcmp_neq;
+ }
+ }
+ if (!set2_has_unknown_ptr && !set2_has_null_ptr) {
+ bool has_only_non_escaping_alloc = true;
+ for (VectorSetI i(&ptset2); i.test(); ++i) {
+ uint pt = i.elem;
+ PointsToNode* ptn = ptnode_adr(pt);
+ Node* obj = ptn->_node;
+ if (ptn->escape_state() != PointsToNode::NoEscape ||
+ !(obj->is_Allocate() || obj->is_CallStaticJava())) {
+ has_only_non_escaping_alloc = false;
+ break;
+ }
+ }
+ if (has_only_non_escaping_alloc) {
+ return _pcmp_neq;
+ }
+ }
+ return NULL;
+ }
+
void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) {
switch (call->Opcode()) {
#ifdef ASSERT
case Op_Allocate:
*** 2429,2438 ****
--- 2562,2576 ----
// We have to assume all input parameters globally escape
// (Note: passing 'false' since _processed is already set).
add_node(n, PointsToNode::JavaObject, PointsToNode::GlobalEscape, false);
break;
}
+ case Op_PartialSubtypeCheck:
+ { // Produces Null or notNull and is used in CmpP.
+ add_node(n, PointsToNode::JavaObject, PointsToNode::ArgEscape, true);
+ break;
+ }
case Op_Phi:
{
const Type *t = n->as_Phi()->type();
if (t->make_ptr() == NULL) {
// nothing to do if not an oop or narrow oop
*** 2666,2675 ****
--- 2804,2818 ----
case Op_Parm:
{
assert(false, "Op_Parm");
break;
}
+ case Op_PartialSubtypeCheck:
+ {
+ assert(false, "Op_PartialSubtypeCheck");
+ break;
+ }
case Op_Phi:
{
#ifdef ASSERT
const Type *t = n->as_Phi()->type();
if (t->make_ptr() == NULL)
src/share/vm/opto/escape.cpp
Index
Unified diffs
Context diffs
Sdiffs
Wdiffs
Patch
New
Old
Previous File
Next File