comparison src/share/vm/opto/escape.cpp @ 4937:73df3733f2eb

7129284: +DoEscapeAnalysis regression w/ early build of 7u4 (HotSpot 23) on Linux Summary: Removed code which tried to create edges from fields of destination objects of arraycopy to fields of source objects. Added 30 sec time limit for EA graph construction. Reviewed-by: never
author kvn
date Fri, 10 Feb 2012 12:53:43 -0800
parents e9a5e0a812c8
children 9a72c7ece7fb
comparison
equal deleted inserted replaced
4896:2f985b6ce7ff 4937:73df3733f2eb
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.
1685 // Normally only 1-3 passes needed to build 1685 // Normally only 1-3 passes needed to build
1686 // Connection Graph depending on graph complexity. 1686 // Connection Graph depending on graph complexity.
1687 // Observed 8 passes in jvm2008 compiler.compiler. 1687 // Observed 8 passes in jvm2008 compiler.compiler.
1688 // Set limit to 20 to catch situation when something 1688 // Set limit to 20 to catch situation when something
1689 // 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).
1690 1691
1691 #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
1692 1699
1693 uint length = worklist.length(); 1700 uint length = worklist.length();
1694 int iterations = 0; 1701 int iterations = 0;
1695 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();
1696 _progress = false; 1707 _progress = false;
1697 for( uint next = 0; next < length; ++next ) { 1708 for( uint next = 0; next < length; ++next ) {
1698 int ni = worklist.at(next); 1709 int ni = worklist.at(next);
1699 PointsToNode* ptn = ptnode_adr(ni); 1710 PointsToNode* ptn = ptnode_adr(ni);
1700 Node* n = ptn->_node; 1711 Node* n = ptn->_node;
1701 assert(n != NULL, "should be known node"); 1712 assert(n != NULL, "should be known node");
1702 build_connection_graph(n, igvn); 1713 build_connection_graph(n, igvn);
1703 } 1714 }
1704 } 1715 time.stop();
1705 if (iterations >= CG_BUILD_ITER_LIMIT) { 1716 }
1706 assert(iterations < CG_BUILD_ITER_LIMIT, 1717 if ((iterations >= CG_BUILD_ITER_LIMIT) ||
1707 err_msg("infinite EA connection graph build with %d nodes and worklist size %d", 1718 (time.seconds() >= CG_BUILD_TIME_LIMIT)) {
1708 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));
1709 // Possible infinite build_connection_graph loop, 1721 // Possible infinite build_connection_graph loop,
1710 // retry compilation without escape analysis. 1722 // bailout (no changes to ideal graph were made).
1711 C->record_failure(C2Compiler::retry_no_escape_analysis());
1712 _collecting = false; 1723 _collecting = false;
1713 return false; 1724 return false;
1714 } 1725 }
1715 #undef CG_BUILD_ITER_LIMIT 1726 #undef CG_BUILD_ITER_LIMIT
1727 #undef CG_BUILD_TIME_LIMIT
1716 1728
1717 // 5. Propagate escaped states. 1729 // 5. Propagate escaped states.
1718 worklist.clear(); 1730 worklist.clear();
1719 1731
1720 // mark all nodes reachable from GlobalEscape nodes 1732 // mark all nodes reachable from GlobalEscape nodes
2290 Node *arg = call->in(i)->uncast(); 2302 Node *arg = call->in(i)->uncast();
2291 const Type *aat = phase->type(arg); 2303 const Type *aat = phase->type(arg);
2292 PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state(); 2304 PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state();
2293 if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() && 2305 if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() &&
2294 (is_arraycopy || arg_esc < PointsToNode::ArgEscape)) { 2306 (is_arraycopy || arg_esc < PointsToNode::ArgEscape)) {
2295 2307 #ifdef ASSERT
2296 assert(aat == Type::TOP || aat == TypePtr::NULL_PTR || 2308 assert(aat == Type::TOP || aat == TypePtr::NULL_PTR ||
2297 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
2298 bool arg_has_oops = aat->isa_oopptr() && 2336 bool arg_has_oops = aat->isa_oopptr() &&
2299 (aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() || 2337 (aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() ||
2300 (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass())); 2338 (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass()));
2301 if (i == TypeFunc::Parms) { 2339 if (i == TypeFunc::Parms) {
2302 src_has_oops = arg_has_oops; 2340 src_has_oops = arg_has_oops;
2305 // 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:
2306 // 2344 //
2307 // arraycopy(char[],0,Object*,0,size); 2345 // arraycopy(char[],0,Object*,0,size);
2308 // arraycopy(Object*,0,char[],0,size); 2346 // arraycopy(Object*,0,char[],0,size);
2309 // 2347 //
2310 // Don't add edges from dst's fields in such cases. 2348 // Do nothing special in such cases.
2311 // 2349 //
2312 bool arg_is_arraycopy_dest = src_has_oops && is_arraycopy && 2350 if (is_arraycopy && (i > TypeFunc::Parms) &&
2313 arg_has_oops && (i > TypeFunc::Parms); 2351 src_has_oops && arg_has_oops) {
2314 #ifdef ASSERT 2352 // Destination object's fields reference an unknown object.
2315 if (!(is_arraycopy || 2353 Node* arg_base = arg;
2316 call->as_CallLeaf()->_name != NULL && 2354 if (arg->is_AddP()) {
2317 (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || 2355 arg_base = get_addp_base(arg);
2318 strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) 2356 }
2319 ) { 2357 for (VectorSetI s(PointsTo(arg_base)); s.test(); ++s) {
2320 call->dump(); 2358 uint ps = s.elem;
2321 assert(false, "EA: unexpected CallLeaf"); 2359 set_escape_state(ps, PointsToNode::ArgEscape);
2322 } 2360 add_edge_from_fields(ps, _phantom_object, Type::OffsetBot);
2323 #endif 2361 }
2324 // Always process arraycopy's destination object since 2362 // Conservatively all values in source object fields globally escape
2325 // we need to add all possible edges to references in 2363 // since we don't know if values in destination object fields
2326 // source object. 2364 // escape (it could be traced but it is too expensive).
2327 if (arg_esc >= PointsToNode::ArgEscape && 2365 Node* src = call->in(TypeFunc::Parms)->uncast();
2328 !arg_is_arraycopy_dest) { 2366 Node* src_base = src;
2329 continue; 2367 if (src->is_AddP()) {
2330 } 2368 src_base = get_addp_base(src);
2331 set_escape_state(arg->_idx, PointsToNode::ArgEscape); 2369 }
2332 Node* arg_base = arg; 2370 for (VectorSetI s(PointsTo(src_base)); s.test(); ++s) {
2333 if (arg->is_AddP()) { 2371 uint ps = s.elem;
2334 // 2372 set_escape_state(ps, PointsToNode::ArgEscape);
2335 // The inline_native_clone() case when the arraycopy stub is called 2373 // Use OffsetTop to indicate fields global escape.
2336 // after the allocation before Initialize and CheckCastPP nodes. 2374 add_edge_from_fields(ps, _phantom_object, Type::OffsetTop);
2337 // Or normal arraycopy for object arrays case.
2338 //
2339 // Set AddP's base (Allocate) as not scalar replaceable since
2340 // pointer to the base (with offset) is passed as argument.
2341 //
2342 arg_base = get_addp_base(arg);
2343 }
2344 VectorSet argset = *PointsTo(arg_base); // Clone set
2345 for( VectorSetI j(&argset); j.test(); ++j ) {
2346 uint pd = j.elem; // Destination object
2347 set_escape_state(pd, PointsToNode::ArgEscape);
2348
2349 if (arg_is_arraycopy_dest) {
2350 PointsToNode* ptd = ptnode_adr(pd);
2351 // Conservatively reference an unknown object since
2352 // not all source's fields/elements may be known.
2353 add_edge_from_fields(pd, _phantom_object, Type::OffsetBot);
2354
2355 Node *src = call->in(TypeFunc::Parms)->uncast();
2356 Node* src_base = src;
2357 if (src->is_AddP()) {
2358 src_base = get_addp_base(src);
2359 }
2360 // Create edges from destination's fields to
2361 // everything known source's fields could point to.
2362 for( VectorSetI s(PointsTo(src_base)); s.test(); ++s ) {
2363 uint ps = s.elem;
2364 bool has_bottom_offset = false;
2365 for (uint fd = 0; fd < ptd->edge_count(); fd++) {
2366 assert(ptd->edge_type(fd) == PointsToNode::FieldEdge, "expecting a field edge");
2367 int fdi = ptd->edge_target(fd);
2368 PointsToNode* pfd = ptnode_adr(fdi);
2369 int offset = pfd->offset();
2370 if (offset == Type::OffsetBot)
2371 has_bottom_offset = true;
2372 assert(offset != -1, "offset should be set");
2373 add_deferred_edge_to_fields(fdi, ps, offset);
2374 }
2375 // Destination object may not have access (no field edge)
2376 // to fields which are accessed in source object.
2377 // As result no edges will be created to those source's
2378 // fields and escape state of destination object will
2379 // not be propagated to those fields.
2380 //
2381 // Mark source object as global escape except in
2382 // the case with Type::OffsetBot field (which is
2383 // common case for array elements access) when
2384 // edges are created to all source's fields.
2385 if (!has_bottom_offset) {
2386 set_escape_state(ps, PointsToNode::GlobalEscape);
2387 }
2388 }
2389 } 2375 }
2390 } 2376 }
2391 } 2377 }
2392 } 2378 }
2393 break; 2379 break;