Mon, 07 Nov 2011 14:33:57 -0800
7059047: EA: can't find initializing store with several CheckCastPP
Summary: Split adjust_escape_state() method into two methods to find initializing stores.
Reviewed-by: never
src/share/vm/opto/escape.cpp | file | annotate | diff | comparison | revisions | |
src/share/vm/opto/escape.hpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/vm/opto/escape.cpp Fri Nov 04 13:55:31 2011 -0700 1.2 +++ b/src/share/vm/opto/escape.cpp Mon Nov 07 14:33:57 2011 -0800 1.3 @@ -378,16 +378,17 @@ 1.4 // whose offset matches "offset". 1.5 void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) { 1.6 PointsToNode* an = ptnode_adr(adr_i); 1.7 + bool is_alloc = an->_node->is_Allocate(); 1.8 for (uint fe = 0; fe < an->edge_count(); fe++) { 1.9 assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); 1.10 int fi = an->edge_target(fe); 1.11 PointsToNode* pf = ptnode_adr(fi); 1.12 - int po = pf->offset(); 1.13 - if (pf->edge_count() == 0) { 1.14 - // we have not seen any stores to this field, assume it was set outside this method 1.15 + int offset = pf->offset(); 1.16 + if (!is_alloc) { 1.17 + // Assume the field was set outside this method if it is not Allocation 1.18 add_pointsto_edge(fi, _phantom_object); 1.19 } 1.20 - if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { 1.21 + if (offset == offs || offset == Type::OffsetBot || offs == Type::OffsetBot) { 1.22 add_deferred_edge(from_i, fi); 1.23 } 1.24 } 1.25 @@ -1041,7 +1042,7 @@ 1.26 PointsToNode::EscapeState es = escape_state(alloc); 1.27 // We have an allocation or call which returns a Java object, 1.28 // see if it is unescaped. 1.29 - if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable) 1.30 + if (es != PointsToNode::NoEscape || !ptn->scalar_replaceable()) 1.31 continue; 1.32 1.33 // Find CheckCastPP for the allocate or for the return value of a call 1.34 @@ -1090,7 +1091,7 @@ 1.35 // so it could be eliminated. 1.36 alloc->as_Allocate()->_is_scalar_replaceable = true; 1.37 } 1.38 - set_escape_state(n->_idx, es); 1.39 + set_escape_state(n->_idx, es); // CheckCastPP escape state 1.40 // in order for an object to be scalar-replaceable, it must be: 1.41 // - a direct allocation (not a call returning an object) 1.42 // - non-escaping 1.43 @@ -1102,15 +1103,14 @@ 1.44 set_map(n->_idx, alloc); 1.45 const TypeOopPtr *t = igvn->type(n)->isa_oopptr(); 1.46 if (t == NULL) 1.47 - continue; // not a TypeInstPtr 1.48 + continue; // not a TypeOopPtr 1.49 tinst = t->cast_to_exactness(true)->is_oopptr()->cast_to_instance_id(ni); 1.50 igvn->hash_delete(n); 1.51 igvn->set_type(n, tinst); 1.52 n->raise_bottom_type(tinst); 1.53 igvn->hash_insert(n); 1.54 record_for_optimizer(n); 1.55 - if (alloc->is_Allocate() && ptn->_scalar_replaceable && 1.56 - (t->isa_instptr() || t->isa_aryptr())) { 1.57 + if (alloc->is_Allocate() && (t->isa_instptr() || t->isa_aryptr())) { 1.58 1.59 // First, put on the worklist all Field edges from Connection Graph 1.60 // which is more accurate then putting immediate users from Ideal Graph. 1.61 @@ -1538,7 +1538,8 @@ 1.62 worklist_init.push(C->root()); 1.63 } 1.64 1.65 - GrowableArray<int> cg_worklist; 1.66 + GrowableArray<Node*> alloc_worklist; 1.67 + GrowableArray<Node*> addp_worklist; 1.68 PhaseGVN* igvn = _igvn; 1.69 bool has_allocations = false; 1.70 1.71 @@ -1551,11 +1552,13 @@ 1.72 if (n->is_Allocate() || n->is_CallStaticJava() && 1.73 ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) { 1.74 has_allocations = true; 1.75 + if (n->is_Allocate()) 1.76 + alloc_worklist.append(n); 1.77 } 1.78 if(n->is_AddP()) { 1.79 // Collect address nodes. Use them during stage 3 below 1.80 // to build initial connection graph field edges. 1.81 - cg_worklist.append(n->_idx); 1.82 + addp_worklist.append(n); 1.83 } else if (n->is_MergeMem()) { 1.84 // Collect all MergeMem nodes to add memory slices for 1.85 // scalar replaceable objects in split_unique_types(). 1.86 @@ -1581,10 +1584,9 @@ 1.87 1.88 // 3. Pass to create initial fields edges (JavaObject -F-> AddP) 1.89 // to reduce number of iterations during stage 4 below. 1.90 - uint cg_length = cg_worklist.length(); 1.91 - for( uint next = 0; next < cg_length; ++next ) { 1.92 - int ni = cg_worklist.at(next); 1.93 - Node* n = ptnode_adr(ni)->_node; 1.94 + uint addp_length = addp_worklist.length(); 1.95 + for( uint next = 0; next < addp_length; ++next ) { 1.96 + Node* n = addp_worklist.at(next); 1.97 Node* base = get_addp_base(n); 1.98 if (base->is_Proj()) 1.99 base = base->in(0); 1.100 @@ -1594,7 +1596,7 @@ 1.101 } 1.102 } 1.103 1.104 - cg_worklist.clear(); 1.105 + GrowableArray<int> cg_worklist; 1.106 cg_worklist.append(_phantom_object); 1.107 GrowableArray<uint> worklist; 1.108 1.109 @@ -1653,73 +1655,44 @@ 1.110 1.111 Arena* arena = Thread::current()->resource_area(); 1.112 VectorSet visited(arena); 1.113 + 1.114 + // 5. Find fields initializing values for not escaped allocations 1.115 + uint alloc_length = alloc_worklist.length(); 1.116 + for (uint next = 0; next < alloc_length; ++next) { 1.117 + Node* n = alloc_worklist.at(next); 1.118 + if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) { 1.119 + find_init_values(n, &visited, igvn); 1.120 + } 1.121 + } 1.122 + 1.123 worklist.clear(); 1.124 1.125 - // 5. Remove deferred edges from the graph and adjust 1.126 - // escape state of nonescaping objects. 1.127 - cg_length = cg_worklist.length(); 1.128 - for( uint next = 0; next < cg_length; ++next ) { 1.129 + // 6. Remove deferred edges from the graph. 1.130 + uint cg_length = cg_worklist.length(); 1.131 + for (uint next = 0; next < cg_length; ++next) { 1.132 int ni = cg_worklist.at(next); 1.133 PointsToNode* ptn = ptnode_adr(ni); 1.134 PointsToNode::NodeType nt = ptn->node_type(); 1.135 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { 1.136 remove_deferred(ni, &worklist, &visited); 1.137 Node *n = ptn->_node; 1.138 - if (n->is_AddP()) { 1.139 - // Search for objects which are not scalar replaceable 1.140 - // and adjust their escape state. 1.141 - adjust_escape_state(ni, igvn); 1.142 - } 1.143 } 1.144 } 1.145 1.146 - // 6. Propagate escape states. 1.147 - worklist.clear(); 1.148 - bool has_non_escaping_obj = false; 1.149 - 1.150 - // push all GlobalEscape nodes on the worklist 1.151 - for( uint next = 0; next < cg_length; ++next ) { 1.152 - int nk = cg_worklist.at(next); 1.153 - if (ptnode_adr(nk)->escape_state() == PointsToNode::GlobalEscape) 1.154 - worklist.push(nk); 1.155 - } 1.156 - // mark all nodes reachable from GlobalEscape nodes 1.157 - while(worklist.length() > 0) { 1.158 - PointsToNode* ptn = ptnode_adr(worklist.pop()); 1.159 - uint e_cnt = ptn->edge_count(); 1.160 - for (uint ei = 0; ei < e_cnt; ei++) { 1.161 - uint npi = ptn->edge_target(ei); 1.162 - PointsToNode *np = ptnode_adr(npi); 1.163 - if (np->escape_state() < PointsToNode::GlobalEscape) { 1.164 - set_escape_state(npi, PointsToNode::GlobalEscape); 1.165 - worklist.push(npi); 1.166 - } 1.167 - } 1.168 + // 7. Adjust escape state of nonescaping objects. 1.169 + for (uint next = 0; next < addp_length; ++next) { 1.170 + Node* n = addp_worklist.at(next); 1.171 + adjust_escape_state(n); 1.172 } 1.173 1.174 - // push all ArgEscape nodes on the worklist 1.175 - for( uint next = 0; next < cg_length; ++next ) { 1.176 - int nk = cg_worklist.at(next); 1.177 - if (ptnode_adr(nk)->escape_state() == PointsToNode::ArgEscape) 1.178 - worklist.push(nk); 1.179 - } 1.180 + // 8. Propagate escape states. 1.181 + worklist.clear(); 1.182 + 1.183 + // mark all nodes reachable from GlobalEscape nodes 1.184 + (void)propagate_escape_state(&cg_worklist, &worklist, PointsToNode::GlobalEscape); 1.185 + 1.186 // mark all nodes reachable from ArgEscape nodes 1.187 - while(worklist.length() > 0) { 1.188 - PointsToNode* ptn = ptnode_adr(worklist.pop()); 1.189 - if (ptn->node_type() == PointsToNode::JavaObject) 1.190 - has_non_escaping_obj = true; // Non GlobalEscape 1.191 - uint e_cnt = ptn->edge_count(); 1.192 - for (uint ei = 0; ei < e_cnt; ei++) { 1.193 - uint npi = ptn->edge_target(ei); 1.194 - PointsToNode *np = ptnode_adr(npi); 1.195 - if (np->escape_state() < PointsToNode::ArgEscape) { 1.196 - set_escape_state(npi, PointsToNode::ArgEscape); 1.197 - worklist.push(npi); 1.198 - } 1.199 - } 1.200 - } 1.201 - 1.202 - GrowableArray<Node*> alloc_worklist; 1.203 + bool has_non_escaping_obj = propagate_escape_state(&cg_worklist, &worklist, PointsToNode::ArgEscape); 1.204 1.205 // push all NoEscape nodes on the worklist 1.206 for( uint next = 0; next < cg_length; ++next ) { 1.207 @@ -1727,6 +1700,7 @@ 1.208 if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape) 1.209 worklist.push(nk); 1.210 } 1.211 + alloc_worklist.clear(); 1.212 // mark all nodes reachable from NoEscape nodes 1.213 while(worklist.length() > 0) { 1.214 uint nk = worklist.pop(); 1.215 @@ -1735,9 +1709,11 @@ 1.216 !(nk == _noop_null || nk == _oop_null)) 1.217 has_non_escaping_obj = true; // Non Escape 1.218 Node* n = ptn->_node; 1.219 - if (n->is_Allocate() && ptn->_scalar_replaceable ) { 1.220 + bool scalar_replaceable = ptn->scalar_replaceable(); 1.221 + if (n->is_Allocate() && scalar_replaceable) { 1.222 // Push scalar replaceable allocations on alloc_worklist 1.223 - // for processing in split_unique_types(). 1.224 + // for processing in split_unique_types(). Note, 1.225 + // following code may change scalar_replaceable value. 1.226 alloc_worklist.append(n); 1.227 } 1.228 uint e_cnt = ptn->edge_count(); 1.229 @@ -1746,6 +1722,13 @@ 1.230 PointsToNode *np = ptnode_adr(npi); 1.231 if (np->escape_state() < PointsToNode::NoEscape) { 1.232 set_escape_state(npi, PointsToNode::NoEscape); 1.233 + if (!scalar_replaceable) { 1.234 + np->set_scalar_replaceable(false); 1.235 + } 1.236 + worklist.push(npi); 1.237 + } else if (np->scalar_replaceable() && !scalar_replaceable) { 1.238 + // Propagate scalar_replaceable value. 1.239 + np->set_scalar_replaceable(false); 1.240 worklist.push(npi); 1.241 } 1.242 } 1.243 @@ -1759,7 +1742,7 @@ 1.244 assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape, "sanity"); 1.245 } 1.246 1.247 - if (EliminateLocks) { 1.248 + if (EliminateLocks && has_non_escaping_obj) { 1.249 // Mark locks before changing ideal graph. 1.250 int cnt = C->macro_count(); 1.251 for( int i=0; i < cnt; i++ ) { 1.252 @@ -1784,7 +1767,18 @@ 1.253 } 1.254 #endif 1.255 1.256 - bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0; 1.257 + bool has_scalar_replaceable_candidates = false; 1.258 + alloc_length = alloc_worklist.length(); 1.259 + for (uint next = 0; next < alloc_length; ++next) { 1.260 + Node* n = alloc_worklist.at(next); 1.261 + PointsToNode* ptn = ptnode_adr(n->_idx); 1.262 + assert(ptn->escape_state() == PointsToNode::NoEscape, "sanity"); 1.263 + if (ptn->scalar_replaceable()) { 1.264 + has_scalar_replaceable_candidates = true; 1.265 + break; 1.266 + } 1.267 + } 1.268 + 1.269 if ( has_scalar_replaceable_candidates && 1.270 C->AliasLevel() >= 3 && EliminateAllocations ) { 1.271 1.272 @@ -1813,53 +1807,32 @@ 1.273 return has_non_escaping_obj; 1.274 } 1.275 1.276 -// Adjust escape state after Connection Graph is built. 1.277 -void ConnectionGraph::adjust_escape_state(int nidx, PhaseTransform* phase) { 1.278 - PointsToNode* ptn = ptnode_adr(nidx); 1.279 - Node* n = ptn->_node; 1.280 - assert(n->is_AddP(), "Should be called for AddP nodes only"); 1.281 - // Search for objects which are not scalar replaceable. 1.282 - // Mark their escape state as ArgEscape to propagate the state 1.283 - // to referenced objects. 1.284 - // Note: currently there are no difference in compiler optimizations 1.285 - // for ArgEscape objects and NoEscape objects which are not 1.286 - // scalar replaceable. 1.287 +// Find fields initializing values for allocations. 1.288 +void ConnectionGraph::find_init_values(Node* alloc, VectorSet* visited, PhaseTransform* phase) { 1.289 + assert(alloc->is_Allocate(), "Should be called for Allocate nodes only"); 1.290 + PointsToNode* pta = ptnode_adr(alloc->_idx); 1.291 + assert(pta->escape_state() == PointsToNode::NoEscape, "Not escaped Allocate nodes only"); 1.292 + InitializeNode* ini = alloc->as_Allocate()->initialization(); 1.293 1.294 Compile* C = _compile; 1.295 - 1.296 - int offset = ptn->offset(); 1.297 - Node* base = get_addp_base(n); 1.298 - VectorSet* ptset = PointsTo(base); 1.299 - int ptset_size = ptset->Size(); 1.300 - 1.301 + visited->Reset(); 1.302 // Check if a oop field's initializing value is recorded and add 1.303 // a corresponding NULL field's value if it is not recorded. 1.304 // Connection Graph does not record a default initialization by NULL 1.305 // captured by Initialize node. 1.306 // 1.307 - // Note: it will disable scalar replacement in some cases: 1.308 - // 1.309 - // Point p[] = new Point[1]; 1.310 - // p[0] = new Point(); // Will be not scalar replaced 1.311 - // 1.312 - // but it will save us from incorrect optimizations in next cases: 1.313 - // 1.314 - // Point p[] = new Point[1]; 1.315 - // if ( x ) p[0] = new Point(); // Will be not scalar replaced 1.316 - // 1.317 - // Do a simple control flow analysis to distinguish above cases. 1.318 - // 1.319 - if (offset != Type::OffsetBot && ptset_size == 1) { 1.320 - uint elem = ptset->getelem(); // Allocation node's index 1.321 - // It does not matter if it is not Allocation node since 1.322 - // only non-escaping allocations are scalar replaced. 1.323 - if (ptnode_adr(elem)->_node->is_Allocate() && 1.324 - ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) { 1.325 - AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate(); 1.326 - InitializeNode* ini = alloc->initialization(); 1.327 + uint ae_cnt = pta->edge_count(); 1.328 + for (uint ei = 0; ei < ae_cnt; ei++) { 1.329 + uint nidx = pta->edge_target(ei); // Field (AddP) 1.330 + PointsToNode* ptn = ptnode_adr(nidx); 1.331 + assert(ptn->_node->is_AddP(), "Should be AddP nodes only"); 1.332 + int offset = ptn->offset(); 1.333 + if (offset != Type::OffsetBot && 1.334 + offset != oopDesc::klass_offset_in_bytes() && 1.335 + !visited->test_set(offset)) { 1.336 1.337 // Check only oop fields. 1.338 - const Type* adr_type = n->as_AddP()->bottom_type(); 1.339 + const Type* adr_type = ptn->_node->as_AddP()->bottom_type(); 1.340 BasicType basic_field_type = T_INT; 1.341 if (adr_type->isa_instptr()) { 1.342 ciField* field = C->alias_type(adr_type->isa_instptr())->field(); 1.343 @@ -1869,12 +1842,20 @@ 1.344 // Ignore non field load (for example, klass load) 1.345 } 1.346 } else if (adr_type->isa_aryptr()) { 1.347 - const Type* elemtype = adr_type->isa_aryptr()->elem(); 1.348 - basic_field_type = elemtype->array_element_basic_type(); 1.349 + if (offset != arrayOopDesc::length_offset_in_bytes()) { 1.350 + const Type* elemtype = adr_type->isa_aryptr()->elem(); 1.351 + basic_field_type = elemtype->array_element_basic_type(); 1.352 + } else { 1.353 + // Ignore array length load 1.354 + } 1.355 +#ifdef ASSERT 1.356 } else { 1.357 - // Raw pointers are used for initializing stores so skip it. 1.358 + // Raw pointers are used for initializing stores so skip it 1.359 + // since it should be recorded already 1.360 + Node* base = get_addp_base(ptn->_node); 1.361 assert(adr_type->isa_rawptr() && base->is_Proj() && 1.362 (base->in(0) == alloc),"unexpected pointer type"); 1.363 +#endif 1.364 } 1.365 if (basic_field_type == T_OBJECT || 1.366 basic_field_type == T_NARROWOOP || 1.367 @@ -1889,18 +1870,33 @@ 1.368 // Check for a store which follows allocation without branches. 1.369 // For example, a volatile field store is not collected 1.370 // by Initialize node. TODO: it would be nice to use idom() here. 1.371 - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { 1.372 - store = n->fast_out(i); 1.373 - if (store->is_Store() && store->in(0) != NULL) { 1.374 - Node* ctrl = store->in(0); 1.375 - while(!(ctrl == ini || ctrl == alloc || ctrl == NULL || 1.376 - ctrl == C->root() || ctrl == C->top() || ctrl->is_Region() || 1.377 - ctrl->is_IfTrue() || ctrl->is_IfFalse())) { 1.378 - ctrl = ctrl->in(0); 1.379 - } 1.380 - if (ctrl == ini || ctrl == alloc) { 1.381 - value = store->in(MemNode::ValueIn); 1.382 - break; 1.383 + // 1.384 + // Search all references to the same field which use different 1.385 + // AddP nodes, for example, in the next case: 1.386 + // 1.387 + // Point p[] = new Point[1]; 1.388 + // if ( x ) { p[0] = new Point(); p[0].x = x; } 1.389 + // if ( p[0] != null ) { y = p[0].x; } // has CastPP 1.390 + // 1.391 + for (uint next = ei; (next < ae_cnt) && (value == NULL); next++) { 1.392 + uint fpi = pta->edge_target(next); // Field (AddP) 1.393 + PointsToNode *ptf = ptnode_adr(fpi); 1.394 + if (ptf->offset() == offset) { 1.395 + Node* nf = ptf->_node; 1.396 + for (DUIterator_Fast imax, i = nf->fast_outs(imax); i < imax; i++) { 1.397 + store = nf->fast_out(i); 1.398 + if (store->is_Store() && store->in(0) != NULL) { 1.399 + Node* ctrl = store->in(0); 1.400 + while(!(ctrl == ini || ctrl == alloc || ctrl == NULL || 1.401 + ctrl == C->root() || ctrl == C->top() || ctrl->is_Region() || 1.402 + ctrl->is_IfTrue() || ctrl->is_IfFalse())) { 1.403 + ctrl = ctrl->in(0); 1.404 + } 1.405 + if (ctrl == ini || ctrl == alloc) { 1.406 + value = store->in(MemNode::ValueIn); 1.407 + break; 1.408 + } 1.409 + } 1.410 } 1.411 } 1.412 } 1.413 @@ -1909,21 +1905,35 @@ 1.414 if (value == NULL || value != ptnode_adr(value->_idx)->_node) { 1.415 // A field's initializing value was not recorded. Add NULL. 1.416 uint null_idx = UseCompressedOops ? _noop_null : _oop_null; 1.417 - add_pointsto_edge(nidx, null_idx); 1.418 + add_edge_from_fields(alloc->_idx, null_idx, offset); 1.419 } 1.420 } 1.421 } 1.422 } 1.423 +} 1.424 + 1.425 +// Adjust escape state after Connection Graph is built. 1.426 +void ConnectionGraph::adjust_escape_state(Node* n) { 1.427 + PointsToNode* ptn = ptnode_adr(n->_idx); 1.428 + assert(n->is_AddP(), "Should be called for AddP nodes only"); 1.429 + // Search for objects which are not scalar replaceable 1.430 + // and mark them to propagate the state to referenced objects. 1.431 + // 1.432 + 1.433 + int offset = ptn->offset(); 1.434 + Node* base = get_addp_base(n); 1.435 + VectorSet* ptset = PointsTo(base); 1.436 + int ptset_size = ptset->Size(); 1.437 1.438 // An object is not scalar replaceable if the field which may point 1.439 // to it has unknown offset (unknown element of an array of objects). 1.440 // 1.441 + 1.442 if (offset == Type::OffsetBot) { 1.443 uint e_cnt = ptn->edge_count(); 1.444 for (uint ei = 0; ei < e_cnt; ei++) { 1.445 uint npi = ptn->edge_target(ei); 1.446 - set_escape_state(npi, PointsToNode::ArgEscape); 1.447 - ptnode_adr(npi)->_scalar_replaceable = false; 1.448 + ptnode_adr(npi)->set_scalar_replaceable(false); 1.449 } 1.450 } 1.451 1.452 @@ -1942,20 +1952,62 @@ 1.453 // to unknown field (unknown element for arrays, offset is OffsetBot). 1.454 // 1.455 // Or the address may point to more then one object. This may produce 1.456 - // the false positive result (set scalar_replaceable to false) 1.457 + // the false positive result (set not scalar replaceable) 1.458 // since the flow-insensitive escape analysis can't separate 1.459 // the case when stores overwrite the field's value from the case 1.460 // when stores happened on different control branches. 1.461 // 1.462 + // Note: it will disable scalar replacement in some cases: 1.463 + // 1.464 + // Point p[] = new Point[1]; 1.465 + // p[0] = new Point(); // Will be not scalar replaced 1.466 + // 1.467 + // but it will save us from incorrect optimizations in next cases: 1.468 + // 1.469 + // Point p[] = new Point[1]; 1.470 + // if ( x ) p[0] = new Point(); // Will be not scalar replaced 1.471 + // 1.472 if (ptset_size > 1 || ptset_size != 0 && 1.473 (has_LoadStore || offset == Type::OffsetBot)) { 1.474 for( VectorSetI j(ptset); j.test(); ++j ) { 1.475 - set_escape_state(j.elem, PointsToNode::ArgEscape); 1.476 - ptnode_adr(j.elem)->_scalar_replaceable = false; 1.477 + ptnode_adr(j.elem)->set_scalar_replaceable(false); 1.478 } 1.479 } 1.480 } 1.481 1.482 +// Propagate escape states to referenced nodes. 1.483 +bool ConnectionGraph::propagate_escape_state(GrowableArray<int>* cg_worklist, 1.484 + GrowableArray<uint>* worklist, 1.485 + PointsToNode::EscapeState esc_state) { 1.486 + bool has_java_obj = false; 1.487 + 1.488 + // push all nodes with the same escape state on the worklist 1.489 + uint cg_length = cg_worklist->length(); 1.490 + for (uint next = 0; next < cg_length; ++next) { 1.491 + int nk = cg_worklist->at(next); 1.492 + if (ptnode_adr(nk)->escape_state() == esc_state) 1.493 + worklist->push(nk); 1.494 + } 1.495 + // mark all reachable nodes 1.496 + while (worklist->length() > 0) { 1.497 + PointsToNode* ptn = ptnode_adr(worklist->pop()); 1.498 + if (ptn->node_type() == PointsToNode::JavaObject) { 1.499 + has_java_obj = true; 1.500 + } 1.501 + uint e_cnt = ptn->edge_count(); 1.502 + for (uint ei = 0; ei < e_cnt; ei++) { 1.503 + uint npi = ptn->edge_target(ei); 1.504 + PointsToNode *np = ptnode_adr(npi); 1.505 + if (np->escape_state() < esc_state) { 1.506 + set_escape_state(npi, esc_state); 1.507 + worklist->push(npi); 1.508 + } 1.509 + } 1.510 + } 1.511 + // Has not escaping java objects 1.512 + return has_java_obj && (esc_state < PointsToNode::GlobalEscape); 1.513 +} 1.514 + 1.515 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { 1.516 1.517 switch (call->Opcode()) { 1.518 @@ -2112,6 +2164,7 @@ 1.519 } else { 1.520 es = PointsToNode::NoEscape; 1.521 edge_to = call_idx; 1.522 + assert(ptnode_adr(call_idx)->scalar_replaceable(), "sanity"); 1.523 } 1.524 set_escape_state(call_idx, es); 1.525 add_pointsto_edge(resproj_idx, edge_to); 1.526 @@ -2135,10 +2188,11 @@ 1.527 } else { 1.528 es = PointsToNode::NoEscape; 1.529 edge_to = call_idx; 1.530 + assert(ptnode_adr(call_idx)->scalar_replaceable(), "sanity"); 1.531 int length = call->in(AllocateNode::ALength)->find_int_con(-1); 1.532 if (length < 0 || length > EliminateAllocationArraySizeLimit) { 1.533 // Not scalar replaceable if the length is not constant or too big. 1.534 - ptnode_adr(call_idx)->_scalar_replaceable = false; 1.535 + ptnode_adr(call_idx)->set_scalar_replaceable(false); 1.536 } 1.537 } 1.538 set_escape_state(call_idx, es); 1.539 @@ -2180,11 +2234,12 @@ 1.540 // Mark it as NoEscape so that objects referenced by 1.541 // it's fields will be marked as NoEscape at least. 1.542 set_escape_state(call_idx, PointsToNode::NoEscape); 1.543 + ptnode_adr(call_idx)->set_scalar_replaceable(false); 1.544 add_pointsto_edge(resproj_idx, call_idx); 1.545 copy_dependencies = true; 1.546 } else if (call_analyzer->is_return_local()) { 1.547 // determine whether any arguments are returned 1.548 - set_escape_state(call_idx, PointsToNode::NoEscape); 1.549 + set_escape_state(call_idx, PointsToNode::ArgEscape); 1.550 bool ret_arg = false; 1.551 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { 1.552 const Type* at = d->field_at(i); 1.553 @@ -2201,7 +2256,6 @@ 1.554 add_pointsto_edge(resproj_idx, arg->_idx); 1.555 else 1.556 add_deferred_edge(resproj_idx, arg->_idx); 1.557 - arg_esp->_hidden_alias = true; 1.558 } 1.559 } 1.560 } 1.561 @@ -2210,18 +2264,12 @@ 1.562 set_escape_state(call_idx, PointsToNode::GlobalEscape); 1.563 add_pointsto_edge(resproj_idx, _phantom_object); 1.564 } 1.565 - copy_dependencies = true; 1.566 + if (done) { 1.567 + copy_dependencies = true; 1.568 + } 1.569 } else { 1.570 set_escape_state(call_idx, PointsToNode::GlobalEscape); 1.571 add_pointsto_edge(resproj_idx, _phantom_object); 1.572 - for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { 1.573 - const Type* at = d->field_at(i); 1.574 - if (at->isa_oopptr() != NULL) { 1.575 - Node *arg = call->in(i)->uncast(); 1.576 - PointsToNode *arg_esp = ptnode_adr(arg->_idx); 1.577 - arg_esp->_hidden_alias = true; 1.578 - } 1.579 - } 1.580 } 1.581 if (copy_dependencies) 1.582 call_analyzer->copy_dependencies(_compile->dependencies());
2.1 --- a/src/share/vm/opto/escape.hpp Fri Nov 04 13:55:31 2011 -0700 2.2 +++ b/src/share/vm/opto/escape.hpp Mon Nov 07 14:33:57 2011 -0800 2.3 @@ -74,7 +74,7 @@ 2.4 // C2 does not have local variables. However for the purposes of constructing 2.5 // the connection graph, the following IR nodes are treated as local variables: 2.6 // Phi (pointer values) 2.7 -// LoadP 2.8 +// LoadP, LoadN 2.9 // Proj#5 (value returned from callnodes including allocations) 2.10 // CheckCastPP, CastPP 2.11 // 2.12 @@ -84,7 +84,7 @@ 2.13 // 2.14 // The following node types are JavaObject: 2.15 // 2.16 -// top() 2.17 +// phantom_object (general globally escaped object) 2.18 // Allocate 2.19 // AllocateArray 2.20 // Parm (for incoming arguments) 2.21 @@ -93,6 +93,7 @@ 2.22 // ConP 2.23 // LoadKlass 2.24 // ThreadLocal 2.25 +// CallStaticJava (which returns Object) 2.26 // 2.27 // AddP nodes are fields. 2.28 // 2.29 @@ -130,10 +131,12 @@ 2.30 2.31 typedef enum { 2.32 UnknownEscape = 0, 2.33 - NoEscape = 1, // A scalar replaceable object with unique type. 2.34 - ArgEscape = 2, // An object passed as argument or referenced by 2.35 - // argument (and not globally escape during call). 2.36 - GlobalEscape = 3 // An object escapes the method and thread. 2.37 + NoEscape = 1, // An object does not escape method or thread and it is 2.38 + // not passed to call. It could be replaced with scalar. 2.39 + ArgEscape = 2, // An object does not escape method or thread but it is 2.40 + // passed as argument to call or referenced by argument 2.41 + // and it does not escape during call. 2.42 + GlobalEscape = 3 // An object escapes the method or thread. 2.43 } EscapeState; 2.44 2.45 typedef enum { 2.46 @@ -153,28 +156,25 @@ 2.47 2.48 NodeType _type; 2.49 EscapeState _escape; 2.50 - GrowableArray<uint>* _edges; // outgoing edges 2.51 + GrowableArray<uint>* _edges; // outgoing edges 2.52 + Node* _node; // Ideal node corresponding to this PointsTo node. 2.53 + int _offset; // Object fields offsets. 2.54 + bool _scalar_replaceable; // Not escaped object could be replaced with scalar 2.55 2.56 public: 2.57 - Node* _node; // Ideal node corresponding to this PointsTo node. 2.58 - int _offset; // Object fields offsets. 2.59 - bool _scalar_replaceable;// Not escaped object could be replaced with scalar 2.60 - bool _hidden_alias; // This node is an argument to a function. 2.61 - // which may return it creating a hidden alias. 2.62 - 2.63 PointsToNode(): 2.64 _type(UnknownType), 2.65 _escape(UnknownEscape), 2.66 _edges(NULL), 2.67 _node(NULL), 2.68 _offset(-1), 2.69 - _scalar_replaceable(true), 2.70 - _hidden_alias(false) {} 2.71 + _scalar_replaceable(true) {} 2.72 2.73 2.74 EscapeState escape_state() const { return _escape; } 2.75 NodeType node_type() const { return _type;} 2.76 int offset() { return _offset;} 2.77 + bool scalar_replaceable() { return _scalar_replaceable;} 2.78 2.79 void set_offset(int offs) { _offset = offs;} 2.80 void set_escape_state(EscapeState state) { _escape = state; } 2.81 @@ -182,6 +182,7 @@ 2.82 assert(_type == UnknownType || _type == ntype, "Can't change node type"); 2.83 _type = ntype; 2.84 } 2.85 + void set_scalar_replaceable(bool v) { _scalar_replaceable = v; } 2.86 2.87 // count of outgoing edges 2.88 uint edge_count() const { return (_edges == NULL) ? 0 : _edges->length(); } 2.89 @@ -233,8 +234,8 @@ 2.90 // that pointer values loaded from 2.91 // a field which has not been set 2.92 // are assumed to point to. 2.93 - uint _oop_null; // ConP(#NULL) 2.94 - uint _noop_null; // ConN(#NULL) 2.95 + uint _oop_null; // ConP(#NULL)->_idx 2.96 + uint _noop_null; // ConN(#NULL)->_idx 2.97 2.98 Compile * _compile; // Compile object for current compilation 2.99 PhaseIterGVN * _igvn; // Value numbering 2.100 @@ -339,8 +340,16 @@ 2.101 // Set the escape state of a node 2.102 void set_escape_state(uint ni, PointsToNode::EscapeState es); 2.103 2.104 + // Find fields initializing values for allocations. 2.105 + void find_init_values(Node* n, VectorSet* visited, PhaseTransform* phase); 2.106 + 2.107 // Adjust escape state after Connection Graph is built. 2.108 - void adjust_escape_state(int nidx, PhaseTransform* phase); 2.109 + void adjust_escape_state(Node* n); 2.110 + 2.111 + // Propagate escape states to referenced nodes. 2.112 + bool propagate_escape_state(GrowableArray<int>* cg_worklist, 2.113 + GrowableArray<uint>* worklist, 2.114 + PointsToNode::EscapeState esc_state); 2.115 2.116 // Compute the escape information 2.117 bool compute_escape(); 2.118 @@ -357,21 +366,6 @@ 2.119 // escape state of a node 2.120 PointsToNode::EscapeState escape_state(Node *n); 2.121 2.122 - // other information we have collected 2.123 - bool is_scalar_replaceable(Node *n) { 2.124 - if (_collecting || (n->_idx >= nodes_size())) 2.125 - return false; 2.126 - PointsToNode* ptn = ptnode_adr(n->_idx); 2.127 - return ptn->escape_state() == PointsToNode::NoEscape && ptn->_scalar_replaceable; 2.128 - } 2.129 - 2.130 - bool hidden_alias(Node *n) { 2.131 - if (_collecting || (n->_idx >= nodes_size())) 2.132 - return true; 2.133 - PointsToNode* ptn = ptnode_adr(n->_idx); 2.134 - return (ptn->escape_state() != PointsToNode::NoEscape) || ptn->_hidden_alias; 2.135 - } 2.136 - 2.137 #ifndef PRODUCT 2.138 void dump(); 2.139 #endif