Fri, 10 Feb 2012 12:53:43 -0800
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
src/share/vm/opto/escape.cpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/vm/opto/escape.cpp Thu Feb 09 18:01:20 2012 -0800 1.2 +++ b/src/share/vm/opto/escape.cpp Fri Feb 10 12:53:43 2012 -0800 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -1687,12 +1687,23 @@ 1.11 // Observed 8 passes in jvm2008 compiler.compiler. 1.12 // Set limit to 20 to catch situation when something 1.13 // did go wrong and recompile the method without EA. 1.14 + // Also limit build time to 30 sec (60 in debug VM). 1.15 1.16 #define CG_BUILD_ITER_LIMIT 20 1.17 1.18 +#ifdef ASSERT 1.19 +#define CG_BUILD_TIME_LIMIT 60.0 1.20 +#else 1.21 +#define CG_BUILD_TIME_LIMIT 30.0 1.22 +#endif 1.23 + 1.24 uint length = worklist.length(); 1.25 int iterations = 0; 1.26 - while(_progress && (iterations++ < CG_BUILD_ITER_LIMIT)) { 1.27 + elapsedTimer time; 1.28 + while(_progress && 1.29 + (iterations++ < CG_BUILD_ITER_LIMIT) && 1.30 + (time.seconds() < CG_BUILD_TIME_LIMIT)) { 1.31 + time.start(); 1.32 _progress = false; 1.33 for( uint next = 0; next < length; ++next ) { 1.34 int ni = worklist.at(next); 1.35 @@ -1701,18 +1712,19 @@ 1.36 assert(n != NULL, "should be known node"); 1.37 build_connection_graph(n, igvn); 1.38 } 1.39 + time.stop(); 1.40 } 1.41 - if (iterations >= CG_BUILD_ITER_LIMIT) { 1.42 - assert(iterations < CG_BUILD_ITER_LIMIT, 1.43 - err_msg("infinite EA connection graph build with %d nodes and worklist size %d", 1.44 - nodes_size(), length)); 1.45 + if ((iterations >= CG_BUILD_ITER_LIMIT) || 1.46 + (time.seconds() >= CG_BUILD_TIME_LIMIT)) { 1.47 + assert(false, err_msg("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d", 1.48 + time.seconds(), iterations, nodes_size(), length)); 1.49 // Possible infinite build_connection_graph loop, 1.50 - // retry compilation without escape analysis. 1.51 - C->record_failure(C2Compiler::retry_no_escape_analysis()); 1.52 + // bailout (no changes to ideal graph were made). 1.53 _collecting = false; 1.54 return false; 1.55 } 1.56 #undef CG_BUILD_ITER_LIMIT 1.57 +#undef CG_BUILD_TIME_LIMIT 1.58 1.59 // 5. Propagate escaped states. 1.60 worklist.clear(); 1.61 @@ -2292,9 +2304,35 @@ 1.62 PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state(); 1.63 if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() && 1.64 (is_arraycopy || arg_esc < PointsToNode::ArgEscape)) { 1.65 - 1.66 +#ifdef ASSERT 1.67 assert(aat == Type::TOP || aat == TypePtr::NULL_PTR || 1.68 aat->isa_ptr() != NULL, "expecting an Ptr"); 1.69 + if (!(is_arraycopy || 1.70 + call->as_CallLeaf()->_name != NULL && 1.71 + (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || 1.72 + strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) 1.73 + ) { 1.74 + call->dump(); 1.75 + assert(false, "EA: unexpected CallLeaf"); 1.76 + } 1.77 +#endif 1.78 + if (arg_esc < PointsToNode::ArgEscape) { 1.79 + set_escape_state(arg->_idx, PointsToNode::ArgEscape); 1.80 + Node* arg_base = arg; 1.81 + if (arg->is_AddP()) { 1.82 + // 1.83 + // The inline_native_clone() case when the arraycopy stub is called 1.84 + // after the allocation before Initialize and CheckCastPP nodes. 1.85 + // Or normal arraycopy for object arrays case. 1.86 + // 1.87 + // Set AddP's base (Allocate) as not scalar replaceable since 1.88 + // pointer to the base (with offset) is passed as argument. 1.89 + // 1.90 + arg_base = get_addp_base(arg); 1.91 + set_escape_state(arg_base->_idx, PointsToNode::ArgEscape); 1.92 + } 1.93 + } 1.94 + 1.95 bool arg_has_oops = aat->isa_oopptr() && 1.96 (aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() || 1.97 (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass())); 1.98 @@ -2307,85 +2345,33 @@ 1.99 // arraycopy(char[],0,Object*,0,size); 1.100 // arraycopy(Object*,0,char[],0,size); 1.101 // 1.102 - // Don't add edges from dst's fields in such cases. 1.103 + // Do nothing special in such cases. 1.104 // 1.105 - bool arg_is_arraycopy_dest = src_has_oops && is_arraycopy && 1.106 - arg_has_oops && (i > TypeFunc::Parms); 1.107 -#ifdef ASSERT 1.108 - if (!(is_arraycopy || 1.109 - call->as_CallLeaf()->_name != NULL && 1.110 - (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || 1.111 - strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) 1.112 - ) { 1.113 - call->dump(); 1.114 - assert(false, "EA: unexpected CallLeaf"); 1.115 - } 1.116 -#endif 1.117 - // Always process arraycopy's destination object since 1.118 - // we need to add all possible edges to references in 1.119 - // source object. 1.120 - if (arg_esc >= PointsToNode::ArgEscape && 1.121 - !arg_is_arraycopy_dest) { 1.122 - continue; 1.123 - } 1.124 - set_escape_state(arg->_idx, PointsToNode::ArgEscape); 1.125 - Node* arg_base = arg; 1.126 - if (arg->is_AddP()) { 1.127 - // 1.128 - // The inline_native_clone() case when the arraycopy stub is called 1.129 - // after the allocation before Initialize and CheckCastPP nodes. 1.130 - // Or normal arraycopy for object arrays case. 1.131 - // 1.132 - // Set AddP's base (Allocate) as not scalar replaceable since 1.133 - // pointer to the base (with offset) is passed as argument. 1.134 - // 1.135 - arg_base = get_addp_base(arg); 1.136 - } 1.137 - VectorSet argset = *PointsTo(arg_base); // Clone set 1.138 - for( VectorSetI j(&argset); j.test(); ++j ) { 1.139 - uint pd = j.elem; // Destination object 1.140 - set_escape_state(pd, PointsToNode::ArgEscape); 1.141 - 1.142 - if (arg_is_arraycopy_dest) { 1.143 - PointsToNode* ptd = ptnode_adr(pd); 1.144 - // Conservatively reference an unknown object since 1.145 - // not all source's fields/elements may be known. 1.146 - add_edge_from_fields(pd, _phantom_object, Type::OffsetBot); 1.147 - 1.148 - Node *src = call->in(TypeFunc::Parms)->uncast(); 1.149 - Node* src_base = src; 1.150 - if (src->is_AddP()) { 1.151 - src_base = get_addp_base(src); 1.152 - } 1.153 - // Create edges from destination's fields to 1.154 - // everything known source's fields could point to. 1.155 - for( VectorSetI s(PointsTo(src_base)); s.test(); ++s ) { 1.156 - uint ps = s.elem; 1.157 - bool has_bottom_offset = false; 1.158 - for (uint fd = 0; fd < ptd->edge_count(); fd++) { 1.159 - assert(ptd->edge_type(fd) == PointsToNode::FieldEdge, "expecting a field edge"); 1.160 - int fdi = ptd->edge_target(fd); 1.161 - PointsToNode* pfd = ptnode_adr(fdi); 1.162 - int offset = pfd->offset(); 1.163 - if (offset == Type::OffsetBot) 1.164 - has_bottom_offset = true; 1.165 - assert(offset != -1, "offset should be set"); 1.166 - add_deferred_edge_to_fields(fdi, ps, offset); 1.167 - } 1.168 - // Destination object may not have access (no field edge) 1.169 - // to fields which are accessed in source object. 1.170 - // As result no edges will be created to those source's 1.171 - // fields and escape state of destination object will 1.172 - // not be propagated to those fields. 1.173 - // 1.174 - // Mark source object as global escape except in 1.175 - // the case with Type::OffsetBot field (which is 1.176 - // common case for array elements access) when 1.177 - // edges are created to all source's fields. 1.178 - if (!has_bottom_offset) { 1.179 - set_escape_state(ps, PointsToNode::GlobalEscape); 1.180 - } 1.181 - } 1.182 + if (is_arraycopy && (i > TypeFunc::Parms) && 1.183 + src_has_oops && arg_has_oops) { 1.184 + // Destination object's fields reference an unknown object. 1.185 + Node* arg_base = arg; 1.186 + if (arg->is_AddP()) { 1.187 + arg_base = get_addp_base(arg); 1.188 + } 1.189 + for (VectorSetI s(PointsTo(arg_base)); s.test(); ++s) { 1.190 + uint ps = s.elem; 1.191 + set_escape_state(ps, PointsToNode::ArgEscape); 1.192 + add_edge_from_fields(ps, _phantom_object, Type::OffsetBot); 1.193 + } 1.194 + // Conservatively all values in source object fields globally escape 1.195 + // since we don't know if values in destination object fields 1.196 + // escape (it could be traced but it is too expensive). 1.197 + Node* src = call->in(TypeFunc::Parms)->uncast(); 1.198 + Node* src_base = src; 1.199 + if (src->is_AddP()) { 1.200 + src_base = get_addp_base(src); 1.201 + } 1.202 + for (VectorSetI s(PointsTo(src_base)); s.test(); ++s) { 1.203 + uint ps = s.elem; 1.204 + set_escape_state(ps, PointsToNode::ArgEscape); 1.205 + // Use OffsetTop to indicate fields global escape. 1.206 + add_edge_from_fields(ps, _phantom_object, Type::OffsetTop); 1.207 } 1.208 } 1.209 }