Mercurial > hg > truffle
comparison src/share/vm/opto/escape.cpp @ 4122:cc81b9c09bbb
7112478: after 7105605 JRuby bench_define_method_methods.rb fails with NPE
Summary: Fixed several EA issues with Connection Graph construction.
Reviewed-by: never, twisti
author | kvn |
---|---|
date | Mon, 28 Nov 2011 15:46:31 -0800 |
parents | 1bd45abaa507 |
children | 1dc233a8c7fe |
comparison
equal
deleted
inserted
replaced
4121:db2e64ca2d5a | 4122:cc81b9c09bbb |
---|---|
128 PointsToNode *t = ptnode_adr(to_i); | 128 PointsToNode *t = ptnode_adr(to_i); |
129 | 129 |
130 assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); | 130 assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); |
131 assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of PointsTo edge"); | 131 assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of PointsTo edge"); |
132 assert(t->node_type() == PointsToNode::JavaObject, "invalid destination of PointsTo edge"); | 132 assert(t->node_type() == PointsToNode::JavaObject, "invalid destination of PointsTo edge"); |
133 if (to_i == _phantom_object) { // Quick test for most common object | |
134 if (f->has_unknown_ptr()) { | |
135 return; | |
136 } else { | |
137 f->set_has_unknown_ptr(); | |
138 } | |
139 } | |
133 add_edge(f, to_i, PointsToNode::PointsToEdge); | 140 add_edge(f, to_i, PointsToNode::PointsToEdge); |
134 } | 141 } |
135 | 142 |
136 void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) { | 143 void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) { |
137 PointsToNode *f = ptnode_adr(from_i); | 144 PointsToNode *f = ptnode_adr(from_i); |
163 assert(t_ptr != NULL, "must be a pointer type"); | 170 assert(t_ptr != NULL, "must be a pointer type"); |
164 return t_ptr->offset(); | 171 return t_ptr->offset(); |
165 } | 172 } |
166 | 173 |
167 void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) { | 174 void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) { |
175 // Don't add fields to NULL pointer. | |
176 if (is_null_ptr(from_i)) | |
177 return; | |
168 PointsToNode *f = ptnode_adr(from_i); | 178 PointsToNode *f = ptnode_adr(from_i); |
169 PointsToNode *t = ptnode_adr(to_i); | 179 PointsToNode *t = ptnode_adr(to_i); |
170 | 180 |
171 assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); | 181 assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); |
172 assert(f->node_type() == PointsToNode::JavaObject, "invalid destination of Field edge"); | 182 assert(f->node_type() == PointsToNode::JavaObject, "invalid destination of Field edge"); |
177 add_edge(f, to_i, PointsToNode::FieldEdge); | 187 add_edge(f, to_i, PointsToNode::FieldEdge); |
178 } | 188 } |
179 | 189 |
180 void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) { | 190 void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) { |
181 // Don't change non-escaping state of NULL pointer. | 191 // Don't change non-escaping state of NULL pointer. |
182 if (ni == _noop_null || ni == _oop_null) | 192 if (is_null_ptr(ni)) |
183 return; | 193 return; |
184 PointsToNode *npt = ptnode_adr(ni); | 194 PointsToNode *npt = ptnode_adr(ni); |
185 PointsToNode::EscapeState old_es = npt->escape_state(); | 195 PointsToNode::EscapeState old_es = npt->escape_state(); |
186 if (es > old_es) | 196 if (es > old_es) |
187 npt->set_escape_state(es); | 197 npt->set_escape_state(es); |
309 deferred_edges->clear(); | 319 deferred_edges->clear(); |
310 visited->Reset(); | 320 visited->Reset(); |
311 | 321 |
312 visited->set(ni); | 322 visited->set(ni); |
313 PointsToNode *ptn = ptnode_adr(ni); | 323 PointsToNode *ptn = ptnode_adr(ni); |
314 if (ptn->edge_count() == 0) { | 324 assert(ptn->node_type() == PointsToNode::LocalVar || |
315 // No deferred or pointsto edges found. Assume the value was set | 325 ptn->node_type() == PointsToNode::Field, "sanity"); |
316 // outside this method. Add edge to phantom object. | 326 assert(ptn->edge_count() != 0, "should have at least phantom_object"); |
317 add_pointsto_edge(ni, _phantom_object); | |
318 } | |
319 | 327 |
320 // Mark current edges as visited and move deferred edges to separate array. | 328 // Mark current edges as visited and move deferred edges to separate array. |
321 for (uint i = 0; i < ptn->edge_count(); ) { | 329 for (uint i = 0; i < ptn->edge_count(); ) { |
322 uint t = ptn->edge_target(i); | 330 uint t = ptn->edge_target(i); |
323 #ifdef ASSERT | 331 #ifdef ASSERT |
334 } | 342 } |
335 for (int next = 0; next < deferred_edges->length(); ++next) { | 343 for (int next = 0; next < deferred_edges->length(); ++next) { |
336 uint t = deferred_edges->at(next); | 344 uint t = deferred_edges->at(next); |
337 PointsToNode *ptt = ptnode_adr(t); | 345 PointsToNode *ptt = ptnode_adr(t); |
338 uint e_cnt = ptt->edge_count(); | 346 uint e_cnt = ptt->edge_count(); |
339 if (e_cnt == 0) { | 347 assert(e_cnt != 0, "should have at least phantom_object"); |
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 } | |
345 for (uint e = 0; e < e_cnt; e++) { | 348 for (uint e = 0; e < e_cnt; e++) { |
346 uint etgt = ptt->edge_target(e); | 349 uint etgt = ptt->edge_target(e); |
347 if (visited->test_set(etgt)) | 350 if (visited->test_set(etgt)) |
348 continue; | 351 continue; |
349 | 352 |
350 PointsToNode::EdgeType et = ptt->edge_type(e); | 353 PointsToNode::EdgeType et = ptt->edge_type(e); |
351 if (et == PointsToNode::PointsToEdge) { | 354 if (et == PointsToNode::PointsToEdge) { |
352 add_pointsto_edge(ni, etgt); | 355 add_pointsto_edge(ni, etgt); |
353 if(etgt == _phantom_object) { | |
354 // Special case - field set outside (globally escaping). | |
355 set_escape_state(ni, PointsToNode::GlobalEscape); | |
356 } | |
357 } else if (et == PointsToNode::DeferredEdge) { | 356 } else if (et == PointsToNode::DeferredEdge) { |
358 deferred_edges->append(etgt); | 357 deferred_edges->append(etgt); |
359 } else { | 358 } else { |
360 assert(false,"invalid connection graph"); | 359 assert(false,"invalid connection graph"); |
361 } | 360 } |
362 } | 361 } |
363 } | 362 } |
363 if (ptn->edge_count() == 0) { | |
364 // No pointsto edges found after deferred edges are removed. | |
365 // For example, in the next case where call is replaced | |
366 // with uncommon trap and as result array's load references | |
367 // itself through deferred edges: | |
368 // | |
369 // A a = b[i]; | |
370 // if (c!=null) a = c.foo(); | |
371 // b[i] = a; | |
372 // | |
373 // Assume the value was set outside this method and | |
374 // add edge to phantom object. | |
375 add_pointsto_edge(ni, _phantom_object); | |
376 } | |
364 } | 377 } |
365 | 378 |
366 | 379 |
367 // Add an edge to node given by "to_i" from any field of adr_i whose offset | 380 // Add an edge to node given by "to_i" from any field of adr_i whose offset |
368 // matches "offset" A deferred edge is added if to_i is a LocalVar, and | 381 // matches "offset" A deferred edge is added if to_i is a LocalVar, and |
369 // a pointsto edge is added if it is a JavaObject | 382 // a pointsto edge is added if it is a JavaObject |
370 | 383 |
371 void ConnectionGraph::add_edge_from_fields(uint adr_i, uint to_i, int offs) { | 384 void ConnectionGraph::add_edge_from_fields(uint adr_i, uint to_i, int offs) { |
385 // No fields for NULL pointer. | |
386 if (is_null_ptr(adr_i)) { | |
387 return; | |
388 } | |
372 PointsToNode* an = ptnode_adr(adr_i); | 389 PointsToNode* an = ptnode_adr(adr_i); |
373 PointsToNode* to = ptnode_adr(to_i); | 390 PointsToNode* to = ptnode_adr(to_i); |
374 bool deferred = (to->node_type() == PointsToNode::LocalVar); | 391 bool deferred = (to->node_type() == PointsToNode::LocalVar); |
375 | 392 bool escaped = (to_i == _phantom_object) && (offs == Type::OffsetTop); |
393 if (escaped) { | |
394 // Values in fields escaped during call. | |
395 assert(an->escape_state() >= PointsToNode::ArgEscape, "sanity"); | |
396 offs = Type::OffsetBot; | |
397 } | |
376 for (uint fe = 0; fe < an->edge_count(); fe++) { | 398 for (uint fe = 0; fe < an->edge_count(); fe++) { |
377 assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); | 399 assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); |
378 int fi = an->edge_target(fe); | 400 int fi = an->edge_target(fe); |
401 if (escaped) { | |
402 set_escape_state(fi, PointsToNode::GlobalEscape); | |
403 } | |
379 PointsToNode* pf = ptnode_adr(fi); | 404 PointsToNode* pf = ptnode_adr(fi); |
380 int po = pf->offset(); | 405 int po = pf->offset(); |
381 if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { | 406 if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { |
382 if (deferred) | 407 if (deferred) |
383 add_deferred_edge(fi, to_i); | 408 add_deferred_edge(fi, to_i); |
388 } | 413 } |
389 | 414 |
390 // Add a deferred edge from node given by "from_i" to any field of adr_i | 415 // Add a deferred edge from node given by "from_i" to any field of adr_i |
391 // whose offset matches "offset". | 416 // whose offset matches "offset". |
392 void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) { | 417 void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) { |
418 // No fields for NULL pointer. | |
419 if (is_null_ptr(adr_i)) { | |
420 return; | |
421 } | |
422 if (adr_i == _phantom_object) { | |
423 // Add only one edge for unknown object. | |
424 add_pointsto_edge(from_i, _phantom_object); | |
425 return; | |
426 } | |
393 PointsToNode* an = ptnode_adr(adr_i); | 427 PointsToNode* an = ptnode_adr(adr_i); |
394 bool is_alloc = an->_node->is_Allocate(); | 428 bool is_alloc = an->_node->is_Allocate(); |
395 for (uint fe = 0; fe < an->edge_count(); fe++) { | 429 for (uint fe = 0; fe < an->edge_count(); fe++) { |
396 assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); | 430 assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); |
397 int fi = an->edge_target(fe); | 431 int fi = an->edge_target(fe); |
1560 | 1594 |
1561 GrowableArray<Node*> alloc_worklist; | 1595 GrowableArray<Node*> alloc_worklist; |
1562 GrowableArray<Node*> addp_worklist; | 1596 GrowableArray<Node*> addp_worklist; |
1563 GrowableArray<Node*> ptr_cmp_worklist; | 1597 GrowableArray<Node*> ptr_cmp_worklist; |
1564 PhaseGVN* igvn = _igvn; | 1598 PhaseGVN* igvn = _igvn; |
1565 bool has_allocations = false; | |
1566 | 1599 |
1567 // Push all useful nodes onto CG list and set their type. | 1600 // Push all useful nodes onto CG list and set their type. |
1568 for( uint next = 0; next < worklist_init.size(); ++next ) { | 1601 for( uint next = 0; next < worklist_init.size(); ++next ) { |
1569 Node* n = worklist_init.at(next); | 1602 Node* n = worklist_init.at(next); |
1570 record_for_escape_analysis(n, igvn); | 1603 record_for_escape_analysis(n, igvn); |
1571 // Only allocations and java static calls results are checked | 1604 // Only allocations and java static calls results are checked |
1572 // for an escape status. See process_call_result() below. | 1605 // for an escape status. See process_call_result() below. |
1573 if (n->is_Allocate() || n->is_CallStaticJava() && | 1606 if (n->is_Allocate() || n->is_CallStaticJava() && |
1574 ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) { | 1607 ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) { |
1575 has_allocations = true; | 1608 alloc_worklist.append(n); |
1576 if (n->is_Allocate()) | |
1577 alloc_worklist.append(n); | |
1578 } else if(n->is_AddP()) { | 1609 } else if(n->is_AddP()) { |
1579 // Collect address nodes. Use them during stage 3 below | 1610 // Collect address nodes. Use them during stage 3 below |
1580 // to build initial connection graph field edges. | 1611 // to build initial connection graph field edges. |
1581 addp_worklist.append(n); | 1612 addp_worklist.append(n); |
1582 } else if (n->is_MergeMem()) { | 1613 } else if (n->is_MergeMem()) { |
1592 Node* m = n->fast_out(i); // Get user | 1623 Node* m = n->fast_out(i); // Get user |
1593 worklist_init.push(m); | 1624 worklist_init.push(m); |
1594 } | 1625 } |
1595 } | 1626 } |
1596 | 1627 |
1597 if (!has_allocations) { | 1628 if (alloc_worklist.length() == 0) { |
1598 _collecting = false; | 1629 _collecting = false; |
1599 return false; // Nothing to do. | 1630 return false; // Nothing to do. |
1600 } | 1631 } |
1601 | 1632 |
1602 // 2. First pass to create simple CG edges (doesn't require to walk CG). | 1633 // 2. First pass to create simple CG edges (doesn't require to walk CG). |
1675 _collecting = false; | 1706 _collecting = false; |
1676 return false; | 1707 return false; |
1677 } | 1708 } |
1678 #undef CG_BUILD_ITER_LIMIT | 1709 #undef CG_BUILD_ITER_LIMIT |
1679 | 1710 |
1711 // 5. Propagate escaped states. | |
1712 worklist.clear(); | |
1713 | |
1714 // mark all nodes reachable from GlobalEscape nodes | |
1715 (void)propagate_escape_state(&cg_worklist, &worklist, PointsToNode::GlobalEscape); | |
1716 | |
1717 // mark all nodes reachable from ArgEscape nodes | |
1718 bool has_non_escaping_obj = propagate_escape_state(&cg_worklist, &worklist, PointsToNode::ArgEscape); | |
1719 | |
1680 Arena* arena = Thread::current()->resource_area(); | 1720 Arena* arena = Thread::current()->resource_area(); |
1681 VectorSet visited(arena); | 1721 VectorSet visited(arena); |
1682 | 1722 |
1683 // 5. Find fields initializing values for not escaped allocations | 1723 // 6. Find fields initializing values for not escaped allocations |
1684 uint alloc_length = alloc_worklist.length(); | 1724 uint alloc_length = alloc_worklist.length(); |
1685 for (uint next = 0; next < alloc_length; ++next) { | 1725 for (uint next = 0; next < alloc_length; ++next) { |
1686 Node* n = alloc_worklist.at(next); | 1726 Node* n = alloc_worklist.at(next); |
1687 if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) { | 1727 if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) { |
1688 find_init_values(n, &visited, igvn); | 1728 has_non_escaping_obj = true; |
1689 } | 1729 if (n->is_Allocate()) { |
1690 } | 1730 find_init_values(n, &visited, igvn); |
1691 | 1731 } |
1692 worklist.clear(); | 1732 } |
1693 | 1733 } |
1694 // 6. Remove deferred edges from the graph. | 1734 |
1695 uint cg_length = cg_worklist.length(); | 1735 uint cg_length = cg_worklist.length(); |
1736 | |
1737 // Skip the rest of code if all objects escaped. | |
1738 if (!has_non_escaping_obj) { | |
1739 cg_length = 0; | |
1740 addp_length = 0; | |
1741 } | |
1742 | |
1743 for (uint next = 0; next < cg_length; ++next) { | |
1744 int ni = cg_worklist.at(next); | |
1745 PointsToNode* ptn = ptnode_adr(ni); | |
1746 PointsToNode::NodeType nt = ptn->node_type(); | |
1747 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { | |
1748 if (ptn->edge_count() == 0) { | |
1749 // No values were found. Assume the value was set | |
1750 // outside this method - add edge to phantom object. | |
1751 add_pointsto_edge(ni, _phantom_object); | |
1752 } | |
1753 } | |
1754 } | |
1755 | |
1756 // 7. Remove deferred edges from the graph. | |
1696 for (uint next = 0; next < cg_length; ++next) { | 1757 for (uint next = 0; next < cg_length; ++next) { |
1697 int ni = cg_worklist.at(next); | 1758 int ni = cg_worklist.at(next); |
1698 PointsToNode* ptn = ptnode_adr(ni); | 1759 PointsToNode* ptn = ptnode_adr(ni); |
1699 PointsToNode::NodeType nt = ptn->node_type(); | 1760 PointsToNode::NodeType nt = ptn->node_type(); |
1700 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { | 1761 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { |
1701 remove_deferred(ni, &worklist, &visited); | 1762 remove_deferred(ni, &worklist, &visited); |
1702 } | 1763 } |
1703 } | 1764 } |
1704 | 1765 |
1705 // 7. Adjust escape state of nonescaping objects. | 1766 // 8. Adjust escape state of nonescaping objects. |
1706 for (uint next = 0; next < addp_length; ++next) { | 1767 for (uint next = 0; next < addp_length; ++next) { |
1707 Node* n = addp_worklist.at(next); | 1768 Node* n = addp_worklist.at(next); |
1708 adjust_escape_state(n); | 1769 adjust_escape_state(n); |
1709 } | 1770 } |
1710 | 1771 |
1711 // 8. Propagate escape states. | 1772 // push all NoEscape nodes on the worklist |
1712 worklist.clear(); | 1773 worklist.clear(); |
1713 | |
1714 // mark all nodes reachable from GlobalEscape nodes | |
1715 (void)propagate_escape_state(&cg_worklist, &worklist, PointsToNode::GlobalEscape); | |
1716 | |
1717 // mark all nodes reachable from ArgEscape nodes | |
1718 bool has_non_escaping_obj = propagate_escape_state(&cg_worklist, &worklist, PointsToNode::ArgEscape); | |
1719 | |
1720 // push all NoEscape nodes on the worklist | |
1721 for( uint next = 0; next < cg_length; ++next ) { | 1774 for( uint next = 0; next < cg_length; ++next ) { |
1722 int nk = cg_worklist.at(next); | 1775 int nk = cg_worklist.at(next); |
1723 if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape) | 1776 if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape && |
1777 !is_null_ptr(nk)) | |
1724 worklist.push(nk); | 1778 worklist.push(nk); |
1725 } | 1779 } |
1780 | |
1726 alloc_worklist.clear(); | 1781 alloc_worklist.clear(); |
1727 // mark all nodes reachable from NoEscape nodes | 1782 // Propagate scalar_replaceable value. |
1728 while(worklist.length() > 0) { | 1783 while(worklist.length() > 0) { |
1729 uint nk = worklist.pop(); | 1784 uint nk = worklist.pop(); |
1730 PointsToNode* ptn = ptnode_adr(nk); | 1785 PointsToNode* ptn = ptnode_adr(nk); |
1731 if (ptn->node_type() == PointsToNode::JavaObject && | |
1732 !(nk == _noop_null || nk == _oop_null)) | |
1733 has_non_escaping_obj = true; // Non Escape | |
1734 Node* n = ptn->_node; | 1786 Node* n = ptn->_node; |
1735 bool scalar_replaceable = ptn->scalar_replaceable(); | 1787 bool scalar_replaceable = ptn->scalar_replaceable(); |
1736 if (n->is_Allocate() && scalar_replaceable) { | 1788 if (n->is_Allocate() && scalar_replaceable) { |
1737 // Push scalar replaceable allocations on alloc_worklist | 1789 // Push scalar replaceable allocations on alloc_worklist |
1738 // for processing in split_unique_types(). Note, | 1790 // for processing in split_unique_types(). Note, |
1740 alloc_worklist.append(n); | 1792 alloc_worklist.append(n); |
1741 } | 1793 } |
1742 uint e_cnt = ptn->edge_count(); | 1794 uint e_cnt = ptn->edge_count(); |
1743 for (uint ei = 0; ei < e_cnt; ei++) { | 1795 for (uint ei = 0; ei < e_cnt; ei++) { |
1744 uint npi = ptn->edge_target(ei); | 1796 uint npi = ptn->edge_target(ei); |
1797 if (is_null_ptr(npi)) | |
1798 continue; | |
1745 PointsToNode *np = ptnode_adr(npi); | 1799 PointsToNode *np = ptnode_adr(npi); |
1746 if (np->escape_state() < PointsToNode::NoEscape) { | 1800 if (np->escape_state() < PointsToNode::NoEscape) { |
1747 set_escape_state(npi, PointsToNode::NoEscape); | 1801 set_escape_state(npi, PointsToNode::NoEscape); |
1748 if (!scalar_replaceable) { | 1802 if (!scalar_replaceable) { |
1749 np->set_scalar_replaceable(false); | 1803 np->set_scalar_replaceable(false); |
1750 } | 1804 } |
1751 worklist.push(npi); | 1805 worklist.push(npi); |
1752 } else if (np->scalar_replaceable() && !scalar_replaceable) { | 1806 } else if (np->scalar_replaceable() && !scalar_replaceable) { |
1753 // Propagate scalar_replaceable value. | |
1754 np->set_scalar_replaceable(false); | 1807 np->set_scalar_replaceable(false); |
1755 worklist.push(npi); | 1808 worklist.push(npi); |
1756 } | 1809 } |
1757 } | 1810 } |
1758 } | 1811 } |
1759 | 1812 |
1760 _collecting = false; | 1813 _collecting = false; |
1761 assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build"); | 1814 assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build"); |
1762 | 1815 |
1763 assert(ptnode_adr(_oop_null)->escape_state() == PointsToNode::NoEscape, "sanity"); | 1816 assert(ptnode_adr(_oop_null)->escape_state() == PointsToNode::NoEscape && |
1817 ptnode_adr(_oop_null)->edge_count() == 0, "sanity"); | |
1764 if (UseCompressedOops) { | 1818 if (UseCompressedOops) { |
1765 assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape, "sanity"); | 1819 assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape && |
1820 ptnode_adr(_noop_null)->edge_count() == 0, "sanity"); | |
1766 } | 1821 } |
1767 | 1822 |
1768 if (EliminateLocks && has_non_escaping_obj) { | 1823 if (EliminateLocks && has_non_escaping_obj) { |
1769 // Mark locks before changing ideal graph. | 1824 // Mark locks before changing ideal graph. |
1770 int cnt = C->macro_count(); | 1825 int cnt = C->macro_count(); |
1877 // Check if a oop field's initializing value is recorded and add | 1932 // Check if a oop field's initializing value is recorded and add |
1878 // a corresponding NULL field's value if it is not recorded. | 1933 // a corresponding NULL field's value if it is not recorded. |
1879 // Connection Graph does not record a default initialization by NULL | 1934 // Connection Graph does not record a default initialization by NULL |
1880 // captured by Initialize node. | 1935 // captured by Initialize node. |
1881 // | 1936 // |
1937 uint null_idx = UseCompressedOops ? _noop_null : _oop_null; | |
1882 uint ae_cnt = pta->edge_count(); | 1938 uint ae_cnt = pta->edge_count(); |
1939 bool visited_bottom_offset = false; | |
1883 for (uint ei = 0; ei < ae_cnt; ei++) { | 1940 for (uint ei = 0; ei < ae_cnt; ei++) { |
1884 uint nidx = pta->edge_target(ei); // Field (AddP) | 1941 uint nidx = pta->edge_target(ei); // Field (AddP) |
1885 PointsToNode* ptn = ptnode_adr(nidx); | 1942 PointsToNode* ptn = ptnode_adr(nidx); |
1886 assert(ptn->_node->is_AddP(), "Should be AddP nodes only"); | 1943 assert(ptn->_node->is_AddP(), "Should be AddP nodes only"); |
1887 int offset = ptn->offset(); | 1944 int offset = ptn->offset(); |
1888 if (offset != Type::OffsetBot && | 1945 if (offset == Type::OffsetBot) { |
1889 offset != oopDesc::klass_offset_in_bytes() && | 1946 if (!visited_bottom_offset) { |
1890 !visited->test_set(offset)) { | 1947 visited_bottom_offset = true; |
1948 // Check only oop fields. | |
1949 const Type* adr_type = ptn->_node->as_AddP()->bottom_type(); | |
1950 if (!adr_type->isa_aryptr() || | |
1951 (adr_type->isa_aryptr()->klass() == NULL) || | |
1952 adr_type->isa_aryptr()->klass()->is_obj_array_klass()) { | |
1953 // OffsetBot is used to reference array's element, | |
1954 // always add reference to NULL since we don't | |
1955 // known which element is referenced. | |
1956 add_edge_from_fields(alloc->_idx, null_idx, offset); | |
1957 } | |
1958 } | |
1959 } else if (offset != oopDesc::klass_offset_in_bytes() && | |
1960 !visited->test_set(offset)) { | |
1891 | 1961 |
1892 // Check only oop fields. | 1962 // Check only oop fields. |
1893 const Type* adr_type = ptn->_node->as_AddP()->bottom_type(); | 1963 const Type* adr_type = ptn->_node->as_AddP()->bottom_type(); |
1894 BasicType basic_field_type = T_INT; | 1964 BasicType basic_field_type = T_INT; |
1895 if (adr_type->isa_instptr()) { | 1965 if (adr_type->isa_instptr()) { |
1960 } | 2030 } |
1961 } | 2031 } |
1962 } | 2032 } |
1963 if (value == NULL || value != ptnode_adr(value->_idx)->_node) { | 2033 if (value == NULL || value != ptnode_adr(value->_idx)->_node) { |
1964 // A field's initializing value was not recorded. Add NULL. | 2034 // A field's initializing value was not recorded. Add NULL. |
1965 uint null_idx = UseCompressedOops ? _noop_null : _oop_null; | |
1966 add_edge_from_fields(alloc->_idx, null_idx, offset); | 2035 add_edge_from_fields(alloc->_idx, null_idx, offset); |
1967 } | 2036 } |
1968 } | 2037 } |
1969 } | 2038 } |
1970 } | 2039 } |
2046 if (ptnode_adr(nk)->escape_state() == esc_state) | 2115 if (ptnode_adr(nk)->escape_state() == esc_state) |
2047 worklist->push(nk); | 2116 worklist->push(nk); |
2048 } | 2117 } |
2049 // mark all reachable nodes | 2118 // mark all reachable nodes |
2050 while (worklist->length() > 0) { | 2119 while (worklist->length() > 0) { |
2051 PointsToNode* ptn = ptnode_adr(worklist->pop()); | 2120 int pt = worklist->pop(); |
2052 if (ptn->node_type() == PointsToNode::JavaObject) { | 2121 PointsToNode* ptn = ptnode_adr(pt); |
2122 if (ptn->node_type() == PointsToNode::JavaObject && | |
2123 !is_null_ptr(pt)) { | |
2053 has_java_obj = true; | 2124 has_java_obj = true; |
2125 if (esc_state > PointsToNode::NoEscape) { | |
2126 // fields values are unknown if object escapes | |
2127 add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); | |
2128 } | |
2054 } | 2129 } |
2055 uint e_cnt = ptn->edge_count(); | 2130 uint e_cnt = ptn->edge_count(); |
2056 for (uint ei = 0; ei < e_cnt; ei++) { | 2131 for (uint ei = 0; ei < e_cnt; ei++) { |
2057 uint npi = ptn->edge_target(ei); | 2132 uint npi = ptn->edge_target(ei); |
2133 if (is_null_ptr(npi)) | |
2134 continue; | |
2058 PointsToNode *np = ptnode_adr(npi); | 2135 PointsToNode *np = ptnode_adr(npi); |
2059 if (np->escape_state() < esc_state) { | 2136 if (np->escape_state() < esc_state) { |
2060 set_escape_state(npi, esc_state); | 2137 set_escape_state(npi, esc_state); |
2061 worklist->push(npi); | 2138 worklist->push(npi); |
2062 } | 2139 } |
2157 } | 2234 } |
2158 return NULL; | 2235 return NULL; |
2159 } | 2236 } |
2160 | 2237 |
2161 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { | 2238 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { |
2162 | 2239 bool is_arraycopy = false; |
2163 switch (call->Opcode()) { | 2240 switch (call->Opcode()) { |
2164 #ifdef ASSERT | 2241 #ifdef ASSERT |
2165 case Op_Allocate: | 2242 case Op_Allocate: |
2166 case Op_AllocateArray: | 2243 case Op_AllocateArray: |
2167 case Op_Lock: | 2244 case Op_Lock: |
2168 case Op_Unlock: | 2245 case Op_Unlock: |
2169 assert(false, "should be done already"); | 2246 assert(false, "should be done already"); |
2170 break; | 2247 break; |
2171 #endif | 2248 #endif |
2249 case Op_CallLeafNoFP: | |
2250 is_arraycopy = (call->as_CallLeaf()->_name != NULL && | |
2251 strstr(call->as_CallLeaf()->_name, "arraycopy") != 0); | |
2252 // fall through | |
2172 case Op_CallLeaf: | 2253 case Op_CallLeaf: |
2173 case Op_CallLeafNoFP: | |
2174 { | 2254 { |
2175 // Stub calls, objects do not escape but they are not scale replaceable. | 2255 // Stub calls, objects do not escape but they are not scale replaceable. |
2176 // Adjust escape state for outgoing arguments. | 2256 // Adjust escape state for outgoing arguments. |
2177 const TypeTuple * d = call->tf()->domain(); | 2257 const TypeTuple * d = call->tf()->domain(); |
2258 bool src_has_oops = false; | |
2178 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { | 2259 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { |
2179 const Type* at = d->field_at(i); | 2260 const Type* at = d->field_at(i); |
2180 Node *arg = call->in(i)->uncast(); | 2261 Node *arg = call->in(i)->uncast(); |
2181 const Type *aat = phase->type(arg); | 2262 const Type *aat = phase->type(arg); |
2263 PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state(); | |
2182 if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() && | 2264 if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() && |
2183 ptnode_adr(arg->_idx)->escape_state() < PointsToNode::ArgEscape) { | 2265 (is_arraycopy || arg_esc < PointsToNode::ArgEscape)) { |
2184 | 2266 |
2185 assert(aat == Type::TOP || aat == TypePtr::NULL_PTR || | 2267 assert(aat == Type::TOP || aat == TypePtr::NULL_PTR || |
2186 aat->isa_ptr() != NULL, "expecting an Ptr"); | 2268 aat->isa_ptr() != NULL, "expecting an Ptr"); |
2269 bool arg_has_oops = aat->isa_oopptr() && | |
2270 (aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() || | |
2271 (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass())); | |
2272 if (i == TypeFunc::Parms) { | |
2273 src_has_oops = arg_has_oops; | |
2274 } | |
2275 // | |
2276 // src or dst could be j.l.Object when other is basic type array: | |
2277 // | |
2278 // arraycopy(char[],0,Object*,0,size); | |
2279 // arraycopy(Object*,0,char[],0,size); | |
2280 // | |
2281 // Don't add edges from dst's fields in such cases. | |
2282 // | |
2283 bool arg_is_arraycopy_dest = src_has_oops && is_arraycopy && | |
2284 arg_has_oops && (i > TypeFunc::Parms); | |
2187 #ifdef ASSERT | 2285 #ifdef ASSERT |
2188 if (!(call->Opcode() == Op_CallLeafNoFP && | 2286 if (!(is_arraycopy || |
2189 call->as_CallLeaf()->_name != NULL && | |
2190 (strstr(call->as_CallLeaf()->_name, "arraycopy") != 0) || | |
2191 call->as_CallLeaf()->_name != NULL && | 2287 call->as_CallLeaf()->_name != NULL && |
2192 (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || | 2288 (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || |
2193 strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) | 2289 strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) |
2194 ) { | 2290 ) { |
2195 call->dump(); | 2291 call->dump(); |
2196 assert(false, "EA: unexpected CallLeaf"); | 2292 assert(false, "EA: unexpected CallLeaf"); |
2197 } | 2293 } |
2198 #endif | 2294 #endif |
2295 // Always process arraycopy's destination object since | |
2296 // we need to add all possible edges to references in | |
2297 // source object. | |
2298 if (arg_esc >= PointsToNode::ArgEscape && | |
2299 !arg_is_arraycopy_dest) { | |
2300 continue; | |
2301 } | |
2199 set_escape_state(arg->_idx, PointsToNode::ArgEscape); | 2302 set_escape_state(arg->_idx, PointsToNode::ArgEscape); |
2303 Node* arg_base = arg; | |
2200 if (arg->is_AddP()) { | 2304 if (arg->is_AddP()) { |
2201 // | 2305 // |
2202 // The inline_native_clone() case when the arraycopy stub is called | 2306 // The inline_native_clone() case when the arraycopy stub is called |
2203 // after the allocation before Initialize and CheckCastPP nodes. | 2307 // after the allocation before Initialize and CheckCastPP nodes. |
2308 // Or normal arraycopy for object arrays case. | |
2204 // | 2309 // |
2205 // Set AddP's base (Allocate) as not scalar replaceable since | 2310 // Set AddP's base (Allocate) as not scalar replaceable since |
2206 // pointer to the base (with offset) is passed as argument. | 2311 // pointer to the base (with offset) is passed as argument. |
2207 // | 2312 // |
2208 arg = get_addp_base(arg); | 2313 arg_base = get_addp_base(arg); |
2209 } | 2314 } |
2210 for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { | 2315 VectorSet argset = *PointsTo(arg_base); // Clone set |
2211 uint pt = j.elem; | 2316 for( VectorSetI j(&argset); j.test(); ++j ) { |
2212 set_escape_state(pt, PointsToNode::ArgEscape); | 2317 uint pd = j.elem; // Destination object |
2318 set_escape_state(pd, PointsToNode::ArgEscape); | |
2319 | |
2320 if (arg_is_arraycopy_dest) { | |
2321 PointsToNode* ptd = ptnode_adr(pd); | |
2322 // Conservatively reference an unknown object since | |
2323 // not all source's fields/elements may be known. | |
2324 add_edge_from_fields(pd, _phantom_object, Type::OffsetBot); | |
2325 | |
2326 Node *src = call->in(TypeFunc::Parms)->uncast(); | |
2327 Node* src_base = src; | |
2328 if (src->is_AddP()) { | |
2329 src_base = get_addp_base(src); | |
2330 } | |
2331 // Create edges from destination's fields to | |
2332 // everything known source's fields could point to. | |
2333 for( VectorSetI s(PointsTo(src_base)); s.test(); ++s ) { | |
2334 uint ps = s.elem; | |
2335 bool has_bottom_offset = false; | |
2336 for (uint fd = 0; fd < ptd->edge_count(); fd++) { | |
2337 assert(ptd->edge_type(fd) == PointsToNode::FieldEdge, "expecting a field edge"); | |
2338 int fdi = ptd->edge_target(fd); | |
2339 PointsToNode* pfd = ptnode_adr(fdi); | |
2340 int offset = pfd->offset(); | |
2341 if (offset == Type::OffsetBot) | |
2342 has_bottom_offset = true; | |
2343 assert(offset != -1, "offset should be set"); | |
2344 add_deferred_edge_to_fields(fdi, ps, offset); | |
2345 } | |
2346 // Destination object may not have access (no field edge) | |
2347 // to fields which are accessed in source object. | |
2348 // As result no edges will be created to those source's | |
2349 // fields and escape state of destination object will | |
2350 // not be propagated to those fields. | |
2351 // | |
2352 // Mark source object as global escape except in | |
2353 // the case with Type::OffsetBot field (which is | |
2354 // common case for array elements access) when | |
2355 // edges are created to all source's fields. | |
2356 if (!has_bottom_offset) { | |
2357 set_escape_state(ps, PointsToNode::GlobalEscape); | |
2358 } | |
2359 } | |
2360 } | |
2213 } | 2361 } |
2214 } | 2362 } |
2215 } | 2363 } |
2216 break; | 2364 break; |
2217 } | 2365 } |
2250 } | 2398 } |
2251 | 2399 |
2252 for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { | 2400 for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { |
2253 uint pt = j.elem; | 2401 uint pt = j.elem; |
2254 if (global_escapes) { | 2402 if (global_escapes) { |
2255 //The argument global escapes, mark everything it could point to | 2403 // The argument global escapes, mark everything it could point to |
2256 set_escape_state(pt, PointsToNode::GlobalEscape); | 2404 set_escape_state(pt, PointsToNode::GlobalEscape); |
2405 add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); | |
2257 } else { | 2406 } else { |
2407 set_escape_state(pt, PointsToNode::ArgEscape); | |
2258 if (fields_escapes) { | 2408 if (fields_escapes) { |
2259 // The argument itself doesn't escape, but any fields might | 2409 // The argument itself doesn't escape, but any fields might. |
2260 add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); | 2410 // Use OffsetTop to indicate such case. |
2411 add_edge_from_fields(pt, _phantom_object, Type::OffsetTop); | |
2261 } | 2412 } |
2262 set_escape_state(pt, PointsToNode::ArgEscape); | |
2263 } | 2413 } |
2264 } | 2414 } |
2265 } | 2415 } |
2266 } | 2416 } |
2267 if (copy_dependencies) | 2417 if (copy_dependencies) |
2283 Node *arg = call->in(i)->uncast(); | 2433 Node *arg = call->in(i)->uncast(); |
2284 set_escape_state(arg->_idx, PointsToNode::GlobalEscape); | 2434 set_escape_state(arg->_idx, PointsToNode::GlobalEscape); |
2285 for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { | 2435 for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { |
2286 uint pt = j.elem; | 2436 uint pt = j.elem; |
2287 set_escape_state(pt, PointsToNode::GlobalEscape); | 2437 set_escape_state(pt, PointsToNode::GlobalEscape); |
2438 add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); | |
2288 } | 2439 } |
2289 } | 2440 } |
2290 } | 2441 } |
2291 } | 2442 } |
2292 } | 2443 } |
2383 // update dependency information. | 2534 // update dependency information. |
2384 // Mark it as NoEscape so that objects referenced by | 2535 // Mark it as NoEscape so that objects referenced by |
2385 // it's fields will be marked as NoEscape at least. | 2536 // it's fields will be marked as NoEscape at least. |
2386 set_escape_state(call_idx, PointsToNode::NoEscape); | 2537 set_escape_state(call_idx, PointsToNode::NoEscape); |
2387 ptnode_adr(call_idx)->set_scalar_replaceable(false); | 2538 ptnode_adr(call_idx)->set_scalar_replaceable(false); |
2539 // Fields values are unknown | |
2540 add_edge_from_fields(call_idx, _phantom_object, Type::OffsetBot); | |
2388 add_pointsto_edge(resproj_idx, call_idx); | 2541 add_pointsto_edge(resproj_idx, call_idx); |
2389 copy_dependencies = true; | 2542 copy_dependencies = true; |
2390 } else if (call_analyzer->is_return_local()) { | 2543 } else { |
2391 // determine whether any arguments are returned | 2544 // determine whether any arguments are returned |
2392 set_escape_state(call_idx, PointsToNode::ArgEscape); | 2545 set_escape_state(call_idx, PointsToNode::ArgEscape); |
2393 bool ret_arg = false; | 2546 bool ret_arg = false; |
2394 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { | 2547 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { |
2395 const Type* at = d->field_at(i); | 2548 const Type* at = d->field_at(i); |
2396 | |
2397 if (at->isa_oopptr() != NULL) { | 2549 if (at->isa_oopptr() != NULL) { |
2398 Node *arg = call->in(i)->uncast(); | 2550 Node *arg = call->in(i)->uncast(); |
2399 | 2551 |
2400 if (call_analyzer->is_arg_returned(i - TypeFunc::Parms)) { | 2552 if (call_analyzer->is_arg_returned(i - TypeFunc::Parms)) { |
2401 ret_arg = true; | 2553 ret_arg = true; |
2407 else | 2559 else |
2408 add_deferred_edge(resproj_idx, arg->_idx); | 2560 add_deferred_edge(resproj_idx, arg->_idx); |
2409 } | 2561 } |
2410 } | 2562 } |
2411 } | 2563 } |
2412 if (done && !ret_arg) { | |
2413 // Returns unknown object. | |
2414 set_escape_state(call_idx, PointsToNode::GlobalEscape); | |
2415 add_pointsto_edge(resproj_idx, _phantom_object); | |
2416 } | |
2417 if (done) { | 2564 if (done) { |
2418 copy_dependencies = true; | 2565 copy_dependencies = true; |
2566 // is_return_local() is true when only arguments are returned. | |
2567 if (!ret_arg || !call_analyzer->is_return_local()) { | |
2568 // Returns unknown object. | |
2569 add_pointsto_edge(resproj_idx, _phantom_object); | |
2570 } | |
2419 } | 2571 } |
2420 } else { | |
2421 set_escape_state(call_idx, PointsToNode::GlobalEscape); | |
2422 add_pointsto_edge(resproj_idx, _phantom_object); | |
2423 } | 2572 } |
2424 if (copy_dependencies) | 2573 if (copy_dependencies) |
2425 call_analyzer->copy_dependencies(_compile->dependencies()); | 2574 call_analyzer->copy_dependencies(_compile->dependencies()); |
2426 } | 2575 } |
2427 if (done) | 2576 if (done) |