1.1 --- a/src/share/vm/opto/escape.cpp Tue Nov 22 09:45:57 2011 +0100 1.2 +++ b/src/share/vm/opto/escape.cpp Mon Nov 28 15:46:31 2011 -0800 1.3 @@ -130,6 +130,13 @@ 1.4 assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); 1.5 assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of PointsTo edge"); 1.6 assert(t->node_type() == PointsToNode::JavaObject, "invalid destination of PointsTo edge"); 1.7 + if (to_i == _phantom_object) { // Quick test for most common object 1.8 + if (f->has_unknown_ptr()) { 1.9 + return; 1.10 + } else { 1.11 + f->set_has_unknown_ptr(); 1.12 + } 1.13 + } 1.14 add_edge(f, to_i, PointsToNode::PointsToEdge); 1.15 } 1.16 1.17 @@ -165,6 +172,9 @@ 1.18 } 1.19 1.20 void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) { 1.21 + // Don't add fields to NULL pointer. 1.22 + if (is_null_ptr(from_i)) 1.23 + return; 1.24 PointsToNode *f = ptnode_adr(from_i); 1.25 PointsToNode *t = ptnode_adr(to_i); 1.26 1.27 @@ -179,7 +189,7 @@ 1.28 1.29 void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) { 1.30 // Don't change non-escaping state of NULL pointer. 1.31 - if (ni == _noop_null || ni == _oop_null) 1.32 + if (is_null_ptr(ni)) 1.33 return; 1.34 PointsToNode *npt = ptnode_adr(ni); 1.35 PointsToNode::EscapeState old_es = npt->escape_state(); 1.36 @@ -311,11 +321,9 @@ 1.37 1.38 visited->set(ni); 1.39 PointsToNode *ptn = ptnode_adr(ni); 1.40 - if (ptn->edge_count() == 0) { 1.41 - // No deferred or pointsto edges found. Assume the value was set 1.42 - // outside this method. Add edge to phantom object. 1.43 - add_pointsto_edge(ni, _phantom_object); 1.44 - } 1.45 + assert(ptn->node_type() == PointsToNode::LocalVar || 1.46 + ptn->node_type() == PointsToNode::Field, "sanity"); 1.47 + assert(ptn->edge_count() != 0, "should have at least phantom_object"); 1.48 1.49 // Mark current edges as visited and move deferred edges to separate array. 1.50 for (uint i = 0; i < ptn->edge_count(); ) { 1.51 @@ -336,12 +344,7 @@ 1.52 uint t = deferred_edges->at(next); 1.53 PointsToNode *ptt = ptnode_adr(t); 1.54 uint e_cnt = ptt->edge_count(); 1.55 - if (e_cnt == 0) { 1.56 - // No deferred or pointsto edges found. Assume the value was set 1.57 - // outside this method. Add edge to phantom object. 1.58 - add_pointsto_edge(t, _phantom_object); 1.59 - add_pointsto_edge(ni, _phantom_object); 1.60 - } 1.61 + assert(e_cnt != 0, "should have at least phantom_object"); 1.62 for (uint e = 0; e < e_cnt; e++) { 1.63 uint etgt = ptt->edge_target(e); 1.64 if (visited->test_set(etgt)) 1.65 @@ -350,10 +353,6 @@ 1.66 PointsToNode::EdgeType et = ptt->edge_type(e); 1.67 if (et == PointsToNode::PointsToEdge) { 1.68 add_pointsto_edge(ni, etgt); 1.69 - if(etgt == _phantom_object) { 1.70 - // Special case - field set outside (globally escaping). 1.71 - set_escape_state(ni, PointsToNode::GlobalEscape); 1.72 - } 1.73 } else if (et == PointsToNode::DeferredEdge) { 1.74 deferred_edges->append(etgt); 1.75 } else { 1.76 @@ -361,6 +360,20 @@ 1.77 } 1.78 } 1.79 } 1.80 + if (ptn->edge_count() == 0) { 1.81 + // No pointsto edges found after deferred edges are removed. 1.82 + // For example, in the next case where call is replaced 1.83 + // with uncommon trap and as result array's load references 1.84 + // itself through deferred edges: 1.85 + // 1.86 + // A a = b[i]; 1.87 + // if (c!=null) a = c.foo(); 1.88 + // b[i] = a; 1.89 + // 1.90 + // Assume the value was set outside this method and 1.91 + // add edge to phantom object. 1.92 + add_pointsto_edge(ni, _phantom_object); 1.93 + } 1.94 } 1.95 1.96 1.97 @@ -369,13 +382,25 @@ 1.98 // a pointsto edge is added if it is a JavaObject 1.99 1.100 void ConnectionGraph::add_edge_from_fields(uint adr_i, uint to_i, int offs) { 1.101 + // No fields for NULL pointer. 1.102 + if (is_null_ptr(adr_i)) { 1.103 + return; 1.104 + } 1.105 PointsToNode* an = ptnode_adr(adr_i); 1.106 PointsToNode* to = ptnode_adr(to_i); 1.107 bool deferred = (to->node_type() == PointsToNode::LocalVar); 1.108 - 1.109 + bool escaped = (to_i == _phantom_object) && (offs == Type::OffsetTop); 1.110 + if (escaped) { 1.111 + // Values in fields escaped during call. 1.112 + assert(an->escape_state() >= PointsToNode::ArgEscape, "sanity"); 1.113 + offs = Type::OffsetBot; 1.114 + } 1.115 for (uint fe = 0; fe < an->edge_count(); fe++) { 1.116 assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); 1.117 int fi = an->edge_target(fe); 1.118 + if (escaped) { 1.119 + set_escape_state(fi, PointsToNode::GlobalEscape); 1.120 + } 1.121 PointsToNode* pf = ptnode_adr(fi); 1.122 int po = pf->offset(); 1.123 if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { 1.124 @@ -390,6 +415,15 @@ 1.125 // Add a deferred edge from node given by "from_i" to any field of adr_i 1.126 // whose offset matches "offset". 1.127 void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) { 1.128 + // No fields for NULL pointer. 1.129 + if (is_null_ptr(adr_i)) { 1.130 + return; 1.131 + } 1.132 + if (adr_i == _phantom_object) { 1.133 + // Add only one edge for unknown object. 1.134 + add_pointsto_edge(from_i, _phantom_object); 1.135 + return; 1.136 + } 1.137 PointsToNode* an = ptnode_adr(adr_i); 1.138 bool is_alloc = an->_node->is_Allocate(); 1.139 for (uint fe = 0; fe < an->edge_count(); fe++) { 1.140 @@ -1562,7 +1596,6 @@ 1.141 GrowableArray<Node*> addp_worklist; 1.142 GrowableArray<Node*> ptr_cmp_worklist; 1.143 PhaseGVN* igvn = _igvn; 1.144 - bool has_allocations = false; 1.145 1.146 // Push all useful nodes onto CG list and set their type. 1.147 for( uint next = 0; next < worklist_init.size(); ++next ) { 1.148 @@ -1572,9 +1605,7 @@ 1.149 // for an escape status. See process_call_result() below. 1.150 if (n->is_Allocate() || n->is_CallStaticJava() && 1.151 ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) { 1.152 - has_allocations = true; 1.153 - if (n->is_Allocate()) 1.154 - alloc_worklist.append(n); 1.155 + alloc_worklist.append(n); 1.156 } else if(n->is_AddP()) { 1.157 // Collect address nodes. Use them during stage 3 below 1.158 // to build initial connection graph field edges. 1.159 @@ -1594,7 +1625,7 @@ 1.160 } 1.161 } 1.162 1.163 - if (!has_allocations) { 1.164 + if (alloc_worklist.length() == 0) { 1.165 _collecting = false; 1.166 return false; // Nothing to do. 1.167 } 1.168 @@ -1677,22 +1708,52 @@ 1.169 } 1.170 #undef CG_BUILD_ITER_LIMIT 1.171 1.172 + // 5. Propagate escaped states. 1.173 + worklist.clear(); 1.174 + 1.175 + // mark all nodes reachable from GlobalEscape nodes 1.176 + (void)propagate_escape_state(&cg_worklist, &worklist, PointsToNode::GlobalEscape); 1.177 + 1.178 + // mark all nodes reachable from ArgEscape nodes 1.179 + bool has_non_escaping_obj = propagate_escape_state(&cg_worklist, &worklist, PointsToNode::ArgEscape); 1.180 + 1.181 Arena* arena = Thread::current()->resource_area(); 1.182 VectorSet visited(arena); 1.183 1.184 - // 5. Find fields initializing values for not escaped allocations 1.185 + // 6. Find fields initializing values for not escaped allocations 1.186 uint alloc_length = alloc_worklist.length(); 1.187 for (uint next = 0; next < alloc_length; ++next) { 1.188 Node* n = alloc_worklist.at(next); 1.189 if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) { 1.190 - find_init_values(n, &visited, igvn); 1.191 + has_non_escaping_obj = true; 1.192 + if (n->is_Allocate()) { 1.193 + find_init_values(n, &visited, igvn); 1.194 + } 1.195 } 1.196 } 1.197 1.198 - worklist.clear(); 1.199 + uint cg_length = cg_worklist.length(); 1.200 1.201 - // 6. Remove deferred edges from the graph. 1.202 - uint cg_length = cg_worklist.length(); 1.203 + // Skip the rest of code if all objects escaped. 1.204 + if (!has_non_escaping_obj) { 1.205 + cg_length = 0; 1.206 + addp_length = 0; 1.207 + } 1.208 + 1.209 + for (uint next = 0; next < cg_length; ++next) { 1.210 + int ni = cg_worklist.at(next); 1.211 + PointsToNode* ptn = ptnode_adr(ni); 1.212 + PointsToNode::NodeType nt = ptn->node_type(); 1.213 + if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { 1.214 + if (ptn->edge_count() == 0) { 1.215 + // No values were found. Assume the value was set 1.216 + // outside this method - add edge to phantom object. 1.217 + add_pointsto_edge(ni, _phantom_object); 1.218 + } 1.219 + } 1.220 + } 1.221 + 1.222 + // 7. Remove deferred edges from the graph. 1.223 for (uint next = 0; next < cg_length; ++next) { 1.224 int ni = cg_worklist.at(next); 1.225 PointsToNode* ptn = ptnode_adr(ni); 1.226 @@ -1702,35 +1763,26 @@ 1.227 } 1.228 } 1.229 1.230 - // 7. Adjust escape state of nonescaping objects. 1.231 + // 8. Adjust escape state of nonescaping objects. 1.232 for (uint next = 0; next < addp_length; ++next) { 1.233 Node* n = addp_worklist.at(next); 1.234 adjust_escape_state(n); 1.235 } 1.236 1.237 - // 8. Propagate escape states. 1.238 + // push all NoEscape nodes on the worklist 1.239 worklist.clear(); 1.240 - 1.241 - // mark all nodes reachable from GlobalEscape nodes 1.242 - (void)propagate_escape_state(&cg_worklist, &worklist, PointsToNode::GlobalEscape); 1.243 - 1.244 - // mark all nodes reachable from ArgEscape nodes 1.245 - bool has_non_escaping_obj = propagate_escape_state(&cg_worklist, &worklist, PointsToNode::ArgEscape); 1.246 - 1.247 - // push all NoEscape nodes on the worklist 1.248 for( uint next = 0; next < cg_length; ++next ) { 1.249 int nk = cg_worklist.at(next); 1.250 - if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape) 1.251 + if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape && 1.252 + !is_null_ptr(nk)) 1.253 worklist.push(nk); 1.254 } 1.255 + 1.256 alloc_worklist.clear(); 1.257 - // mark all nodes reachable from NoEscape nodes 1.258 + // Propagate scalar_replaceable value. 1.259 while(worklist.length() > 0) { 1.260 uint nk = worklist.pop(); 1.261 PointsToNode* ptn = ptnode_adr(nk); 1.262 - if (ptn->node_type() == PointsToNode::JavaObject && 1.263 - !(nk == _noop_null || nk == _oop_null)) 1.264 - has_non_escaping_obj = true; // Non Escape 1.265 Node* n = ptn->_node; 1.266 bool scalar_replaceable = ptn->scalar_replaceable(); 1.267 if (n->is_Allocate() && scalar_replaceable) { 1.268 @@ -1742,6 +1794,8 @@ 1.269 uint e_cnt = ptn->edge_count(); 1.270 for (uint ei = 0; ei < e_cnt; ei++) { 1.271 uint npi = ptn->edge_target(ei); 1.272 + if (is_null_ptr(npi)) 1.273 + continue; 1.274 PointsToNode *np = ptnode_adr(npi); 1.275 if (np->escape_state() < PointsToNode::NoEscape) { 1.276 set_escape_state(npi, PointsToNode::NoEscape); 1.277 @@ -1750,7 +1804,6 @@ 1.278 } 1.279 worklist.push(npi); 1.280 } else if (np->scalar_replaceable() && !scalar_replaceable) { 1.281 - // Propagate scalar_replaceable value. 1.282 np->set_scalar_replaceable(false); 1.283 worklist.push(npi); 1.284 } 1.285 @@ -1760,9 +1813,11 @@ 1.286 _collecting = false; 1.287 assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build"); 1.288 1.289 - assert(ptnode_adr(_oop_null)->escape_state() == PointsToNode::NoEscape, "sanity"); 1.290 + assert(ptnode_adr(_oop_null)->escape_state() == PointsToNode::NoEscape && 1.291 + ptnode_adr(_oop_null)->edge_count() == 0, "sanity"); 1.292 if (UseCompressedOops) { 1.293 - assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape, "sanity"); 1.294 + assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape && 1.295 + ptnode_adr(_noop_null)->edge_count() == 0, "sanity"); 1.296 } 1.297 1.298 if (EliminateLocks && has_non_escaping_obj) { 1.299 @@ -1879,15 +1934,30 @@ 1.300 // Connection Graph does not record a default initialization by NULL 1.301 // captured by Initialize node. 1.302 // 1.303 + uint null_idx = UseCompressedOops ? _noop_null : _oop_null; 1.304 uint ae_cnt = pta->edge_count(); 1.305 + bool visited_bottom_offset = false; 1.306 for (uint ei = 0; ei < ae_cnt; ei++) { 1.307 uint nidx = pta->edge_target(ei); // Field (AddP) 1.308 PointsToNode* ptn = ptnode_adr(nidx); 1.309 assert(ptn->_node->is_AddP(), "Should be AddP nodes only"); 1.310 int offset = ptn->offset(); 1.311 - if (offset != Type::OffsetBot && 1.312 - offset != oopDesc::klass_offset_in_bytes() && 1.313 - !visited->test_set(offset)) { 1.314 + if (offset == Type::OffsetBot) { 1.315 + if (!visited_bottom_offset) { 1.316 + visited_bottom_offset = true; 1.317 + // Check only oop fields. 1.318 + const Type* adr_type = ptn->_node->as_AddP()->bottom_type(); 1.319 + if (!adr_type->isa_aryptr() || 1.320 + (adr_type->isa_aryptr()->klass() == NULL) || 1.321 + adr_type->isa_aryptr()->klass()->is_obj_array_klass()) { 1.322 + // OffsetBot is used to reference array's element, 1.323 + // always add reference to NULL since we don't 1.324 + // known which element is referenced. 1.325 + add_edge_from_fields(alloc->_idx, null_idx, offset); 1.326 + } 1.327 + } 1.328 + } else if (offset != oopDesc::klass_offset_in_bytes() && 1.329 + !visited->test_set(offset)) { 1.330 1.331 // Check only oop fields. 1.332 const Type* adr_type = ptn->_node->as_AddP()->bottom_type(); 1.333 @@ -1962,7 +2032,6 @@ 1.334 } 1.335 if (value == NULL || value != ptnode_adr(value->_idx)->_node) { 1.336 // A field's initializing value was not recorded. Add NULL. 1.337 - uint null_idx = UseCompressedOops ? _noop_null : _oop_null; 1.338 add_edge_from_fields(alloc->_idx, null_idx, offset); 1.339 } 1.340 } 1.341 @@ -2048,13 +2117,21 @@ 1.342 } 1.343 // mark all reachable nodes 1.344 while (worklist->length() > 0) { 1.345 - PointsToNode* ptn = ptnode_adr(worklist->pop()); 1.346 - if (ptn->node_type() == PointsToNode::JavaObject) { 1.347 + int pt = worklist->pop(); 1.348 + PointsToNode* ptn = ptnode_adr(pt); 1.349 + if (ptn->node_type() == PointsToNode::JavaObject && 1.350 + !is_null_ptr(pt)) { 1.351 has_java_obj = true; 1.352 + if (esc_state > PointsToNode::NoEscape) { 1.353 + // fields values are unknown if object escapes 1.354 + add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); 1.355 + } 1.356 } 1.357 uint e_cnt = ptn->edge_count(); 1.358 for (uint ei = 0; ei < e_cnt; ei++) { 1.359 uint npi = ptn->edge_target(ei); 1.360 + if (is_null_ptr(npi)) 1.361 + continue; 1.362 PointsToNode *np = ptnode_adr(npi); 1.363 if (np->escape_state() < esc_state) { 1.364 set_escape_state(npi, esc_state); 1.365 @@ -2159,7 +2236,7 @@ 1.366 } 1.367 1.368 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { 1.369 - 1.370 + bool is_arraycopy = false; 1.371 switch (call->Opcode()) { 1.372 #ifdef ASSERT 1.373 case Op_Allocate: 1.374 @@ -2169,25 +2246,44 @@ 1.375 assert(false, "should be done already"); 1.376 break; 1.377 #endif 1.378 + case Op_CallLeafNoFP: 1.379 + is_arraycopy = (call->as_CallLeaf()->_name != NULL && 1.380 + strstr(call->as_CallLeaf()->_name, "arraycopy") != 0); 1.381 + // fall through 1.382 case Op_CallLeaf: 1.383 - case Op_CallLeafNoFP: 1.384 { 1.385 // Stub calls, objects do not escape but they are not scale replaceable. 1.386 // Adjust escape state for outgoing arguments. 1.387 const TypeTuple * d = call->tf()->domain(); 1.388 + bool src_has_oops = false; 1.389 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { 1.390 const Type* at = d->field_at(i); 1.391 Node *arg = call->in(i)->uncast(); 1.392 const Type *aat = phase->type(arg); 1.393 + PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state(); 1.394 if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() && 1.395 - ptnode_adr(arg->_idx)->escape_state() < PointsToNode::ArgEscape) { 1.396 + (is_arraycopy || arg_esc < PointsToNode::ArgEscape)) { 1.397 1.398 assert(aat == Type::TOP || aat == TypePtr::NULL_PTR || 1.399 aat->isa_ptr() != NULL, "expecting an Ptr"); 1.400 + bool arg_has_oops = aat->isa_oopptr() && 1.401 + (aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() || 1.402 + (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass())); 1.403 + if (i == TypeFunc::Parms) { 1.404 + src_has_oops = arg_has_oops; 1.405 + } 1.406 + // 1.407 + // src or dst could be j.l.Object when other is basic type array: 1.408 + // 1.409 + // arraycopy(char[],0,Object*,0,size); 1.410 + // arraycopy(Object*,0,char[],0,size); 1.411 + // 1.412 + // Don't add edges from dst's fields in such cases. 1.413 + // 1.414 + bool arg_is_arraycopy_dest = src_has_oops && is_arraycopy && 1.415 + arg_has_oops && (i > TypeFunc::Parms); 1.416 #ifdef ASSERT 1.417 - if (!(call->Opcode() == Op_CallLeafNoFP && 1.418 - call->as_CallLeaf()->_name != NULL && 1.419 - (strstr(call->as_CallLeaf()->_name, "arraycopy") != 0) || 1.420 + if (!(is_arraycopy || 1.421 call->as_CallLeaf()->_name != NULL && 1.422 (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || 1.423 strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) 1.424 @@ -2196,20 +2292,72 @@ 1.425 assert(false, "EA: unexpected CallLeaf"); 1.426 } 1.427 #endif 1.428 + // Always process arraycopy's destination object since 1.429 + // we need to add all possible edges to references in 1.430 + // source object. 1.431 + if (arg_esc >= PointsToNode::ArgEscape && 1.432 + !arg_is_arraycopy_dest) { 1.433 + continue; 1.434 + } 1.435 set_escape_state(arg->_idx, PointsToNode::ArgEscape); 1.436 + Node* arg_base = arg; 1.437 if (arg->is_AddP()) { 1.438 // 1.439 // The inline_native_clone() case when the arraycopy stub is called 1.440 // after the allocation before Initialize and CheckCastPP nodes. 1.441 + // Or normal arraycopy for object arrays case. 1.442 // 1.443 // Set AddP's base (Allocate) as not scalar replaceable since 1.444 // pointer to the base (with offset) is passed as argument. 1.445 // 1.446 - arg = get_addp_base(arg); 1.447 + arg_base = get_addp_base(arg); 1.448 } 1.449 - for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { 1.450 - uint pt = j.elem; 1.451 - set_escape_state(pt, PointsToNode::ArgEscape); 1.452 + VectorSet argset = *PointsTo(arg_base); // Clone set 1.453 + for( VectorSetI j(&argset); j.test(); ++j ) { 1.454 + uint pd = j.elem; // Destination object 1.455 + set_escape_state(pd, PointsToNode::ArgEscape); 1.456 + 1.457 + if (arg_is_arraycopy_dest) { 1.458 + PointsToNode* ptd = ptnode_adr(pd); 1.459 + // Conservatively reference an unknown object since 1.460 + // not all source's fields/elements may be known. 1.461 + add_edge_from_fields(pd, _phantom_object, Type::OffsetBot); 1.462 + 1.463 + Node *src = call->in(TypeFunc::Parms)->uncast(); 1.464 + Node* src_base = src; 1.465 + if (src->is_AddP()) { 1.466 + src_base = get_addp_base(src); 1.467 + } 1.468 + // Create edges from destination's fields to 1.469 + // everything known source's fields could point to. 1.470 + for( VectorSetI s(PointsTo(src_base)); s.test(); ++s ) { 1.471 + uint ps = s.elem; 1.472 + bool has_bottom_offset = false; 1.473 + for (uint fd = 0; fd < ptd->edge_count(); fd++) { 1.474 + assert(ptd->edge_type(fd) == PointsToNode::FieldEdge, "expecting a field edge"); 1.475 + int fdi = ptd->edge_target(fd); 1.476 + PointsToNode* pfd = ptnode_adr(fdi); 1.477 + int offset = pfd->offset(); 1.478 + if (offset == Type::OffsetBot) 1.479 + has_bottom_offset = true; 1.480 + assert(offset != -1, "offset should be set"); 1.481 + add_deferred_edge_to_fields(fdi, ps, offset); 1.482 + } 1.483 + // Destination object may not have access (no field edge) 1.484 + // to fields which are accessed in source object. 1.485 + // As result no edges will be created to those source's 1.486 + // fields and escape state of destination object will 1.487 + // not be propagated to those fields. 1.488 + // 1.489 + // Mark source object as global escape except in 1.490 + // the case with Type::OffsetBot field (which is 1.491 + // common case for array elements access) when 1.492 + // edges are created to all source's fields. 1.493 + if (!has_bottom_offset) { 1.494 + set_escape_state(ps, PointsToNode::GlobalEscape); 1.495 + } 1.496 + } 1.497 + } 1.498 } 1.499 } 1.500 } 1.501 @@ -2252,14 +2400,16 @@ 1.502 for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { 1.503 uint pt = j.elem; 1.504 if (global_escapes) { 1.505 - //The argument global escapes, mark everything it could point to 1.506 + // The argument global escapes, mark everything it could point to 1.507 set_escape_state(pt, PointsToNode::GlobalEscape); 1.508 + add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); 1.509 } else { 1.510 + set_escape_state(pt, PointsToNode::ArgEscape); 1.511 if (fields_escapes) { 1.512 - // The argument itself doesn't escape, but any fields might 1.513 - add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); 1.514 + // The argument itself doesn't escape, but any fields might. 1.515 + // Use OffsetTop to indicate such case. 1.516 + add_edge_from_fields(pt, _phantom_object, Type::OffsetTop); 1.517 } 1.518 - set_escape_state(pt, PointsToNode::ArgEscape); 1.519 } 1.520 } 1.521 } 1.522 @@ -2285,6 +2435,7 @@ 1.523 for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { 1.524 uint pt = j.elem; 1.525 set_escape_state(pt, PointsToNode::GlobalEscape); 1.526 + add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); 1.527 } 1.528 } 1.529 } 1.530 @@ -2385,15 +2536,16 @@ 1.531 // it's fields will be marked as NoEscape at least. 1.532 set_escape_state(call_idx, PointsToNode::NoEscape); 1.533 ptnode_adr(call_idx)->set_scalar_replaceable(false); 1.534 + // Fields values are unknown 1.535 + add_edge_from_fields(call_idx, _phantom_object, Type::OffsetBot); 1.536 add_pointsto_edge(resproj_idx, call_idx); 1.537 copy_dependencies = true; 1.538 - } else if (call_analyzer->is_return_local()) { 1.539 + } else { 1.540 // determine whether any arguments are returned 1.541 set_escape_state(call_idx, PointsToNode::ArgEscape); 1.542 bool ret_arg = false; 1.543 for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { 1.544 const Type* at = d->field_at(i); 1.545 - 1.546 if (at->isa_oopptr() != NULL) { 1.547 Node *arg = call->in(i)->uncast(); 1.548 1.549 @@ -2409,17 +2561,14 @@ 1.550 } 1.551 } 1.552 } 1.553 - if (done && !ret_arg) { 1.554 - // Returns unknown object. 1.555 - set_escape_state(call_idx, PointsToNode::GlobalEscape); 1.556 - add_pointsto_edge(resproj_idx, _phantom_object); 1.557 - } 1.558 if (done) { 1.559 copy_dependencies = true; 1.560 + // is_return_local() is true when only arguments are returned. 1.561 + if (!ret_arg || !call_analyzer->is_return_local()) { 1.562 + // Returns unknown object. 1.563 + add_pointsto_edge(resproj_idx, _phantom_object); 1.564 + } 1.565 } 1.566 - } else { 1.567 - set_escape_state(call_idx, PointsToNode::GlobalEscape); 1.568 - add_pointsto_edge(resproj_idx, _phantom_object); 1.569 } 1.570 if (copy_dependencies) 1.571 call_analyzer->copy_dependencies(_compile->dependencies());