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;