Mercurial > hg > truffle
comparison src/share/vm/opto/escape.cpp @ 4970:33df1aeaebbf
Merge with http://hg.openjdk.java.net/hsx/hsx24/hotspot/
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Mon, 27 Feb 2012 13:10:13 +0100 |
parents | 73df3733f2eb |
children | 9a72c7ece7fb |
comparison
equal
deleted
inserted
replaced
4703:2cfb7fb2dce7 | 4970:33df1aeaebbf |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. | 2 * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | 4 * |
5 * This code is free software; you can redistribute it and/or modify it | 5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as | 6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
1593 } | 1593 } |
1594 | 1594 |
1595 GrowableArray<Node*> alloc_worklist; | 1595 GrowableArray<Node*> alloc_worklist; |
1596 GrowableArray<Node*> addp_worklist; | 1596 GrowableArray<Node*> addp_worklist; |
1597 GrowableArray<Node*> ptr_cmp_worklist; | 1597 GrowableArray<Node*> ptr_cmp_worklist; |
1598 GrowableArray<Node*> storestore_worklist; | |
1598 PhaseGVN* igvn = _igvn; | 1599 PhaseGVN* igvn = _igvn; |
1599 | 1600 |
1600 // Push all useful nodes onto CG list and set their type. | 1601 // Push all useful nodes onto CG list and set their type. |
1601 for( uint next = 0; next < worklist_init.size(); ++next ) { | 1602 for( uint next = 0; next < worklist_init.size(); ++next ) { |
1602 Node* n = worklist_init.at(next); | 1603 Node* n = worklist_init.at(next); |
1616 _mergemem_worklist.append(n->as_MergeMem()); | 1617 _mergemem_worklist.append(n->as_MergeMem()); |
1617 } else if (OptimizePtrCompare && n->is_Cmp() && | 1618 } else if (OptimizePtrCompare && n->is_Cmp() && |
1618 (n->Opcode() == Op_CmpP || n->Opcode() == Op_CmpN)) { | 1619 (n->Opcode() == Op_CmpP || n->Opcode() == Op_CmpN)) { |
1619 // Compare pointers nodes | 1620 // Compare pointers nodes |
1620 ptr_cmp_worklist.append(n); | 1621 ptr_cmp_worklist.append(n); |
1622 } else if (n->is_MemBarStoreStore()) { | |
1623 // Collect all MemBarStoreStore nodes so that depending on the | |
1624 // escape status of the associated Allocate node some of them | |
1625 // may be eliminated. | |
1626 storestore_worklist.append(n); | |
1621 } | 1627 } |
1622 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { | 1628 for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
1623 Node* m = n->fast_out(i); // Get user | 1629 Node* m = n->fast_out(i); // Get user |
1624 worklist_init.push(m); | 1630 worklist_init.push(m); |
1625 } | 1631 } |
1679 // Normally only 1-3 passes needed to build | 1685 // Normally only 1-3 passes needed to build |
1680 // Connection Graph depending on graph complexity. | 1686 // Connection Graph depending on graph complexity. |
1681 // Observed 8 passes in jvm2008 compiler.compiler. | 1687 // Observed 8 passes in jvm2008 compiler.compiler. |
1682 // Set limit to 20 to catch situation when something | 1688 // Set limit to 20 to catch situation when something |
1683 // did go wrong and recompile the method without EA. | 1689 // did go wrong and recompile the method without EA. |
1690 // Also limit build time to 30 sec (60 in debug VM). | |
1684 | 1691 |
1685 #define CG_BUILD_ITER_LIMIT 20 | 1692 #define CG_BUILD_ITER_LIMIT 20 |
1693 | |
1694 #ifdef ASSERT | |
1695 #define CG_BUILD_TIME_LIMIT 60.0 | |
1696 #else | |
1697 #define CG_BUILD_TIME_LIMIT 30.0 | |
1698 #endif | |
1686 | 1699 |
1687 uint length = worklist.length(); | 1700 uint length = worklist.length(); |
1688 int iterations = 0; | 1701 int iterations = 0; |
1689 while(_progress && (iterations++ < CG_BUILD_ITER_LIMIT)) { | 1702 elapsedTimer time; |
1703 while(_progress && | |
1704 (iterations++ < CG_BUILD_ITER_LIMIT) && | |
1705 (time.seconds() < CG_BUILD_TIME_LIMIT)) { | |
1706 time.start(); | |
1690 _progress = false; | 1707 _progress = false; |
1691 for( uint next = 0; next < length; ++next ) { | 1708 for( uint next = 0; next < length; ++next ) { |
1692 int ni = worklist.at(next); | 1709 int ni = worklist.at(next); |
1693 PointsToNode* ptn = ptnode_adr(ni); | 1710 PointsToNode* ptn = ptnode_adr(ni); |
1694 Node* n = ptn->_node; | 1711 Node* n = ptn->_node; |
1695 assert(n != NULL, "should be known node"); | 1712 assert(n != NULL, "should be known node"); |
1696 build_connection_graph(n, igvn); | 1713 build_connection_graph(n, igvn); |
1697 } | 1714 } |
1698 } | 1715 time.stop(); |
1699 if (iterations >= CG_BUILD_ITER_LIMIT) { | 1716 } |
1700 assert(iterations < CG_BUILD_ITER_LIMIT, | 1717 if ((iterations >= CG_BUILD_ITER_LIMIT) || |
1701 err_msg("infinite EA connection graph build with %d nodes and worklist size %d", | 1718 (time.seconds() >= CG_BUILD_TIME_LIMIT)) { |
1702 nodes_size(), length)); | 1719 assert(false, err_msg("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d", |
1720 time.seconds(), iterations, nodes_size(), length)); | |
1703 // Possible infinite build_connection_graph loop, | 1721 // Possible infinite build_connection_graph loop, |
1704 // retry compilation without escape analysis. | 1722 // bailout (no changes to ideal graph were made). |
1705 C->record_failure(C2Compiler::retry_no_escape_analysis()); | |
1706 _collecting = false; | 1723 _collecting = false; |
1707 return false; | 1724 return false; |
1708 } | 1725 } |
1709 #undef CG_BUILD_ITER_LIMIT | 1726 #undef CG_BUILD_ITER_LIMIT |
1727 #undef CG_BUILD_TIME_LIMIT | |
1710 | 1728 |
1711 // 5. Propagate escaped states. | 1729 // 5. Propagate escaped states. |
1712 worklist.clear(); | 1730 worklist.clear(); |
1713 | 1731 |
1714 // mark all nodes reachable from GlobalEscape nodes | 1732 // mark all nodes reachable from GlobalEscape nodes |
1722 | 1740 |
1723 // 6. Find fields initializing values for not escaped allocations | 1741 // 6. Find fields initializing values for not escaped allocations |
1724 uint alloc_length = alloc_worklist.length(); | 1742 uint alloc_length = alloc_worklist.length(); |
1725 for (uint next = 0; next < alloc_length; ++next) { | 1743 for (uint next = 0; next < alloc_length; ++next) { |
1726 Node* n = alloc_worklist.at(next); | 1744 Node* n = alloc_worklist.at(next); |
1727 if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) { | 1745 PointsToNode::EscapeState es = ptnode_adr(n->_idx)->escape_state(); |
1746 if (es == PointsToNode::NoEscape) { | |
1728 has_non_escaping_obj = true; | 1747 has_non_escaping_obj = true; |
1729 if (n->is_Allocate()) { | 1748 if (n->is_Allocate()) { |
1730 find_init_values(n, &visited, igvn); | 1749 find_init_values(n, &visited, igvn); |
1731 } | 1750 // The object allocated by this Allocate node will never be |
1751 // seen by an other thread. Mark it so that when it is | |
1752 // expanded no MemBarStoreStore is added. | |
1753 n->as_Allocate()->initialization()->set_does_not_escape(); | |
1754 } | |
1755 } else if ((es == PointsToNode::ArgEscape) && n->is_Allocate()) { | |
1756 // Same as above. Mark this Allocate node so that when it is | |
1757 // expanded no MemBarStoreStore is added. | |
1758 n->as_Allocate()->initialization()->set_does_not_escape(); | |
1732 } | 1759 } |
1733 } | 1760 } |
1734 | 1761 |
1735 uint cg_length = cg_worklist.length(); | 1762 uint cg_length = cg_worklist.length(); |
1736 | 1763 |
1825 int cnt = C->macro_count(); | 1852 int cnt = C->macro_count(); |
1826 for( int i=0; i < cnt; i++ ) { | 1853 for( int i=0; i < cnt; i++ ) { |
1827 Node *n = C->macro_node(i); | 1854 Node *n = C->macro_node(i); |
1828 if (n->is_AbstractLock()) { // Lock and Unlock nodes | 1855 if (n->is_AbstractLock()) { // Lock and Unlock nodes |
1829 AbstractLockNode* alock = n->as_AbstractLock(); | 1856 AbstractLockNode* alock = n->as_AbstractLock(); |
1830 if (!alock->is_eliminated() || alock->is_coarsened()) { | 1857 if (!alock->is_non_esc_obj()) { |
1831 PointsToNode::EscapeState es = escape_state(alock->obj_node()); | 1858 PointsToNode::EscapeState es = escape_state(alock->obj_node()); |
1832 assert(es != PointsToNode::UnknownEscape, "should know"); | 1859 assert(es != PointsToNode::UnknownEscape, "should know"); |
1833 if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { | 1860 if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { |
1834 if (!alock->is_eliminated()) { | 1861 assert(!alock->is_eliminated() || alock->is_coarsened(), "sanity"); |
1835 // Mark it eliminated to update any counters | 1862 // The lock could be marked eliminated by lock coarsening |
1836 alock->set_eliminated(); | 1863 // code during first IGVN before EA. Replace coarsened flag |
1837 } else { | 1864 // to eliminate all associated locks/unlocks. |
1838 // The lock could be marked eliminated by lock coarsening | 1865 alock->set_non_esc_obj(); |
1839 // code during first IGVN before EA. Clear coarsened flag | |
1840 // to eliminate all associated locks/unlocks and relock | |
1841 // during deoptimization. | |
1842 alock->clear_coarsened(); | |
1843 } | |
1844 } | 1866 } |
1845 } | 1867 } |
1846 } | 1868 } |
1847 } | 1869 } |
1848 } | 1870 } |
1870 // cleanup | 1892 // cleanup |
1871 if (_pcmp_neq->outcnt() == 0) | 1893 if (_pcmp_neq->outcnt() == 0) |
1872 igvn->hash_delete(_pcmp_neq); | 1894 igvn->hash_delete(_pcmp_neq); |
1873 if (_pcmp_eq->outcnt() == 0) | 1895 if (_pcmp_eq->outcnt() == 0) |
1874 igvn->hash_delete(_pcmp_eq); | 1896 igvn->hash_delete(_pcmp_eq); |
1897 } | |
1898 | |
1899 // For MemBarStoreStore nodes added in library_call.cpp, check | |
1900 // escape status of associated AllocateNode and optimize out | |
1901 // MemBarStoreStore node if the allocated object never escapes. | |
1902 while (storestore_worklist.length() != 0) { | |
1903 Node *n = storestore_worklist.pop(); | |
1904 MemBarStoreStoreNode *storestore = n ->as_MemBarStoreStore(); | |
1905 Node *alloc = storestore->in(MemBarNode::Precedent)->in(0); | |
1906 assert (alloc->is_Allocate(), "storestore should point to AllocateNode"); | |
1907 PointsToNode::EscapeState es = ptnode_adr(alloc->_idx)->escape_state(); | |
1908 if (es == PointsToNode::NoEscape || es == PointsToNode::ArgEscape) { | |
1909 MemBarNode* mb = MemBarNode::make(C, Op_MemBarCPUOrder, Compile::AliasIdxBot); | |
1910 mb->init_req(TypeFunc::Memory, storestore->in(TypeFunc::Memory)); | |
1911 mb->init_req(TypeFunc::Control, storestore->in(TypeFunc::Control)); | |
1912 | |
1913 _igvn->register_new_node_with_optimizer(mb); | |
1914 _igvn->replace_node(storestore, mb); | |
1915 } | |
1875 } | 1916 } |
1876 | 1917 |
1877 #ifndef PRODUCT | 1918 #ifndef PRODUCT |
1878 if (PrintEscapeAnalysis) { | 1919 if (PrintEscapeAnalysis) { |
1879 dump(); // Dump ConnectionGraph | 1920 dump(); // Dump ConnectionGraph |
2261 Node *arg = call->in(i)->uncast(); | 2302 Node *arg = call->in(i)->uncast(); |
2262 const Type *aat = phase->type(arg); | 2303 const Type *aat = phase->type(arg); |
2263 PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state(); | 2304 PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state(); |
2264 if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() && | 2305 if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() && |
2265 (is_arraycopy || arg_esc < PointsToNode::ArgEscape)) { | 2306 (is_arraycopy || arg_esc < PointsToNode::ArgEscape)) { |
2266 | 2307 #ifdef ASSERT |
2267 assert(aat == Type::TOP || aat == TypePtr::NULL_PTR || | 2308 assert(aat == Type::TOP || aat == TypePtr::NULL_PTR || |
2268 aat->isa_ptr() != NULL, "expecting an Ptr"); | 2309 aat->isa_ptr() != NULL, "expecting an Ptr"); |
2310 if (!(is_arraycopy || | |
2311 call->as_CallLeaf()->_name != NULL && | |
2312 (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || | |
2313 strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) | |
2314 ) { | |
2315 call->dump(); | |
2316 assert(false, "EA: unexpected CallLeaf"); | |
2317 } | |
2318 #endif | |
2319 if (arg_esc < PointsToNode::ArgEscape) { | |
2320 set_escape_state(arg->_idx, PointsToNode::ArgEscape); | |
2321 Node* arg_base = arg; | |
2322 if (arg->is_AddP()) { | |
2323 // | |
2324 // The inline_native_clone() case when the arraycopy stub is called | |
2325 // after the allocation before Initialize and CheckCastPP nodes. | |
2326 // Or normal arraycopy for object arrays case. | |
2327 // | |
2328 // Set AddP's base (Allocate) as not scalar replaceable since | |
2329 // pointer to the base (with offset) is passed as argument. | |
2330 // | |
2331 arg_base = get_addp_base(arg); | |
2332 set_escape_state(arg_base->_idx, PointsToNode::ArgEscape); | |
2333 } | |
2334 } | |
2335 | |
2269 bool arg_has_oops = aat->isa_oopptr() && | 2336 bool arg_has_oops = aat->isa_oopptr() && |
2270 (aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() || | 2337 (aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() || |
2271 (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass())); | 2338 (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass())); |
2272 if (i == TypeFunc::Parms) { | 2339 if (i == TypeFunc::Parms) { |
2273 src_has_oops = arg_has_oops; | 2340 src_has_oops = arg_has_oops; |
2276 // src or dst could be j.l.Object when other is basic type array: | 2343 // src or dst could be j.l.Object when other is basic type array: |
2277 // | 2344 // |
2278 // arraycopy(char[],0,Object*,0,size); | 2345 // arraycopy(char[],0,Object*,0,size); |
2279 // arraycopy(Object*,0,char[],0,size); | 2346 // arraycopy(Object*,0,char[],0,size); |
2280 // | 2347 // |
2281 // Don't add edges from dst's fields in such cases. | 2348 // Do nothing special in such cases. |
2282 // | 2349 // |
2283 bool arg_is_arraycopy_dest = src_has_oops && is_arraycopy && | 2350 if (is_arraycopy && (i > TypeFunc::Parms) && |
2284 arg_has_oops && (i > TypeFunc::Parms); | 2351 src_has_oops && arg_has_oops) { |
2285 #ifdef ASSERT | 2352 // Destination object's fields reference an unknown object. |
2286 if (!(is_arraycopy || | 2353 Node* arg_base = arg; |
2287 call->as_CallLeaf()->_name != NULL && | 2354 if (arg->is_AddP()) { |
2288 (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || | 2355 arg_base = get_addp_base(arg); |
2289 strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) | 2356 } |
2290 ) { | 2357 for (VectorSetI s(PointsTo(arg_base)); s.test(); ++s) { |
2291 call->dump(); | 2358 uint ps = s.elem; |
2292 assert(false, "EA: unexpected CallLeaf"); | 2359 set_escape_state(ps, PointsToNode::ArgEscape); |
2293 } | 2360 add_edge_from_fields(ps, _phantom_object, Type::OffsetBot); |
2294 #endif | 2361 } |
2295 // Always process arraycopy's destination object since | 2362 // Conservatively all values in source object fields globally escape |
2296 // we need to add all possible edges to references in | 2363 // since we don't know if values in destination object fields |
2297 // source object. | 2364 // escape (it could be traced but it is too expensive). |
2298 if (arg_esc >= PointsToNode::ArgEscape && | 2365 Node* src = call->in(TypeFunc::Parms)->uncast(); |
2299 !arg_is_arraycopy_dest) { | 2366 Node* src_base = src; |
2300 continue; | 2367 if (src->is_AddP()) { |
2301 } | 2368 src_base = get_addp_base(src); |
2302 set_escape_state(arg->_idx, PointsToNode::ArgEscape); | 2369 } |
2303 Node* arg_base = arg; | 2370 for (VectorSetI s(PointsTo(src_base)); s.test(); ++s) { |
2304 if (arg->is_AddP()) { | 2371 uint ps = s.elem; |
2305 // | 2372 set_escape_state(ps, PointsToNode::ArgEscape); |
2306 // The inline_native_clone() case when the arraycopy stub is called | 2373 // Use OffsetTop to indicate fields global escape. |
2307 // after the allocation before Initialize and CheckCastPP nodes. | 2374 add_edge_from_fields(ps, _phantom_object, Type::OffsetTop); |
2308 // Or normal arraycopy for object arrays case. | |
2309 // | |
2310 // Set AddP's base (Allocate) as not scalar replaceable since | |
2311 // pointer to the base (with offset) is passed as argument. | |
2312 // | |
2313 arg_base = get_addp_base(arg); | |
2314 } | |
2315 VectorSet argset = *PointsTo(arg_base); // Clone set | |
2316 for( VectorSetI j(&argset); j.test(); ++j ) { | |
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 } | 2375 } |
2361 } | 2376 } |
2362 } | 2377 } |
2363 } | 2378 } |
2364 break; | 2379 break; |