Mercurial > hg > graal-jvmci-8
comparison src/share/vm/opto/escape.cpp @ 4113:8c57262447d3
7105605: Use EA info to optimize pointers compare
Summary: optimize pointers compare using EA information.
Reviewed-by: never, twisti
author | kvn |
---|---|
date | Mon, 14 Nov 2011 18:38:03 -0800 |
parents | 59e515ee9354 |
children | 1bd45abaa507 |
comparison
equal
deleted
inserted
replaced
4112:e8fdaf4a66cb | 4113:8c57262447d3 |
---|---|
117 assert(_noop_null < nodes_size(), "should be created already"); | 117 assert(_noop_null < nodes_size(), "should be created already"); |
118 add_node(noop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true); | 118 add_node(noop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true); |
119 } else { | 119 } else { |
120 _noop_null = _oop_null; // Should be initialized | 120 _noop_null = _oop_null; // Should be initialized |
121 } | 121 } |
122 _pcmp_neq = NULL; // Should be initialized | |
123 _pcmp_eq = NULL; | |
122 } | 124 } |
123 | 125 |
124 void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) { | 126 void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) { |
125 PointsToNode *f = ptnode_adr(from_i); | 127 PointsToNode *f = ptnode_adr(from_i); |
126 PointsToNode *t = ptnode_adr(to_i); | 128 PointsToNode *t = ptnode_adr(to_i); |
307 deferred_edges->clear(); | 309 deferred_edges->clear(); |
308 visited->Reset(); | 310 visited->Reset(); |
309 | 311 |
310 visited->set(ni); | 312 visited->set(ni); |
311 PointsToNode *ptn = ptnode_adr(ni); | 313 PointsToNode *ptn = ptnode_adr(ni); |
314 if (ptn->edge_count() == 0) { | |
315 // No deferred or pointsto edges found. Assume the value was set | |
316 // outside this method. Add edge to phantom object. | |
317 add_pointsto_edge(ni, _phantom_object); | |
318 } | |
312 | 319 |
313 // Mark current edges as visited and move deferred edges to separate array. | 320 // Mark current edges as visited and move deferred edges to separate array. |
314 for (uint i = 0; i < ptn->edge_count(); ) { | 321 for (uint i = 0; i < ptn->edge_count(); ) { |
315 uint t = ptn->edge_target(i); | 322 uint t = ptn->edge_target(i); |
316 #ifdef ASSERT | 323 #ifdef ASSERT |
327 } | 334 } |
328 for (int next = 0; next < deferred_edges->length(); ++next) { | 335 for (int next = 0; next < deferred_edges->length(); ++next) { |
329 uint t = deferred_edges->at(next); | 336 uint t = deferred_edges->at(next); |
330 PointsToNode *ptt = ptnode_adr(t); | 337 PointsToNode *ptt = ptnode_adr(t); |
331 uint e_cnt = ptt->edge_count(); | 338 uint e_cnt = ptt->edge_count(); |
339 if (e_cnt == 0) { | |
340 // No deferred or pointsto edges found. Assume the value was set | |
341 // outside this method. Add edge to phantom object. | |
342 add_pointsto_edge(t, _phantom_object); | |
343 add_pointsto_edge(ni, _phantom_object); | |
344 } | |
332 for (uint e = 0; e < e_cnt; e++) { | 345 for (uint e = 0; e < e_cnt; e++) { |
333 uint etgt = ptt->edge_target(e); | 346 uint etgt = ptt->edge_target(e); |
334 if (visited->test_set(etgt)) | 347 if (visited->test_set(etgt)) |
335 continue; | 348 continue; |
336 | 349 |
390 } | 403 } |
391 if (offset == offs || offset == Type::OffsetBot || offs == Type::OffsetBot) { | 404 if (offset == offs || offset == Type::OffsetBot || offs == Type::OffsetBot) { |
392 add_deferred_edge(from_i, fi); | 405 add_deferred_edge(from_i, fi); |
393 } | 406 } |
394 } | 407 } |
408 // Some fields references (AddP) may still be missing | |
409 // until Connection Graph construction is complete. | |
410 // For example, loads from RAW pointers with offset 0 | |
411 // which don't have AddP. | |
412 // A reference to phantom_object will be added if | |
413 // a field reference is still missing after completing | |
414 // Connection Graph (see remove_deferred()). | |
395 } | 415 } |
396 | 416 |
397 // Helper functions | 417 // Helper functions |
398 | 418 |
399 static Node* get_addp_base(Node *addp) { | 419 static Node* get_addp_base(Node *addp) { |
1538 worklist_init.push(C->root()); | 1558 worklist_init.push(C->root()); |
1539 } | 1559 } |
1540 | 1560 |
1541 GrowableArray<Node*> alloc_worklist; | 1561 GrowableArray<Node*> alloc_worklist; |
1542 GrowableArray<Node*> addp_worklist; | 1562 GrowableArray<Node*> addp_worklist; |
1563 GrowableArray<Node*> ptr_cmp_worklist; | |
1543 PhaseGVN* igvn = _igvn; | 1564 PhaseGVN* igvn = _igvn; |
1544 bool has_allocations = false; | 1565 bool has_allocations = false; |
1545 | 1566 |
1546 // Push all useful nodes onto CG list and set their type. | 1567 // Push all useful nodes onto CG list and set their type. |
1547 for( uint next = 0; next < worklist_init.size(); ++next ) { | 1568 for( uint next = 0; next < worklist_init.size(); ++next ) { |
1552 if (n->is_Allocate() || n->is_CallStaticJava() && | 1573 if (n->is_Allocate() || n->is_CallStaticJava() && |
1553 ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) { | 1574 ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) { |
1554 has_allocations = true; | 1575 has_allocations = true; |
1555 if (n->is_Allocate()) | 1576 if (n->is_Allocate()) |
1556 alloc_worklist.append(n); | 1577 alloc_worklist.append(n); |
1557 } | 1578 } else if(n->is_AddP()) { |
1558 if(n->is_AddP()) { | |
1559 // Collect address nodes. Use them during stage 3 below | 1579 // Collect address nodes. Use them during stage 3 below |
1560 // to build initial connection graph field edges. | 1580 // to build initial connection graph field edges. |
1561 addp_worklist.append(n); | 1581 addp_worklist.append(n); |
1562 } else if (n->is_MergeMem()) { | 1582 } else if (n->is_MergeMem()) { |
1563 // Collect all MergeMem nodes to add memory slices for | 1583 // Collect all MergeMem nodes to add memory slices for |
1564 // scalar replaceable objects in split_unique_types(). | 1584 // scalar replaceable objects in split_unique_types(). |
1565 _mergemem_worklist.append(n->as_MergeMem()); | 1585 _mergemem_worklist.append(n->as_MergeMem()); |
1586 } else if (OptimizePtrCompare && n->is_Cmp() && | |
1587 (n->Opcode() == Op_CmpP || n->Opcode() == Op_CmpN)) { | |
1588 // Compare pointers nodes | |
1589 ptr_cmp_worklist.append(n); | |
1566 } | 1590 } |
1567 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { | 1591 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
1568 Node* m = n->fast_out(i); // Get user | 1592 Node* m = n->fast_out(i); // Get user |
1569 worklist_init.push(m); | 1593 worklist_init.push(m); |
1570 } | 1594 } |
1586 // to reduce number of iterations during stage 4 below. | 1610 // to reduce number of iterations during stage 4 below. |
1587 uint addp_length = addp_worklist.length(); | 1611 uint addp_length = addp_worklist.length(); |
1588 for( uint next = 0; next < addp_length; ++next ) { | 1612 for( uint next = 0; next < addp_length; ++next ) { |
1589 Node* n = addp_worklist.at(next); | 1613 Node* n = addp_worklist.at(next); |
1590 Node* base = get_addp_base(n); | 1614 Node* base = get_addp_base(n); |
1591 if (base->is_Proj()) | 1615 if (base->is_Proj() && base->in(0)->is_Call()) |
1592 base = base->in(0); | 1616 base = base->in(0); |
1593 PointsToNode::NodeType nt = ptnode_adr(base->_idx)->node_type(); | 1617 PointsToNode::NodeType nt = ptnode_adr(base->_idx)->node_type(); |
1594 if (nt == PointsToNode::JavaObject) { | 1618 if (nt == PointsToNode::JavaObject) { |
1595 build_connection_graph(n, igvn); | 1619 build_connection_graph(n, igvn); |
1596 } | 1620 } |
1673 int ni = cg_worklist.at(next); | 1697 int ni = cg_worklist.at(next); |
1674 PointsToNode* ptn = ptnode_adr(ni); | 1698 PointsToNode* ptn = ptnode_adr(ni); |
1675 PointsToNode::NodeType nt = ptn->node_type(); | 1699 PointsToNode::NodeType nt = ptn->node_type(); |
1676 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { | 1700 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { |
1677 remove_deferred(ni, &worklist, &visited); | 1701 remove_deferred(ni, &worklist, &visited); |
1678 Node *n = ptn->_node; | |
1679 } | 1702 } |
1680 } | 1703 } |
1681 | 1704 |
1682 // 7. Adjust escape state of nonescaping objects. | 1705 // 7. Adjust escape state of nonescaping objects. |
1683 for (uint next = 0; next < addp_length; ++next) { | 1706 for (uint next = 0; next < addp_length; ++next) { |
1757 alock->set_eliminated(); | 1780 alock->set_eliminated(); |
1758 } | 1781 } |
1759 } | 1782 } |
1760 } | 1783 } |
1761 } | 1784 } |
1785 } | |
1786 | |
1787 if (OptimizePtrCompare && has_non_escaping_obj) { | |
1788 // Add ConI(#CC_GT) and ConI(#CC_EQ). | |
1789 _pcmp_neq = igvn->makecon(TypeInt::CC_GT); | |
1790 _pcmp_eq = igvn->makecon(TypeInt::CC_EQ); | |
1791 // Optimize objects compare. | |
1792 while (ptr_cmp_worklist.length() != 0) { | |
1793 Node *n = ptr_cmp_worklist.pop(); | |
1794 Node *res = optimize_ptr_compare(n); | |
1795 if (res != NULL) { | |
1796 #ifndef PRODUCT | |
1797 if (PrintOptimizePtrCompare) { | |
1798 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")); | |
1799 if (Verbose) { | |
1800 n->dump(1); | |
1801 } | |
1802 } | |
1803 #endif | |
1804 _igvn->replace_node(n, res); | |
1805 } | |
1806 } | |
1807 // cleanup | |
1808 if (_pcmp_neq->outcnt() == 0) | |
1809 igvn->hash_delete(_pcmp_neq); | |
1810 if (_pcmp_eq->outcnt() == 0) | |
1811 igvn->hash_delete(_pcmp_eq); | |
1762 } | 1812 } |
1763 | 1813 |
1764 #ifndef PRODUCT | 1814 #ifndef PRODUCT |
1765 if (PrintEscapeAnalysis) { | 1815 if (PrintEscapeAnalysis) { |
1766 dump(); // Dump ConnectionGraph | 1816 dump(); // Dump ConnectionGraph |
2006 } | 2056 } |
2007 // Has not escaping java objects | 2057 // Has not escaping java objects |
2008 return has_java_obj && (esc_state < PointsToNode::GlobalEscape); | 2058 return has_java_obj && (esc_state < PointsToNode::GlobalEscape); |
2009 } | 2059 } |
2010 | 2060 |
2061 // Optimize objects compare. | |
2062 Node* ConnectionGraph::optimize_ptr_compare(Node* n) { | |
2063 assert(OptimizePtrCompare, "sanity"); | |
2064 // Clone returned Set since PointsTo() returns pointer | |
2065 // to the same structure ConnectionGraph.pt_ptset. | |
2066 VectorSet ptset1 = *PointsTo(n->in(1)); | |
2067 VectorSet ptset2 = *PointsTo(n->in(2)); | |
2068 | |
2069 // Check simple cases first. | |
2070 if (ptset1.Size() == 1) { | |
2071 uint pt1 = ptset1.getelem(); | |
2072 PointsToNode* ptn1 = ptnode_adr(pt1); | |
2073 if (ptn1->escape_state() == PointsToNode::NoEscape) { | |
2074 if (ptset2.Size() == 1 && ptset2.getelem() == pt1) { | |
2075 // Comparing the same not escaping object. | |
2076 return _pcmp_eq; | |
2077 } | |
2078 Node* obj = ptn1->_node; | |
2079 // Comparing not escaping allocation. | |
2080 if ((obj->is_Allocate() || obj->is_CallStaticJava()) && | |
2081 !ptset2.test(pt1)) { | |
2082 return _pcmp_neq; // This includes nullness check. | |
2083 } | |
2084 } | |
2085 } else if (ptset2.Size() == 1) { | |
2086 uint pt2 = ptset2.getelem(); | |
2087 PointsToNode* ptn2 = ptnode_adr(pt2); | |
2088 if (ptn2->escape_state() == PointsToNode::NoEscape) { | |
2089 Node* obj = ptn2->_node; | |
2090 // Comparing not escaping allocation. | |
2091 if ((obj->is_Allocate() || obj->is_CallStaticJava()) && | |
2092 !ptset1.test(pt2)) { | |
2093 return _pcmp_neq; // This includes nullness check. | |
2094 } | |
2095 } | |
2096 } | |
2097 | |
2098 if (!ptset1.disjoint(ptset2)) { | |
2099 return NULL; // Sets are not disjoint | |
2100 } | |
2101 | |
2102 // Sets are disjoint. | |
2103 bool set1_has_unknown_ptr = ptset1.test(_phantom_object) != 0; | |
2104 bool set2_has_unknown_ptr = ptset2.test(_phantom_object) != 0; | |
2105 bool set1_has_null_ptr = (ptset1.test(_oop_null) | ptset1.test(_noop_null)) != 0; | |
2106 bool set2_has_null_ptr = (ptset2.test(_oop_null) | ptset2.test(_noop_null)) != 0; | |
2107 | |
2108 if (set1_has_unknown_ptr && set2_has_null_ptr || | |
2109 set2_has_unknown_ptr && set1_has_null_ptr) { | |
2110 // Check nullness of unknown object. | |
2111 return NULL; | |
2112 } | |
2113 | |
2114 // Disjointness by itself is not sufficient since | |
2115 // alias analysis is not complete for escaped objects. | |
2116 // Disjoint sets are definitely unrelated only when | |
2117 // at least one set has only not escaping objects. | |
2118 if (!set1_has_unknown_ptr && !set1_has_null_ptr) { | |
2119 bool has_only_non_escaping_alloc = true; | |
2120 for (VectorSetI i(&ptset1); i.test(); ++i) { | |
2121 uint pt = i.elem; | |
2122 PointsToNode* ptn = ptnode_adr(pt); | |
2123 Node* obj = ptn->_node; | |
2124 if (ptn->escape_state() != PointsToNode::NoEscape || | |
2125 !(obj->is_Allocate() || obj->is_CallStaticJava())) { | |
2126 has_only_non_escaping_alloc = false; | |
2127 break; | |
2128 } | |
2129 } | |
2130 if (has_only_non_escaping_alloc) { | |
2131 return _pcmp_neq; | |
2132 } | |
2133 } | |
2134 if (!set2_has_unknown_ptr && !set2_has_null_ptr) { | |
2135 bool has_only_non_escaping_alloc = true; | |
2136 for (VectorSetI i(&ptset2); i.test(); ++i) { | |
2137 uint pt = i.elem; | |
2138 PointsToNode* ptn = ptnode_adr(pt); | |
2139 Node* obj = ptn->_node; | |
2140 if (ptn->escape_state() != PointsToNode::NoEscape || | |
2141 !(obj->is_Allocate() || obj->is_CallStaticJava())) { | |
2142 has_only_non_escaping_alloc = false; | |
2143 break; | |
2144 } | |
2145 } | |
2146 if (has_only_non_escaping_alloc) { | |
2147 return _pcmp_neq; | |
2148 } | |
2149 } | |
2150 return NULL; | |
2151 } | |
2152 | |
2011 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { | 2153 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { |
2012 | 2154 |
2013 switch (call->Opcode()) { | 2155 switch (call->Opcode()) { |
2014 #ifdef ASSERT | 2156 #ifdef ASSERT |
2015 case Op_Allocate: | 2157 case Op_Allocate: |
2429 // We have to assume all input parameters globally escape | 2571 // We have to assume all input parameters globally escape |
2430 // (Note: passing 'false' since _processed is already set). | 2572 // (Note: passing 'false' since _processed is already set). |
2431 add_node(n, PointsToNode::JavaObject, PointsToNode::GlobalEscape, false); | 2573 add_node(n, PointsToNode::JavaObject, PointsToNode::GlobalEscape, false); |
2432 break; | 2574 break; |
2433 } | 2575 } |
2576 case Op_PartialSubtypeCheck: | |
2577 { // Produces Null or notNull and is used in CmpP. | |
2578 add_node(n, PointsToNode::JavaObject, PointsToNode::ArgEscape, true); | |
2579 break; | |
2580 } | |
2434 case Op_Phi: | 2581 case Op_Phi: |
2435 { | 2582 { |
2436 const Type *t = n->as_Phi()->type(); | 2583 const Type *t = n->as_Phi()->type(); |
2437 if (t->make_ptr() == NULL) { | 2584 if (t->make_ptr() == NULL) { |
2438 // nothing to do if not an oop or narrow oop | 2585 // nothing to do if not an oop or narrow oop |
2587 | 2734 |
2588 switch (n->Opcode()) { | 2735 switch (n->Opcode()) { |
2589 case Op_AddP: | 2736 case Op_AddP: |
2590 { | 2737 { |
2591 Node *base = get_addp_base(n); | 2738 Node *base = get_addp_base(n); |
2739 int offset = address_offset(n, phase); | |
2592 // Create a field edge to this node from everything base could point to. | 2740 // Create a field edge to this node from everything base could point to. |
2593 for( VectorSetI i(PointsTo(base)); i.test(); ++i ) { | 2741 for( VectorSetI i(PointsTo(base)); i.test(); ++i ) { |
2594 uint pt = i.elem; | 2742 uint pt = i.elem; |
2595 add_field_edge(pt, n_idx, address_offset(n, phase)); | 2743 add_field_edge(pt, n_idx, offset); |
2596 } | 2744 } |
2597 break; | 2745 break; |
2598 } | 2746 } |
2599 case Op_CastX2P: | 2747 case Op_CastX2P: |
2600 { | 2748 { |
2657 // For everything "adr_base" could point to, create a deferred edge from | 2805 // For everything "adr_base" could point to, create a deferred edge from |
2658 // this node to each field with the same offset. | 2806 // this node to each field with the same offset. |
2659 int offset = address_offset(adr, phase); | 2807 int offset = address_offset(adr, phase); |
2660 for( VectorSetI i(PointsTo(adr_base)); i.test(); ++i ) { | 2808 for( VectorSetI i(PointsTo(adr_base)); i.test(); ++i ) { |
2661 uint pt = i.elem; | 2809 uint pt = i.elem; |
2810 if (adr->is_AddP()) { | |
2811 // Add field edge if it is missing. | |
2812 add_field_edge(pt, adr->_idx, offset); | |
2813 } | |
2662 add_deferred_edge_to_fields(n_idx, pt, offset); | 2814 add_deferred_edge_to_fields(n_idx, pt, offset); |
2663 } | 2815 } |
2664 break; | 2816 break; |
2665 } | 2817 } |
2666 case Op_Parm: | 2818 case Op_Parm: |
2667 { | 2819 { |
2668 assert(false, "Op_Parm"); | 2820 assert(false, "Op_Parm"); |
2821 break; | |
2822 } | |
2823 case Op_PartialSubtypeCheck: | |
2824 { | |
2825 assert(false, "Op_PartialSubtypeCheck"); | |
2669 break; | 2826 break; |
2670 } | 2827 } |
2671 case Op_Phi: | 2828 case Op_Phi: |
2672 { | 2829 { |
2673 #ifdef ASSERT | 2830 #ifdef ASSERT |
2743 #endif | 2900 #endif |
2744 | 2901 |
2745 assert(adr->is_AddP(), "expecting an AddP"); | 2902 assert(adr->is_AddP(), "expecting an AddP"); |
2746 Node *adr_base = get_addp_base(adr); | 2903 Node *adr_base = get_addp_base(adr); |
2747 Node *val = n->in(MemNode::ValueIn)->uncast(); | 2904 Node *val = n->in(MemNode::ValueIn)->uncast(); |
2905 int offset = address_offset(adr, phase); | |
2748 // For everything "adr_base" could point to, create a deferred edge | 2906 // For everything "adr_base" could point to, create a deferred edge |
2749 // to "val" from each field with the same offset. | 2907 // to "val" from each field with the same offset. |
2750 for( VectorSetI i(PointsTo(adr_base)); i.test(); ++i ) { | 2908 for( VectorSetI i(PointsTo(adr_base)); i.test(); ++i ) { |
2751 uint pt = i.elem; | 2909 uint pt = i.elem; |
2752 add_edge_from_fields(pt, val->_idx, address_offset(adr, phase)); | 2910 // Add field edge if it is missing. |
2911 add_field_edge(pt, adr->_idx, offset); | |
2912 add_edge_from_fields(pt, val->_idx, offset); | |
2753 } | 2913 } |
2754 break; | 2914 break; |
2755 } | 2915 } |
2756 case Op_AryEq: | 2916 case Op_AryEq: |
2757 case Op_StrComp: | 2917 case Op_StrComp: |