diff src/share/vm/opto/escape.cpp @ 253:b0fe4deeb9fb

6726999: nsk/stress/jck12a/jck12a010 assert(n != null,"Bad immediate dominator info.") Summary: Escape Analysis fixes. Reviewed-by: never, rasbold
author kvn
date Mon, 28 Jul 2008 17:12:52 -0700
parents 02a35ad4adf8
children c3e045194476
line wrap: on
line diff
--- a/src/share/vm/opto/escape.cpp	Fri Jul 25 16:03:40 2008 -0700
+++ b/src/share/vm/opto/escape.cpp	Mon Jul 28 17:12:52 2008 -0700
@@ -62,10 +62,14 @@
  "F"  // FieldEdge
 };
 
-void PointsToNode::dump() const {
+void PointsToNode::dump(bool print_state) const {
   NodeType nt = node_type();
-  EscapeState es = escape_state();
-  tty->print("%s %s %s [[", node_type_names[(int) nt], esc_names[(int) es], _scalar_replaceable ? "" : "NSR");
+  tty->print("%s ", node_type_names[(int) nt]);
+  if (print_state) {
+    EscapeState es = escape_state();
+    tty->print("%s %s ", esc_names[(int) es], _scalar_replaceable ? "":"NSR");
+  }
+  tty->print("[[");
   for (uint i = 0; i < edge_count(); i++) {
     tty->print(" %d%s", edge_target(i), edge_type_suffix[(int) edge_type(i)]);
   }
@@ -84,11 +88,22 @@
   _compile(C),
   _node_map(C->comp_arena()) {
 
-  _phantom_object = C->top()->_idx;
-  PointsToNode *phn = ptnode_adr(_phantom_object);
-  phn->_node = C->top();
-  phn->set_node_type(PointsToNode::JavaObject);
-  phn->set_escape_state(PointsToNode::GlobalEscape);
+  _phantom_object = C->top()->_idx,
+  add_node(C->top(), PointsToNode::JavaObject, PointsToNode::GlobalEscape,true);
+
+  // Add ConP(#NULL) and ConN(#NULL) nodes.
+  PhaseGVN* igvn = C->initial_gvn();
+  Node* oop_null = igvn->zerocon(T_OBJECT);
+  _oop_null = oop_null->_idx;
+  assert(_oop_null < C->unique(), "should be created already");
+  add_node(oop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true);
+
+  if (UseCompressedOops) {
+    Node* noop_null = igvn->zerocon(T_NARROWOOP);
+    _noop_null = noop_null->_idx;
+    assert(_noop_null < C->unique(), "should be created already");
+    add_node(noop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true);
+  }
 }
 
 void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) {
@@ -500,29 +515,30 @@
   igvn->set_type(addp, tinst);
   // record the allocation in the node map
   set_map(addp->_idx, get_map(base->_idx));
-  // if the Address input is not the appropriate instance type
-  // (due to intervening casts,) insert a cast
-  Node *adr = addp->in(AddPNode::Address);
-  const TypeOopPtr  *atype = igvn->type(adr)->isa_oopptr();
-  if (atype != NULL && atype->instance_id() != inst_id) {
-    assert(!atype->is_known_instance(), "no conflicting instances");
-    const TypeOopPtr *new_atype = base_t->add_offset(atype->offset())->isa_oopptr();
-    Node *acast = new (_compile, 2) CastPPNode(adr, new_atype);
-    acast->set_req(0, adr->in(0));
-    igvn->set_type(acast, new_atype);
-    record_for_optimizer(acast);
-    Node *bcast = acast;
-    Node *abase = addp->in(AddPNode::Base);
-    if (abase != adr) {
-      bcast = new (_compile, 2) CastPPNode(abase, base_t);
-      bcast->set_req(0, abase->in(0));
-      igvn->set_type(bcast, base_t);
-      record_for_optimizer(bcast);
+
+  // Set addp's Base and Address to 'base'.
+  Node *abase = addp->in(AddPNode::Base);
+  Node *adr   = addp->in(AddPNode::Address);
+  if (adr->is_Proj() && adr->in(0)->is_Allocate() &&
+      adr->in(0)->_idx == (uint)inst_id) {
+    // Skip AddP cases #3 and #5.
+  } else {
+    assert(!abase->is_top(), "sanity"); // AddP case #3
+    if (abase != base) {
+      igvn->hash_delete(addp);
+      addp->set_req(AddPNode::Base, base);
+      if (abase == adr) {
+        addp->set_req(AddPNode::Address, base);
+      } else {
+        // AddP case #4 (adr is array's element offset AddP node)
+#ifdef ASSERT
+        const TypeOopPtr *atype = igvn->type(adr)->isa_oopptr();
+        assert(adr->is_AddP() && atype != NULL &&
+               atype->instance_id() == inst_id, "array's element offset should be processed first");
+#endif
+      }
+      igvn->hash_insert(addp);
     }
-    igvn->hash_delete(addp);
-    addp->set_req(AddPNode::Base, bcast);
-    addp->set_req(AddPNode::Address, acast);
-    igvn->hash_insert(addp);
   }
   // Put on IGVN worklist since at least addp's type was changed above.
   record_for_optimizer(addp);
@@ -660,27 +676,31 @@
   Compile* C = phase->C;
   const TypeOopPtr *tinst = C->get_adr_type(alias_idx)->isa_oopptr();
   bool is_instance = (tinst != NULL) && tinst->is_known_instance();
+  Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
   Node *prev = NULL;
   Node *result = orig_mem;
   while (prev != result) {
     prev = result;
+    if (result == start_mem)
+      break;  // hit one of our sentinals
     if (result->is_Mem()) {
-      MemNode *mem = result->as_Mem();
-      const Type *at = phase->type(mem->in(MemNode::Address));
+      const Type *at = phase->type(result->in(MemNode::Address));
       if (at != Type::TOP) {
         assert (at->isa_ptr() != NULL, "pointer type required.");
         int idx = C->get_alias_index(at->is_ptr());
         if (idx == alias_idx)
           break;
       }
-      result = mem->in(MemNode::Memory);
+      result = result->in(MemNode::Memory);
     }
     if (!is_instance)
       continue;  // don't search further for non-instance types
     // skip over a call which does not affect this memory slice
     if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) {
       Node *proj_in = result->in(0);
-      if (proj_in->is_Call()) {
+      if (proj_in->is_Allocate() && proj_in->_idx == (uint)tinst->instance_id()) {
+        break;  // hit one of our sentinals
+      } else if (proj_in->is_Call()) {
         CallNode *call = proj_in->as_Call();
         if (!call->may_modify(tinst, phase)) {
           result = call->in(TypeFunc::Memory);
@@ -1006,12 +1026,12 @@
         memnode_worklist.append_if_missing(use);
       } else if (use->is_MergeMem()) {
         mergemem_worklist.append_if_missing(use);
-      } else if (use->is_Call() && tinst != NULL) {
+      } else if (use->is_SafePoint() && tinst != NULL) {
         // Look for MergeMem nodes for calls which reference unique allocation
         // (through CheckCastPP nodes) even for debug info.
         Node* m = use->in(TypeFunc::Memory);
         uint iid = tinst->instance_id();
-        while (m->is_Proj() && m->in(0)->is_Call() &&
+        while (m->is_Proj() && m->in(0)->is_SafePoint() &&
                m->in(0) != use && !m->in(0)->_idx != iid) {
           m = m->in(0)->in(TypeFunc::Memory);
         }
@@ -1348,15 +1368,95 @@
       remove_deferred(ni, &deferred_edges, &visited);
       Node *n = ptn->_node;
       if (n->is_AddP()) {
-        // If this AddP computes an address which may point to more that one
-        // object or more then one field (array's element), nothing the address
-        // points to can be scalar replaceable.
+        // Search for objects which are not scalar replaceable.
+        // Mark their escape state as ArgEscape to propagate the state
+        // to referenced objects.
+        // Note: currently there are no difference in compiler optimizations
+        // for ArgEscape objects and NoEscape objects which are not
+        // scalar replaceable.
+
+        int offset = ptn->offset();
         Node *base = get_addp_base(n);
         ptset.Clear();
         PointsTo(ptset, base, igvn);
-        if (ptset.Size() > 1 ||
-            (ptset.Size() != 0 && ptn->offset() == Type::OffsetBot)) {
+        int ptset_size = ptset.Size();
+
+        // Check if a field's initializing value is recorded and add
+        // a corresponding NULL field's value if it is not recorded.
+        // Connection Graph does not record a default initialization by NULL
+        // captured by Initialize node.
+        //
+        // Note: it will disable scalar replacement in some cases:
+        //
+        //    Point p[] = new Point[1];
+        //    p[0] = new Point(); // Will be not scalar replaced
+        //
+        // but it will save us from incorrect optimizations in next cases:
+        //
+        //    Point p[] = new Point[1];
+        //    if ( x ) p[0] = new Point(); // Will be not scalar replaced
+        //
+        // Without a control flow analysis we can't distinguish above cases.
+        //
+        if (offset != Type::OffsetBot && ptset_size == 1) {
+          uint elem = ptset.getelem(); // Allocation node's index
+          // It does not matter if it is not Allocation node since
+          // only non-escaping allocations are scalar replaced.
+          if (ptnode_adr(elem)->_node->is_Allocate() &&
+              ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) {
+            AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate();
+            InitializeNode* ini = alloc->initialization();
+            Node* value = NULL;
+            if (ini != NULL) {
+              BasicType ft = UseCompressedOops ? T_NARROWOOP : T_OBJECT;
+              Node* store = ini->find_captured_store(offset, type2aelembytes(ft), igvn);
+              if (store != NULL && store->is_Store())
+                value = store->in(MemNode::ValueIn);
+            }
+            if (value == NULL || value != ptnode_adr(value->_idx)->_node) {
+              // A field's initializing value was not recorded. Add NULL.
+              uint null_idx = UseCompressedOops ? _noop_null : _oop_null;
+              add_pointsto_edge(ni, null_idx);
+            }
+          }
+        }
+
+        // An object is not scalar replaceable if the field which may point
+        // to it has unknown offset (unknown element of an array of objects).
+        //
+        if (offset == Type::OffsetBot) {
+          uint e_cnt = ptn->edge_count();
+          for (uint ei = 0; ei < e_cnt; ei++) {
+            uint npi = ptn->edge_target(ei);
+            set_escape_state(npi, PointsToNode::ArgEscape);
+            ptnode_adr(npi)->_scalar_replaceable = false;
+          }
+        }
+
+        // Currently an object is not scalar replaceable if a LoadStore node
+        // access its field since the field value is unknown after it.
+        //
+        bool has_LoadStore = false;
+        for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+          Node *use = n->fast_out(i);
+          if (use->is_LoadStore()) {
+            has_LoadStore = true;
+            break;
+          }
+        }
+        // An object is not scalar replaceable if the address points
+        // to unknown field (unknown element for arrays, offset is OffsetBot).
+        //
+        // Or the address may point to more then one object. This may produce
+        // the false positive result (set scalar_replaceable to false)
+        // since the flow-insensitive escape analysis can't separate
+        // the case when stores overwrite the field's value from the case
+        // when stores happened on different control branches.
+        //
+        if (ptset_size > 1 || ptset_size != 0 &&
+            (has_LoadStore || offset == Type::OffsetBot)) {
           for( VectorSetI j(&ptset); j.test(); ++j ) {
+            set_escape_state(j.elem, PointsToNode::ArgEscape);
             ptnode_adr(j.elem)->_scalar_replaceable = false;
           }
         }
@@ -1855,7 +1955,7 @@
     case Op_LoadN:
     {
       const Type *t = phase->type(n);
-      if (!t->isa_narrowoop() && t->isa_ptr() == NULL) {
+      if (t->make_ptr() == NULL) {
         _processed.set(n->_idx);
         return;
       }
@@ -1878,8 +1978,9 @@
     }
     case Op_Phi:
     {
-      if (n->as_Phi()->type()->isa_ptr() == NULL) {
-        // nothing to do if not an oop
+      const Type *t = n->as_Phi()->type();
+      if (t->make_ptr() == NULL) {
+        // nothing to do if not an oop or narrow oop
         _processed.set(n->_idx);
         return;
       }
@@ -2067,7 +2168,7 @@
     {
       const Type *t = phase->type(n);
 #ifdef ASSERT
-      if (!t->isa_narrowoop() && t->isa_ptr() == NULL)
+      if (t->make_ptr() == NULL)
         assert(false, "Op_LoadP");
 #endif
 
@@ -2099,7 +2200,8 @@
     case Op_Phi:
     {
 #ifdef ASSERT
-      if (n->as_Phi()->type()->isa_ptr() == NULL)
+      const Type *t = n->as_Phi()->type();
+      if (t->make_ptr() == NULL)
         assert(false, "Op_Phi");
 #endif
       for (uint i = 1; i < n->req() ; i++) {
@@ -2213,16 +2315,14 @@
         PointsToNode::NodeType ptn_loc_type = ptn_loc->node_type();
         if ( ptn_loc_type == PointsToNode::LocalVar && ptn_loc->_node != NULL &&
              ptn_loc->edge_count() == 1 && ptn_loc->edge_target(0) == ni ) {
-          tty->print("%6d  LocalVar [[%d]]", li, ni);
-          ptnode_adr(li)->_node->dump();
+          ptnode_adr(li)->dump(false);
         }
       }
       if (Verbose) {
         // Print all fields which reference this allocation
         for (uint i = 0; i < ptn->edge_count(); i++) {
           uint ei = ptn->edge_target(i);
-          tty->print("%6d  Field [[%d]]", ei, ni);
-          ptnode_adr(ei)->_node->dump();
+          ptnode_adr(ei)->dump(false);
         }
       }
       tty->cr();