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; |