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