src/share/vm/opto/escape.cpp

changeset 3318
cc81b9c09bbb
parent 3311
1bd45abaa507
child 3392
1dc233a8c7fe
     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());

mercurial