7059047: EA: can't find initializing store with several CheckCastPP

Mon, 07 Nov 2011 14:33:57 -0800

author
kvn
date
Mon, 07 Nov 2011 14:33:57 -0800
changeset 3254
59e515ee9354
parent 3253
1feb272af3a7
child 3255
44ce519bc3d1

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

mercurial