void ConnectionGraph::split_unique_types()

in src/hotspot/share/opto/escape.cpp [4403:5053]


void ConnectionGraph::split_unique_types(GrowableArray<Node *>  &alloc_worklist,
                                         GrowableArray<ArrayCopyNode*> &arraycopy_worklist,
                                         GrowableArray<MergeMemNode*> &mergemem_worklist,
                                         Unique_Node_List &reducible_merges) {
  DEBUG_ONLY(Unique_Node_List reduced_merges;)
  GrowableArray<Node *>  memnode_worklist;
  GrowableArray<PhiNode *>  orig_phis;
  PhaseIterGVN  *igvn = _igvn;
  uint new_index_start = (uint) _compile->num_alias_types();
  VectorSet visited;
  ideal_nodes.clear(); // Reset for use with set_map/get_map.
  uint unique_old = _compile->unique();

  //  Phase 1:  Process possible allocations from alloc_worklist.
  //  Create instance types for the CheckCastPP for allocations where possible.
  //
  // (Note: don't forget to change the order of the second AddP node on
  //  the alloc_worklist if the order of the worklist processing is changed,
  //  see the comment in find_second_addp().)
  //
  while (alloc_worklist.length() != 0) {
    Node *n = alloc_worklist.pop();
    uint ni = n->_idx;
    if (n->is_Call()) {
      CallNode *alloc = n->as_Call();
      // copy escape information to call node
      PointsToNode* ptn = ptnode_adr(alloc->_idx);
      PointsToNode::EscapeState es = ptn->escape_state();
      // We have an allocation or call which returns a Java object,
      // see if it is non-escaped.
      if (es != PointsToNode::NoEscape || !ptn->scalar_replaceable()) {
        continue;
      }
      // Find CheckCastPP for the allocate or for the return value of a call
      n = alloc->result_cast();
      if (n == nullptr) {            // No uses except Initialize node
        if (alloc->is_Allocate()) {
          // Set the scalar_replaceable flag for allocation
          // so it could be eliminated if it has no uses.
          alloc->as_Allocate()->_is_scalar_replaceable = true;
        }
        continue;
      }
      if (!n->is_CheckCastPP()) { // not unique CheckCastPP.
        // we could reach here for allocate case if one init is associated with many allocs.
        if (alloc->is_Allocate()) {
          alloc->as_Allocate()->_is_scalar_replaceable = false;
        }
        continue;
      }

      // The inline code for Object.clone() casts the allocation result to
      // java.lang.Object and then to the actual type of the allocated
      // object. Detect this case and use the second cast.
      // Also detect j.l.reflect.Array.newInstance(jobject, jint) case when
      // the allocation result is cast to java.lang.Object and then
      // to the actual Array type.
      if (alloc->is_Allocate() && n->as_Type()->type() == TypeInstPtr::NOTNULL
          && (alloc->is_AllocateArray() ||
              igvn->type(alloc->in(AllocateNode::KlassNode)) != TypeInstKlassPtr::OBJECT)) {
        Node *cast2 = nullptr;
        for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
          Node *use = n->fast_out(i);
          if (use->is_CheckCastPP()) {
            cast2 = use;
            break;
          }
        }
        if (cast2 != nullptr) {
          n = cast2;
        } else {
          // Non-scalar replaceable if the allocation type is unknown statically
          // (reflection allocation), the object can't be restored during
          // deoptimization without precise type.
          continue;
        }
      }

      const TypeOopPtr *t = igvn->type(n)->isa_oopptr();
      if (t == nullptr) {
        continue;  // not a TypeOopPtr
      }
      if (!t->klass_is_exact()) {
        continue; // not an unique type
      }
      if (alloc->is_Allocate()) {
        // Set the scalar_replaceable flag for allocation
        // so it could be eliminated.
        alloc->as_Allocate()->_is_scalar_replaceable = true;
      }
      set_escape_state(ptnode_adr(n->_idx), es NOT_PRODUCT(COMMA trace_propagate_message(ptn))); // CheckCastPP escape state
      // in order for an object to be scalar-replaceable, it must be:
      //   - a direct allocation (not a call returning an object)
      //   - non-escaping
      //   - eligible to be a unique type
      //   - not determined to be ineligible by escape analysis
      set_map(alloc, n);
      set_map(n, alloc);
      const TypeOopPtr* tinst = t->cast_to_instance_id(ni);
      igvn->hash_delete(n);
      igvn->set_type(n,  tinst);
      n->raise_bottom_type(tinst);
      igvn->hash_insert(n);
      record_for_optimizer(n);
      // Allocate an alias index for the header fields. Accesses to
      // the header emitted during macro expansion wouldn't have
      // correct memory state otherwise.
      _compile->get_alias_index(tinst->add_offset(oopDesc::mark_offset_in_bytes()));
      _compile->get_alias_index(tinst->add_offset(oopDesc::klass_offset_in_bytes()));
      if (alloc->is_Allocate() && (t->isa_instptr() || t->isa_aryptr())) {
        // Add a new NarrowMem projection for each existing NarrowMem projection with new adr type
        InitializeNode* init = alloc->as_Allocate()->initialization();
        assert(init != nullptr, "can't find Initialization node for this Allocate node");
        auto process_narrow_proj = [&](NarrowMemProjNode* proj) {
          const TypePtr* adr_type = proj->adr_type();
          const TypePtr* new_adr_type = tinst->add_offset(adr_type->offset());
          if (adr_type != new_adr_type && !init->already_has_narrow_mem_proj_with_adr_type(new_adr_type)) {
            DEBUG_ONLY( uint alias_idx = _compile->get_alias_index(new_adr_type); )
            assert(_compile->get_general_index(alias_idx) == _compile->get_alias_index(adr_type), "new adr type should be narrowed down from existing adr type");
            NarrowMemProjNode* new_proj = new NarrowMemProjNode(init, new_adr_type);
            igvn->set_type(new_proj, new_proj->bottom_type());
            record_for_optimizer(new_proj);
            set_map(proj, new_proj); // record it so ConnectionGraph::find_inst_mem() can find it
          }
        };
        init->for_each_narrow_mem_proj_with_new_uses(process_narrow_proj);

        // First, put on the worklist all Field edges from Connection Graph
        // which is more accurate than putting immediate users from Ideal Graph.
        for (EdgeIterator e(ptn); e.has_next(); e.next()) {
          PointsToNode* tgt = e.get();
          if (tgt->is_Arraycopy()) {
            continue;
          }
          Node* use = tgt->ideal_node();
          assert(tgt->is_Field() && use->is_AddP(),
                 "only AddP nodes are Field edges in CG");
          if (use->outcnt() > 0) { // Don't process dead nodes
            Node* addp2 = find_second_addp(use, use->in(AddPNode::Base));
            if (addp2 != nullptr) {
              assert(alloc->is_AllocateArray(),"array allocation was expected");
              alloc_worklist.append_if_missing(addp2);
            }
            alloc_worklist.append_if_missing(use);
          }
        }

        // An allocation may have an Initialize which has raw stores. Scan
        // the users of the raw allocation result and push AddP users
        // on alloc_worklist.
        Node *raw_result = alloc->proj_out_or_null(TypeFunc::Parms);
        assert (raw_result != nullptr, "must have an allocation result");
        for (DUIterator_Fast imax, i = raw_result->fast_outs(imax); i < imax; i++) {
          Node *use = raw_result->fast_out(i);
          if (use->is_AddP() && use->outcnt() > 0) { // Don't process dead nodes
            Node* addp2 = find_second_addp(use, raw_result);
            if (addp2 != nullptr) {
              assert(alloc->is_AllocateArray(),"array allocation was expected");
              alloc_worklist.append_if_missing(addp2);
            }
            alloc_worklist.append_if_missing(use);
          } else if (use->is_MemBar()) {
            memnode_worklist.append_if_missing(use);
          }
        }
      }
    } else if (n->is_AddP()) {
      if (has_reducible_merge_base(n->as_AddP(), reducible_merges)) {
        // This AddP will go away when we reduce the Phi
        continue;
      }
      Node* addp_base = get_addp_base(n);
      JavaObjectNode* jobj = unique_java_object(addp_base);
      if (jobj == nullptr || jobj == phantom_obj) {
#ifdef ASSERT
        ptnode_adr(get_addp_base(n)->_idx)->dump();
        ptnode_adr(n->_idx)->dump();
        assert(jobj != nullptr && jobj != phantom_obj, "escaped allocation");
#endif
        _compile->record_failure(_invocation > 0 ? C2Compiler::retry_no_iterative_escape_analysis() : C2Compiler::retry_no_escape_analysis());
        return;
      }
      Node *base = get_map(jobj->idx());  // CheckCastPP node
      if (!split_AddP(n, base)) continue; // wrong type from dead path
    } else if (n->is_Phi() ||
               n->is_CheckCastPP() ||
               n->is_EncodeP() ||
               n->is_DecodeN() ||
               (n->is_ConstraintCast() && n->Opcode() == Op_CastPP)) {
      if (visited.test_set(n->_idx)) {
        assert(n->is_Phi(), "loops only through Phi's");
        continue;  // already processed
      }
      // Reducible Phi's will be removed from the graph after split_unique_types
      // finishes. For now we just try to split out the SR inputs of the merge.
      Node* parent = n->in(1);
      if (reducible_merges.member(n)) {
        reduce_phi(n->as_Phi(), alloc_worklist);
#ifdef ASSERT
        if (VerifyReduceAllocationMerges) {
          reduced_merges.push(n);
        }
#endif
        continue;
      } else if (reducible_merges.member(parent)) {
        // 'n' is an user of a reducible merge (a Phi). It will be simplified as
        // part of reduce_merge.
        continue;
      }
      JavaObjectNode* jobj = unique_java_object(n);
      if (jobj == nullptr || jobj == phantom_obj) {
#ifdef ASSERT
        ptnode_adr(n->_idx)->dump();
        assert(jobj != nullptr && jobj != phantom_obj, "escaped allocation");
#endif
        _compile->record_failure(_invocation > 0 ? C2Compiler::retry_no_iterative_escape_analysis() : C2Compiler::retry_no_escape_analysis());
        return;
      } else {
        Node *val = get_map(jobj->idx());   // CheckCastPP node
        TypeNode *tn = n->as_Type();
        const TypeOopPtr* tinst = igvn->type(val)->isa_oopptr();
        assert(tinst != nullptr && tinst->is_known_instance() &&
               tinst->instance_id() == jobj->idx() , "instance type expected.");

        const Type *tn_type = igvn->type(tn);
        const TypeOopPtr *tn_t;
        if (tn_type->isa_narrowoop()) {
          tn_t = tn_type->make_ptr()->isa_oopptr();
        } else {
          tn_t = tn_type->isa_oopptr();
        }
        if (tn_t != nullptr && tinst->maybe_java_subtype_of(tn_t)) {
          if (tn_type->isa_narrowoop()) {
            tn_type = tinst->make_narrowoop();
          } else {
            tn_type = tinst;
          }
          igvn->hash_delete(tn);
          igvn->set_type(tn, tn_type);
          tn->set_type(tn_type);
          igvn->hash_insert(tn);
          record_for_optimizer(n);
        } else {
          assert(tn_type == TypePtr::NULL_PTR ||
                 (tn_t != nullptr && !tinst->maybe_java_subtype_of(tn_t)),
                 "unexpected type");
          continue; // Skip dead path with different type
        }
      }
    } else {
      DEBUG_ONLY(n->dump();)
      assert(false, "EA: unexpected node");
      continue;
    }
    // push allocation's users on appropriate worklist
    for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
      Node *use = n->fast_out(i);
      if(use->is_Mem() && use->in(MemNode::Address) == n) {
        // Load/store to instance's field
        memnode_worklist.append_if_missing(use);
      } else if (use->is_MemBar()) {
        if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge
          memnode_worklist.append_if_missing(use);
        }
      } else if (use->is_AddP() && use->outcnt() > 0) { // No dead nodes
        Node* addp2 = find_second_addp(use, n);
        if (addp2 != nullptr) {
          alloc_worklist.append_if_missing(addp2);
        }
        alloc_worklist.append_if_missing(use);
      } else if (use->is_Phi() ||
                 use->is_CheckCastPP() ||
                 use->is_EncodeNarrowPtr() ||
                 use->is_DecodeNarrowPtr() ||
                 (use->is_ConstraintCast() && use->Opcode() == Op_CastPP)) {
        alloc_worklist.append_if_missing(use);
#ifdef ASSERT
      } else if (use->is_Mem()) {
        assert(use->in(MemNode::Address) != n, "EA: missing allocation reference path");
      } else if (use->is_MergeMem()) {
        assert(mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist");
      } else if (use->is_SafePoint()) {
        // Look for MergeMem nodes for calls which reference unique allocation
        // (through CheckCastPP nodes) even for debug info.
        Node* m = use->in(TypeFunc::Memory);
        if (m->is_MergeMem()) {
          assert(mergemem_worklist.contains(m->as_MergeMem()), "EA: missing MergeMem node in the worklist");
        }
      } else if (use->Opcode() == Op_EncodeISOArray) {
        if (use->in(MemNode::Memory) == n || use->in(3) == n) {
          // EncodeISOArray overwrites destination array
          memnode_worklist.append_if_missing(use);
        }
      } else {
        uint op = use->Opcode();
        if ((op == Op_StrCompressedCopy || op == Op_StrInflatedCopy) &&
            (use->in(MemNode::Memory) == n)) {
          // They overwrite memory edge corresponding to destination array,
          memnode_worklist.append_if_missing(use);
        } else if (!(op == Op_CmpP || op == Op_Conv2B ||
              op == Op_CastP2X ||
              op == Op_FastLock || op == Op_AryEq ||
              op == Op_StrComp || op == Op_CountPositives ||
              op == Op_StrCompressedCopy || op == Op_StrInflatedCopy ||
              op == Op_StrEquals || op == Op_VectorizedHashCode ||
              op == Op_StrIndexOf || op == Op_StrIndexOfChar ||
              op == Op_SubTypeCheck ||
              op == Op_ReinterpretS2HF ||
              BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use))) {
          n->dump();
          use->dump();
          assert(false, "EA: missing allocation reference path");
        }
#endif
      }
    }

  }

#ifdef ASSERT
  if (VerifyReduceAllocationMerges) {
    for (uint i = 0; i < reducible_merges.size(); i++) {
      Node* phi = reducible_merges.at(i);

      if (!reduced_merges.member(phi)) {
        phi->dump(2);
        phi->dump(-2);
        assert(false, "This reducible merge wasn't reduced.");
      }

      // At this point reducible Phis shouldn't have AddP users anymore; only SafePoints or Casts.
      for (DUIterator_Fast jmax, j = phi->fast_outs(jmax); j < jmax; j++) {
        Node* use = phi->fast_out(j);
        if (!use->is_SafePoint() && !use->is_CastPP()) {
          phi->dump(2);
          phi->dump(-2);
          assert(false, "Unexpected user of reducible Phi -> %d:%s:%d", use->_idx, use->Name(), use->outcnt());
        }
      }
    }
  }
#endif

  // Go over all ArrayCopy nodes and if one of the inputs has a unique
  // type, record it in the ArrayCopy node so we know what memory this
  // node uses/modified.
  for (int next = 0; next < arraycopy_worklist.length(); next++) {
    ArrayCopyNode* ac = arraycopy_worklist.at(next);
    Node* dest = ac->in(ArrayCopyNode::Dest);
    if (dest->is_AddP()) {
      dest = get_addp_base(dest);
    }
    JavaObjectNode* jobj = unique_java_object(dest);
    if (jobj != nullptr) {
      Node *base = get_map(jobj->idx());
      if (base != nullptr) {
        const TypeOopPtr *base_t = _igvn->type(base)->isa_oopptr();
        ac->_dest_type = base_t;
      }
    }
    Node* src = ac->in(ArrayCopyNode::Src);
    if (src->is_AddP()) {
      src = get_addp_base(src);
    }
    jobj = unique_java_object(src);
    if (jobj != nullptr) {
      Node* base = get_map(jobj->idx());
      if (base != nullptr) {
        const TypeOopPtr *base_t = _igvn->type(base)->isa_oopptr();
        ac->_src_type = base_t;
      }
    }
  }

  // New alias types were created in split_AddP().
  uint new_index_end = (uint) _compile->num_alias_types();

  _compile->print_method(PHASE_EA_AFTER_SPLIT_UNIQUE_TYPES_1, 5);

  //  Phase 2:  Process MemNode's from memnode_worklist. compute new address type and
  //            compute new values for Memory inputs  (the Memory inputs are not
  //            actually updated until phase 4.)
  if (memnode_worklist.length() == 0)
    return;  // nothing to do
  while (memnode_worklist.length() != 0) {
    Node *n = memnode_worklist.pop();
    if (visited.test_set(n->_idx)) {
      continue;
    }
    if (n->is_Phi() || n->is_ClearArray()) {
      // we don't need to do anything, but the users must be pushed
    } else if (n->is_MemBar()) { // MemBar nodes
      if (!n->is_Initialize()) { // memory projections for Initialize pushed below (so we get to all their uses)
        // we don't need to do anything, but the users must be pushed
        n = n->as_MemBar()->proj_out_or_null(TypeFunc::Memory);
        if (n == nullptr) {
          continue;
        }
      }
    } else if (n->is_CallLeaf()) {
      // Runtime calls with narrow memory input (no MergeMem node)
      // get the memory projection
      n = n->as_Call()->proj_out_or_null(TypeFunc::Memory);
      if (n == nullptr) {
        continue;
      }
    } else if (n->Opcode() == Op_StrInflatedCopy) {
      // Check direct uses of StrInflatedCopy.
      // It is memory type Node - no special SCMemProj node.
    } else if (n->Opcode() == Op_StrCompressedCopy ||
               n->Opcode() == Op_EncodeISOArray) {
      // get the memory projection
      n = n->find_out_with(Op_SCMemProj);
      assert(n != nullptr && n->Opcode() == Op_SCMemProj, "memory projection required");
    } else if (n->is_Proj()) {
      assert(n->in(0)->is_Initialize(), "we only push memory projections for Initialize");
    } else {
#ifdef ASSERT
      if (!n->is_Mem()) {
        n->dump();
      }
      assert(n->is_Mem(), "memory node required.");
#endif
      Node *addr = n->in(MemNode::Address);
      const Type *addr_t = igvn->type(addr);
      if (addr_t == Type::TOP) {
        continue;
      }
      assert (addr_t->isa_ptr() != nullptr, "pointer type required.");
      int alias_idx = _compile->get_alias_index(addr_t->is_ptr());
      assert ((uint)alias_idx < new_index_end, "wrong alias index");
      Node *mem = find_inst_mem(n->in(MemNode::Memory), alias_idx, orig_phis);
      if (_compile->failing()) {
        return;
      }
      if (mem != n->in(MemNode::Memory)) {
        // We delay the memory edge update since we need old one in
        // MergeMem code below when instances memory slices are separated.
        set_map(n, mem);
      }
      if (n->is_Load()) {
        continue;  // don't push users
      } else if (n->is_LoadStore()) {
        // get the memory projection
        n = n->find_out_with(Op_SCMemProj);
        assert(n != nullptr && n->Opcode() == Op_SCMemProj, "memory projection required");
      }
    }
    // push user on appropriate worklist
    for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
      Node *use = n->fast_out(i);
      if (use->is_Phi() || use->is_ClearArray()) {
        memnode_worklist.append_if_missing(use);
      } else if (use->is_Mem() && use->in(MemNode::Memory) == n) {
        memnode_worklist.append_if_missing(use);
      } else if (use->is_MemBar() || use->is_CallLeaf()) {
        if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge
          memnode_worklist.append_if_missing(use);
        }
      } else if (use->is_Proj()) {
        assert(n->is_Initialize(), "We only push projections of Initialize");
        if (use->as_Proj()->_con == TypeFunc::Memory) { // Ignore precedent edge
          memnode_worklist.append_if_missing(use);
        }
#ifdef ASSERT
      } else if(use->is_Mem()) {
        assert(use->in(MemNode::Memory) != n, "EA: missing memory path");
      } else if (use->is_MergeMem()) {
        assert(mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist");
      } else if (use->Opcode() == Op_EncodeISOArray) {
        if (use->in(MemNode::Memory) == n || use->in(3) == n) {
          // EncodeISOArray overwrites destination array
          memnode_worklist.append_if_missing(use);
        }
      } else {
        uint op = use->Opcode();
        if ((use->in(MemNode::Memory) == n) &&
            (op == Op_StrCompressedCopy || op == Op_StrInflatedCopy)) {
          // They overwrite memory edge corresponding to destination array,
          memnode_worklist.append_if_missing(use);
        } else if (!(BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use) ||
              op == Op_AryEq || op == Op_StrComp || op == Op_CountPositives ||
              op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || op == Op_VectorizedHashCode ||
              op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar)) {
          n->dump();
          use->dump();
          assert(false, "EA: missing memory path");
        }
#endif
      }
    }
  }

  //  Phase 3:  Process MergeMem nodes from mergemem_worklist.
  //            Walk each memory slice moving the first node encountered of each
  //            instance type to the input corresponding to its alias index.
  uint length = mergemem_worklist.length();
  for( uint next = 0; next < length; ++next ) {
    MergeMemNode* nmm = mergemem_worklist.at(next);
    assert(!visited.test_set(nmm->_idx), "should not be visited before");
    // Note: we don't want to use MergeMemStream here because we only want to
    // scan inputs which exist at the start, not ones we add during processing.
    // Note 2: MergeMem may already contains instance memory slices added
    // during find_inst_mem() call when memory nodes were processed above.
    igvn->hash_delete(nmm);
    uint nslices = MIN2(nmm->req(), new_index_start);
    for (uint i = Compile::AliasIdxRaw+1; i < nslices; i++) {
      Node* mem = nmm->in(i);
      Node* cur = nullptr;
      if (mem == nullptr || mem->is_top()) {
        continue;
      }
      // First, update mergemem by moving memory nodes to corresponding slices
      // if their type became more precise since this mergemem was created.
      while (mem->is_Mem()) {
        const Type* at = igvn->type(mem->in(MemNode::Address));
        if (at != Type::TOP) {
          assert (at->isa_ptr() != nullptr, "pointer type required.");
          uint idx = (uint)_compile->get_alias_index(at->is_ptr());
          if (idx == i) {
            if (cur == nullptr) {
              cur = mem;
            }
          } else {
            if (idx >= nmm->req() || nmm->is_empty_memory(nmm->in(idx))) {
              nmm->set_memory_at(idx, mem);
            }
          }
        }
        mem = mem->in(MemNode::Memory);
      }
      nmm->set_memory_at(i, (cur != nullptr) ? cur : mem);
      // Find any instance of the current type if we haven't encountered
      // already a memory slice of the instance along the memory chain.
      for (uint ni = new_index_start; ni < new_index_end; ni++) {
        if((uint)_compile->get_general_index(ni) == i) {
          Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni);
          if (nmm->is_empty_memory(m)) {
            Node* result = find_inst_mem(mem, ni, orig_phis);
            if (_compile->failing()) {
              return;
            }
            nmm->set_memory_at(ni, result);
          }
        }
      }
    }
    // Find the rest of instances values
    for (uint ni = new_index_start; ni < new_index_end; ni++) {
      const TypeOopPtr *tinst = _compile->get_adr_type(ni)->isa_oopptr();
      Node* result = step_through_mergemem(nmm, ni, tinst);
      if (result == nmm->base_memory()) {
        // Didn't find instance memory, search through general slice recursively.
        result = nmm->memory_at(_compile->get_general_index(ni));
        result = find_inst_mem(result, ni, orig_phis);
        if (_compile->failing()) {
          return;
        }
        nmm->set_memory_at(ni, result);
      }
    }

    // If we have crossed the 3/4 point of max node limit it's too risky
    // to continue with EA/SR because we might hit the max node limit.
    if (_compile->live_nodes() >= _compile->max_node_limit() * 0.75) {
      if (_compile->do_reduce_allocation_merges()) {
        _compile->record_failure(C2Compiler::retry_no_reduce_allocation_merges());
      } else if (_invocation > 0) {
        _compile->record_failure(C2Compiler::retry_no_iterative_escape_analysis());
      } else {
        _compile->record_failure(C2Compiler::retry_no_escape_analysis());
      }
      return;
    }

    igvn->hash_insert(nmm);
    record_for_optimizer(nmm);
  }

  _compile->print_method(PHASE_EA_AFTER_SPLIT_UNIQUE_TYPES_3, 5);

  //  Phase 4:  Update the inputs of non-instance memory Phis and
  //            the Memory input of memnodes
  // First update the inputs of any non-instance Phi's from
  // which we split out an instance Phi.  Note we don't have
  // to recursively process Phi's encountered on the input memory
  // chains as is done in split_memory_phi() since they  will
  // also be processed here.
  for (int j = 0; j < orig_phis.length(); j++) {
    PhiNode *phi = orig_phis.at(j);
    int alias_idx = _compile->get_alias_index(phi->adr_type());
    igvn->hash_delete(phi);
    for (uint i = 1; i < phi->req(); i++) {
      Node *mem = phi->in(i);
      Node *new_mem = find_inst_mem(mem, alias_idx, orig_phis);
      if (_compile->failing()) {
        return;
      }
      if (mem != new_mem) {
        phi->set_req(i, new_mem);
      }
    }
    igvn->hash_insert(phi);
    record_for_optimizer(phi);
  }

  // Update the memory inputs of MemNodes with the value we computed
  // in Phase 2 and move stores memory users to corresponding memory slices.
  // Disable memory split verification code until the fix for 6984348.
  // Currently it produces false negative results since it does not cover all cases.
#if 0 // ifdef ASSERT
  visited.Reset();
  Node_Stack old_mems(arena, _compile->unique() >> 2);
#endif
  for (uint i = 0; i < ideal_nodes.size(); i++) {
    Node*    n = ideal_nodes.at(i);
    Node* nmem = get_map(n->_idx);
    assert(nmem != nullptr, "sanity");
    if (n->is_Mem()) {
#if 0 // ifdef ASSERT
      Node* old_mem = n->in(MemNode::Memory);
      if (!visited.test_set(old_mem->_idx)) {
        old_mems.push(old_mem, old_mem->outcnt());
      }
#endif
      assert(n->in(MemNode::Memory) != nmem, "sanity");
      if (!n->is_Load()) {
        // Move memory users of a store first.
        move_inst_mem(n, orig_phis);
      }
      // Now update memory input
      igvn->hash_delete(n);
      n->set_req(MemNode::Memory, nmem);
      igvn->hash_insert(n);
      record_for_optimizer(n);
    } else {
      assert(n->is_Allocate() || n->is_CheckCastPP() ||
             n->is_AddP() || n->is_Phi() || n->is_NarrowMemProj(), "unknown node used for set_map()");
    }
  }
#if 0 // ifdef ASSERT
  // Verify that memory was split correctly
  while (old_mems.is_nonempty()) {
    Node* old_mem = old_mems.node();
    uint  old_cnt = old_mems.index();
    old_mems.pop();
    assert(old_cnt == old_mem->outcnt(), "old mem could be lost");
  }
#endif
  _compile->print_method(PHASE_EA_AFTER_SPLIT_UNIQUE_TYPES_4, 5);
}