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); |
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()) { |
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()) { |
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 } |
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; |