Mercurial > hg > truffle
comparison src/share/vm/opto/escape.cpp @ 1634:60a14ad85270
6966411: escape.cpp:450 assert(base->Opcode() == Op_ConP
Summary: Execute IGVN optimization before and after Escape Analysis
Reviewed-by: never
author | kvn |
---|---|
date | Fri, 02 Jul 2010 17:30:30 -0700 |
parents | c18cbe5936b8 |
children | 5867d89c129b |
comparison
equal
deleted
inserted
replaced
1633:65b0c03b165d | 1634:60a14ad85270 |
---|---|
79 else | 79 else |
80 _node->dump(); | 80 _node->dump(); |
81 } | 81 } |
82 #endif | 82 #endif |
83 | 83 |
84 ConnectionGraph::ConnectionGraph(Compile * C) : | 84 ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) : |
85 _nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()), | 85 _nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()), |
86 _processed(C->comp_arena()), | 86 _processed(C->comp_arena()), |
87 _collecting(true), | 87 _collecting(true), |
88 _compile(C), | 88 _compile(C), |
89 _igvn(igvn), | |
89 _node_map(C->comp_arena()) { | 90 _node_map(C->comp_arena()) { |
90 | 91 |
91 _phantom_object = C->top()->_idx, | 92 _phantom_object = C->top()->_idx, |
92 add_node(C->top(), PointsToNode::JavaObject, PointsToNode::GlobalEscape,true); | 93 add_node(C->top(), PointsToNode::JavaObject, PointsToNode::GlobalEscape,true); |
93 | 94 |
94 // Add ConP(#NULL) and ConN(#NULL) nodes. | 95 // Add ConP(#NULL) and ConN(#NULL) nodes. |
95 PhaseGVN* igvn = C->initial_gvn(); | |
96 Node* oop_null = igvn->zerocon(T_OBJECT); | 96 Node* oop_null = igvn->zerocon(T_OBJECT); |
97 _oop_null = oop_null->_idx; | 97 _oop_null = oop_null->_idx; |
98 assert(_oop_null < C->unique(), "should be created already"); | 98 assert(_oop_null < C->unique(), "should be created already"); |
99 add_node(oop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true); | 99 add_node(oop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true); |
100 | 100 |
180 | 180 |
181 if (done) | 181 if (done) |
182 _processed.set(n->_idx); | 182 _processed.set(n->_idx); |
183 } | 183 } |
184 | 184 |
185 PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n, PhaseTransform *phase) { | 185 PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n) { |
186 uint idx = n->_idx; | 186 uint idx = n->_idx; |
187 PointsToNode::EscapeState es; | 187 PointsToNode::EscapeState es; |
188 | 188 |
189 // If we are still collecting or there were no non-escaping allocations | 189 // If we are still collecting or there were no non-escaping allocations |
190 // we don't know the answer yet | 190 // we don't know the answer yet |
205 | 205 |
206 // PointsTo() calls n->uncast() which can return a new ideal node. | 206 // PointsTo() calls n->uncast() which can return a new ideal node. |
207 if (n->uncast()->_idx >= nodes_size()) | 207 if (n->uncast()->_idx >= nodes_size()) |
208 return PointsToNode::UnknownEscape; | 208 return PointsToNode::UnknownEscape; |
209 | 209 |
210 PointsToNode::EscapeState orig_es = es; | |
211 | |
210 // compute max escape state of anything this node could point to | 212 // compute max escape state of anything this node could point to |
211 VectorSet ptset(Thread::current()->resource_area()); | 213 VectorSet ptset(Thread::current()->resource_area()); |
212 PointsTo(ptset, n, phase); | 214 PointsTo(ptset, n); |
213 for(VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i) { | 215 for(VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i) { |
214 uint pt = i.elem; | 216 uint pt = i.elem; |
215 PointsToNode::EscapeState pes = ptnode_adr(pt)->escape_state(); | 217 PointsToNode::EscapeState pes = ptnode_adr(pt)->escape_state(); |
216 if (pes > es) | 218 if (pes > es) |
217 es = pes; | 219 es = pes; |
218 } | 220 } |
219 // cache the computed escape state | 221 if (orig_es != es) { |
220 assert(es != PointsToNode::UnknownEscape, "should have computed an escape state"); | 222 // cache the computed escape state |
221 ptnode_adr(idx)->set_escape_state(es); | 223 assert(es != PointsToNode::UnknownEscape, "should have computed an escape state"); |
224 ptnode_adr(idx)->set_escape_state(es); | |
225 } // orig_es could be PointsToNode::UnknownEscape | |
222 return es; | 226 return es; |
223 } | 227 } |
224 | 228 |
225 void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase) { | 229 void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n) { |
226 VectorSet visited(Thread::current()->resource_area()); | 230 VectorSet visited(Thread::current()->resource_area()); |
227 GrowableArray<uint> worklist; | 231 GrowableArray<uint> worklist; |
228 | 232 |
229 #ifdef ASSERT | 233 #ifdef ASSERT |
230 Node *orig_n = n; | 234 Node *orig_n = n; |
988 // | 992 // |
989 void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) { | 993 void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) { |
990 GrowableArray<Node *> memnode_worklist; | 994 GrowableArray<Node *> memnode_worklist; |
991 GrowableArray<PhiNode *> orig_phis; | 995 GrowableArray<PhiNode *> orig_phis; |
992 | 996 |
993 PhaseGVN *igvn = _compile->initial_gvn(); | 997 PhaseGVN *igvn = _igvn; |
994 uint new_index_start = (uint) _compile->num_alias_types(); | 998 uint new_index_start = (uint) _compile->num_alias_types(); |
995 Arena* arena = Thread::current()->resource_area(); | 999 Arena* arena = Thread::current()->resource_area(); |
996 VectorSet visited(arena); | 1000 VectorSet visited(arena); |
997 VectorSet ptset(arena); | 1001 VectorSet ptset(arena); |
998 | 1002 |
1010 const TypeOopPtr* tinst = NULL; | 1014 const TypeOopPtr* tinst = NULL; |
1011 if (n->is_Call()) { | 1015 if (n->is_Call()) { |
1012 CallNode *alloc = n->as_Call(); | 1016 CallNode *alloc = n->as_Call(); |
1013 // copy escape information to call node | 1017 // copy escape information to call node |
1014 PointsToNode* ptn = ptnode_adr(alloc->_idx); | 1018 PointsToNode* ptn = ptnode_adr(alloc->_idx); |
1015 PointsToNode::EscapeState es = escape_state(alloc, igvn); | 1019 PointsToNode::EscapeState es = escape_state(alloc); |
1016 // We have an allocation or call which returns a Java object, | 1020 // We have an allocation or call which returns a Java object, |
1017 // see if it is unescaped. | 1021 // see if it is unescaped. |
1018 if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable) | 1022 if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable) |
1019 continue; | 1023 continue; |
1020 | 1024 |
1121 } | 1125 } |
1122 } | 1126 } |
1123 } | 1127 } |
1124 } else if (n->is_AddP()) { | 1128 } else if (n->is_AddP()) { |
1125 ptset.Clear(); | 1129 ptset.Clear(); |
1126 PointsTo(ptset, get_addp_base(n), igvn); | 1130 PointsTo(ptset, get_addp_base(n)); |
1127 assert(ptset.Size() == 1, "AddP address is unique"); | 1131 assert(ptset.Size() == 1, "AddP address is unique"); |
1128 uint elem = ptset.getelem(); // Allocation node's index | 1132 uint elem = ptset.getelem(); // Allocation node's index |
1129 if (elem == _phantom_object) { | 1133 if (elem == _phantom_object) { |
1130 assert(false, "escaped allocation"); | 1134 assert(false, "escaped allocation"); |
1131 continue; // Assume the value was set outside this method. | 1135 continue; // Assume the value was set outside this method. |
1141 if (visited.test_set(n->_idx)) { | 1145 if (visited.test_set(n->_idx)) { |
1142 assert(n->is_Phi(), "loops only through Phi's"); | 1146 assert(n->is_Phi(), "loops only through Phi's"); |
1143 continue; // already processed | 1147 continue; // already processed |
1144 } | 1148 } |
1145 ptset.Clear(); | 1149 ptset.Clear(); |
1146 PointsTo(ptset, n, igvn); | 1150 PointsTo(ptset, n); |
1147 if (ptset.Size() == 1) { | 1151 if (ptset.Size() == 1) { |
1148 uint elem = ptset.getelem(); // Allocation node's index | 1152 uint elem = ptset.getelem(); // Allocation node's index |
1149 if (elem == _phantom_object) { | 1153 if (elem == _phantom_object) { |
1150 assert(false, "escaped allocation"); | 1154 assert(false, "escaped allocation"); |
1151 continue; // Assume the value was set outside this method. | 1155 continue; // Assume the value was set outside this method. |
1476 } | 1480 } |
1477 } | 1481 } |
1478 return false; | 1482 return false; |
1479 } | 1483 } |
1480 | 1484 |
1485 void ConnectionGraph::do_analysis(Compile *C, PhaseIterGVN *igvn) { | |
1486 // Add ConP#NULL and ConN#NULL nodes before ConnectionGraph construction | |
1487 // to create space for them in ConnectionGraph::_nodes[]. | |
1488 Node* oop_null = igvn->zerocon(T_OBJECT); | |
1489 Node* noop_null = igvn->zerocon(T_NARROWOOP); | |
1490 | |
1491 ConnectionGraph* congraph = new(C->comp_arena()) ConnectionGraph(C, igvn); | |
1492 // Perform escape analysis | |
1493 if (congraph->compute_escape()) { | |
1494 // There are non escaping objects. | |
1495 C->set_congraph(congraph); | |
1496 } | |
1497 | |
1498 // Cleanup. | |
1499 if (oop_null->outcnt() == 0) | |
1500 igvn->hash_delete(oop_null); | |
1501 if (noop_null->outcnt() == 0) | |
1502 igvn->hash_delete(noop_null); | |
1503 } | |
1504 | |
1481 bool ConnectionGraph::compute_escape() { | 1505 bool ConnectionGraph::compute_escape() { |
1482 Compile* C = _compile; | 1506 Compile* C = _compile; |
1483 | 1507 |
1484 // 1. Populate Connection Graph (CG) with Ideal nodes. | 1508 // 1. Populate Connection Graph (CG) with Ideal nodes. |
1485 | 1509 |
1490 if (C->root() != NULL) { | 1514 if (C->root() != NULL) { |
1491 worklist_init.push(C->root()); | 1515 worklist_init.push(C->root()); |
1492 } | 1516 } |
1493 | 1517 |
1494 GrowableArray<int> cg_worklist; | 1518 GrowableArray<int> cg_worklist; |
1495 PhaseGVN* igvn = C->initial_gvn(); | 1519 PhaseGVN* igvn = _igvn; |
1496 bool has_allocations = false; | 1520 bool has_allocations = false; |
1497 | 1521 |
1498 // Push all useful nodes onto CG list and set their type. | 1522 // Push all useful nodes onto CG list and set their type. |
1499 for( uint next = 0; next < worklist_init.size(); ++next ) { | 1523 for( uint next = 0; next < worklist_init.size(); ++next ) { |
1500 Node* n = worklist_init.at(next); | 1524 Node* n = worklist_init.at(next); |
1659 } | 1683 } |
1660 | 1684 |
1661 _collecting = false; | 1685 _collecting = false; |
1662 assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build"); | 1686 assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build"); |
1663 | 1687 |
1688 #ifndef PRODUCT | |
1689 if (PrintEscapeAnalysis) { | |
1690 dump(); // Dump ConnectionGraph | |
1691 } | |
1692 #endif | |
1693 | |
1664 bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0; | 1694 bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0; |
1665 if ( has_scalar_replaceable_candidates && | 1695 if ( has_scalar_replaceable_candidates && |
1666 C->AliasLevel() >= 3 && EliminateAllocations ) { | 1696 C->AliasLevel() >= 3 && EliminateAllocations ) { |
1667 | 1697 |
1668 // Now use the escape information to create unique types for | 1698 // Now use the escape information to create unique types for |
1669 // scalar replaceable objects. | 1699 // scalar replaceable objects. |
1670 split_unique_types(alloc_worklist); | 1700 split_unique_types(alloc_worklist); |
1671 | 1701 |
1672 if (C->failing()) return false; | 1702 if (C->failing()) return false; |
1673 | |
1674 // Clean up after split unique types. | |
1675 ResourceMark rm; | |
1676 PhaseRemoveUseless pru(C->initial_gvn(), C->for_igvn()); | |
1677 | 1703 |
1678 C->print_method("After Escape Analysis", 2); | 1704 C->print_method("After Escape Analysis", 2); |
1679 | 1705 |
1680 #ifdef ASSERT | 1706 #ifdef ASSERT |
1681 } else if (Verbose && (PrintEscapeAnalysis || PrintEliminateAllocations)) { | 1707 } else if (Verbose && (PrintEscapeAnalysis || PrintEliminateAllocations)) { |
1709 Compile* C = _compile; | 1735 Compile* C = _compile; |
1710 | 1736 |
1711 int offset = ptn->offset(); | 1737 int offset = ptn->offset(); |
1712 Node* base = get_addp_base(n); | 1738 Node* base = get_addp_base(n); |
1713 ptset.Clear(); | 1739 ptset.Clear(); |
1714 PointsTo(ptset, base, phase); | 1740 PointsTo(ptset, base); |
1715 int ptset_size = ptset.Size(); | 1741 int ptset_size = ptset.Size(); |
1716 | 1742 |
1717 // Check if a oop field's initializing value is recorded and add | 1743 // Check if a oop field's initializing value is recorded and add |
1718 // a corresponding NULL field's value if it is not recorded. | 1744 // a corresponding NULL field's value if it is not recorded. |
1719 // Connection Graph does not record a default initialization by NULL | 1745 // Connection Graph does not record a default initialization by NULL |
1887 // pointer to the base (with offset) is passed as argument. | 1913 // pointer to the base (with offset) is passed as argument. |
1888 // | 1914 // |
1889 arg = get_addp_base(arg); | 1915 arg = get_addp_base(arg); |
1890 } | 1916 } |
1891 ptset.Clear(); | 1917 ptset.Clear(); |
1892 PointsTo(ptset, arg, phase); | 1918 PointsTo(ptset, arg); |
1893 for( VectorSetI j(&ptset); j.test(); ++j ) { | 1919 for( VectorSetI j(&ptset); j.test(); ++j ) { |
1894 uint pt = j.elem; | 1920 uint pt = j.elem; |
1895 set_escape_state(pt, PointsToNode::ArgEscape); | 1921 set_escape_state(pt, PointsToNode::ArgEscape); |
1896 } | 1922 } |
1897 } | 1923 } |
1932 set_escape_state(arg->_idx, PointsToNode::ArgEscape); | 1958 set_escape_state(arg->_idx, PointsToNode::ArgEscape); |
1933 copy_dependencies = true; | 1959 copy_dependencies = true; |
1934 } | 1960 } |
1935 | 1961 |
1936 ptset.Clear(); | 1962 ptset.Clear(); |
1937 PointsTo(ptset, arg, phase); | 1963 PointsTo(ptset, arg); |
1938 for( VectorSetI j(&ptset); j.test(); ++j ) { | 1964 for( VectorSetI j(&ptset); j.test(); ++j ) { |
1939 uint pt = j.elem; | 1965 uint pt = j.elem; |
1940 if (global_escapes) { | 1966 if (global_escapes) { |
1941 //The argument global escapes, mark everything it could point to | 1967 //The argument global escapes, mark everything it could point to |
1942 set_escape_state(pt, PointsToNode::GlobalEscape); | 1968 set_escape_state(pt, PointsToNode::GlobalEscape); |
1968 const Type* at = d->field_at(i); | 1994 const Type* at = d->field_at(i); |
1969 if (at->isa_oopptr() != NULL) { | 1995 if (at->isa_oopptr() != NULL) { |
1970 Node *arg = call->in(i)->uncast(); | 1996 Node *arg = call->in(i)->uncast(); |
1971 set_escape_state(arg->_idx, PointsToNode::GlobalEscape); | 1997 set_escape_state(arg->_idx, PointsToNode::GlobalEscape); |
1972 ptset.Clear(); | 1998 ptset.Clear(); |
1973 PointsTo(ptset, arg, phase); | 1999 PointsTo(ptset, arg); |
1974 for( VectorSetI j(&ptset); j.test(); ++j ) { | 2000 for( VectorSetI j(&ptset); j.test(); ++j ) { |
1975 uint pt = j.elem; | 2001 uint pt = j.elem; |
1976 set_escape_state(pt, PointsToNode::GlobalEscape); | 2002 set_escape_state(pt, PointsToNode::GlobalEscape); |
1977 } | 2003 } |
1978 } | 2004 } |
2431 case Op_AddP: | 2457 case Op_AddP: |
2432 { | 2458 { |
2433 Node *base = get_addp_base(n); | 2459 Node *base = get_addp_base(n); |
2434 // Create a field edge to this node from everything base could point to. | 2460 // Create a field edge to this node from everything base could point to. |
2435 VectorSet ptset(Thread::current()->resource_area()); | 2461 VectorSet ptset(Thread::current()->resource_area()); |
2436 PointsTo(ptset, base, phase); | 2462 PointsTo(ptset, base); |
2437 for( VectorSetI i(&ptset); i.test(); ++i ) { | 2463 for( VectorSetI i(&ptset); i.test(); ++i ) { |
2438 uint pt = i.elem; | 2464 uint pt = i.elem; |
2439 add_field_edge(pt, n_idx, address_offset(n, phase)); | 2465 add_field_edge(pt, n_idx, address_offset(n, phase)); |
2440 } | 2466 } |
2441 break; | 2467 break; |
2499 } | 2525 } |
2500 | 2526 |
2501 // For everything "adr_base" could point to, create a deferred edge from | 2527 // For everything "adr_base" could point to, create a deferred edge from |
2502 // this node to each field with the same offset. | 2528 // this node to each field with the same offset. |
2503 VectorSet ptset(Thread::current()->resource_area()); | 2529 VectorSet ptset(Thread::current()->resource_area()); |
2504 PointsTo(ptset, adr_base, phase); | 2530 PointsTo(ptset, adr_base); |
2505 int offset = address_offset(adr, phase); | 2531 int offset = address_offset(adr, phase); |
2506 for( VectorSetI i(&ptset); i.test(); ++i ) { | 2532 for( VectorSetI i(&ptset); i.test(); ++i ) { |
2507 uint pt = i.elem; | 2533 uint pt = i.elem; |
2508 add_deferred_edge_to_fields(n_idx, pt, offset); | 2534 add_deferred_edge_to_fields(n_idx, pt, offset); |
2509 } | 2535 } |
2592 Node *adr_base = get_addp_base(adr); | 2618 Node *adr_base = get_addp_base(adr); |
2593 Node *val = n->in(MemNode::ValueIn)->uncast(); | 2619 Node *val = n->in(MemNode::ValueIn)->uncast(); |
2594 // For everything "adr_base" could point to, create a deferred edge | 2620 // For everything "adr_base" could point to, create a deferred edge |
2595 // to "val" from each field with the same offset. | 2621 // to "val" from each field with the same offset. |
2596 VectorSet ptset(Thread::current()->resource_area()); | 2622 VectorSet ptset(Thread::current()->resource_area()); |
2597 PointsTo(ptset, adr_base, phase); | 2623 PointsTo(ptset, adr_base); |
2598 for( VectorSetI i(&ptset); i.test(); ++i ) { | 2624 for( VectorSetI i(&ptset); i.test(); ++i ) { |
2599 uint pt = i.elem; | 2625 uint pt = i.elem; |
2600 add_edge_from_fields(pt, val->_idx, address_offset(adr, phase)); | 2626 add_edge_from_fields(pt, val->_idx, address_offset(adr, phase)); |
2601 } | 2627 } |
2602 break; | 2628 break; |
2636 } | 2662 } |
2637 } | 2663 } |
2638 | 2664 |
2639 #ifndef PRODUCT | 2665 #ifndef PRODUCT |
2640 void ConnectionGraph::dump() { | 2666 void ConnectionGraph::dump() { |
2641 PhaseGVN *igvn = _compile->initial_gvn(); | |
2642 bool first = true; | 2667 bool first = true; |
2643 | 2668 |
2644 uint size = nodes_size(); | 2669 uint size = nodes_size(); |
2645 for (uint ni = 0; ni < size; ni++) { | 2670 for (uint ni = 0; ni < size; ni++) { |
2646 PointsToNode *ptn = ptnode_adr(ni); | 2671 PointsToNode *ptn = ptnode_adr(ni); |
2647 PointsToNode::NodeType ptn_type = ptn->node_type(); | 2672 PointsToNode::NodeType ptn_type = ptn->node_type(); |
2648 | 2673 |
2649 if (ptn_type != PointsToNode::JavaObject || ptn->_node == NULL) | 2674 if (ptn_type != PointsToNode::JavaObject || ptn->_node == NULL) |
2650 continue; | 2675 continue; |
2651 PointsToNode::EscapeState es = escape_state(ptn->_node, igvn); | 2676 PointsToNode::EscapeState es = escape_state(ptn->_node); |
2652 if (ptn->_node->is_Allocate() && (es == PointsToNode::NoEscape || Verbose)) { | 2677 if (ptn->_node->is_Allocate() && (es == PointsToNode::NoEscape || Verbose)) { |
2653 if (first) { | 2678 if (first) { |
2654 tty->cr(); | 2679 tty->cr(); |
2655 tty->print("======== Connection graph for "); | 2680 tty->print("======== Connection graph for "); |
2656 _compile->method()->print_short_name(); | 2681 _compile->method()->print_short_name(); |