diff a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp
--- a/src/hotspot/share/opto/cfgnode.cpp
+++ b/src/hotspot/share/opto/cfgnode.cpp
@@ -31,10 +31,11 @@
 #include "opto/addnode.hpp"
 #include "opto/castnode.hpp"
 #include "opto/cfgnode.hpp"
 #include "opto/connode.hpp"
 #include "opto/convertnode.hpp"
+#include "opto/inlinetypenode.hpp"
 #include "opto/loopnode.hpp"
 #include "opto/machnode.hpp"
 #include "opto/movenode.hpp"
 #include "opto/narrowptrnode.hpp"
 #include "opto/mulnode.hpp"
@@ -516,10 +517,11 @@
   if (!cmp->is_Cmp()) {
     return false;
   }
   return true;
 }
+
 //------------------------------Ideal------------------------------------------
 // Return a node which is more "ideal" than the current node.  Must preserve
 // the CFG, but we can still strip out dead paths.
 Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) {
   if( !can_reshape && !in(0) ) return nullptr;     // Already degraded to a Copy
@@ -962,11 +964,12 @@
     return false; // No comparison
   } else if (cmp1->Opcode() == Op_CmpF || cmp1->Opcode() == Op_CmpD ||
              cmp2->Opcode() == Op_CmpF || cmp2->Opcode() == Op_CmpD ||
              cmp1->Opcode() == Op_CmpP || cmp1->Opcode() == Op_CmpN ||
              cmp2->Opcode() == Op_CmpP || cmp2->Opcode() == Op_CmpN ||
-             cmp1->is_SubTypeCheck() || cmp2->is_SubTypeCheck()) {
+             cmp1->is_SubTypeCheck() || cmp2->is_SubTypeCheck() ||
+             cmp1->is_FlatArrayCheck() || cmp2->is_FlatArrayCheck()) {
     // Floats and pointers don't exactly obey trichotomy. To be on the safe side, don't transform their tests.
     // SubTypeCheck is not commutative
     return false;
   } else if (cmp1 != cmp2) {
     if (cmp1->in(1) == cmp2->in(2) &&
@@ -1041,11 +1044,11 @@
   return nullptr;
 }
 
 
 //=============================================================================
-// note that these functions assume that the _adr_type field is flattened
+// note that these functions assume that the _adr_type field is flat
 uint PhiNode::hash() const {
   const Type* at = _adr_type;
   return TypeNode::hash() + (at ? at->hash() : 0);
 }
 bool PhiNode::cmp( const Node &n ) const {
@@ -1059,11 +1062,11 @@
 
 //----------------------------make---------------------------------------------
 // create a new phi with edges matching r and set (initially) to x
 PhiNode* PhiNode::make(Node* r, Node* x, const Type *t, const TypePtr* at) {
   uint preds = r->req();   // Number of predecessor paths
-  assert(t != Type::MEMORY || at == flatten_phi_adr_type(at), "flatten at");
+  assert(t != Type::MEMORY || at == flatten_phi_adr_type(at) || (flatten_phi_adr_type(at) == TypeAryPtr::INLINES && Compile::current()->flat_accesses_share_alias()), "flatten at");
   PhiNode* p = new PhiNode(r, t, at);
   for (uint j = 1; j < preds; j++) {
     // Fill in all inputs, except those which the region does not yet have
     if (r->in(j) != nullptr)
       p->init_req(j, x);
@@ -1187,10 +1190,18 @@
 void PhiNode::verify_adr_type(bool recursive) const {
   if (VMError::is_error_reported())  return;  // muzzle asserts when debugging an error
   if (Node::in_dump())               return;  // muzzle asserts when printing
 
   assert((_type == Type::MEMORY) == (_adr_type != nullptr), "adr_type for memory phis only");
+  // Flat array element shouldn't get their own memory slice until flat_accesses_share_alias is cleared.
+  // It could be the graph has no loads/stores and flat_accesses_share_alias is never cleared. EA could still
+  // creates per element Phis but that wouldn't be a problem as there are no memory accesses for that array.
+  assert(_adr_type == nullptr || _adr_type->isa_aryptr() == nullptr ||
+         _adr_type->is_aryptr()->is_known_instance() ||
+         !_adr_type->is_aryptr()->is_flat() ||
+         !Compile::current()->flat_accesses_share_alias() ||
+         _adr_type == TypeAryPtr::INLINES, "flat array element shouldn't get its own slice yet");
 
   if (!VerifyAliases)       return;  // verify thoroughly only if requested
 
   assert(_adr_type == flatten_phi_adr_type(_adr_type),
          "Phi::adr_type must be pre-normalized");
@@ -1405,10 +1416,11 @@
       }
     }
   }
   return false;
 }
+
 //----------------------------check_cmove_id-----------------------------------
 // Check for CMove'ing a constant after comparing against the constant.
 // Happens all the time now, since if we compare equality vs a constant in
 // the parser, we "know" the variable is constant on one path and we force
 // it.  Thus code like "if( x==0 ) {/*EMPTY*/}" ends up inserting a
@@ -2025,10 +2037,56 @@
     worklist.push(this);
   }
   return delay;
 }
 
+// Push inline type input nodes (and null) down through the phi recursively (can handle data loops).
+InlineTypeNode* PhiNode::push_inline_types_down(PhaseGVN* phase, bool can_reshape, ciInlineKlass* inline_klass) {
+  assert(inline_klass != nullptr, "must be");
+  InlineTypeNode* vt = InlineTypeNode::make_null(*phase, inline_klass, /* transform = */ false)->clone_with_phis(phase, in(0), nullptr, !_type->maybe_null());
+  if (can_reshape) {
+    // Replace phi right away to be able to use the inline
+    // type node when reaching the phi again through data loops.
+    PhaseIterGVN* igvn = phase->is_IterGVN();
+    for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) {
+      Node* u = fast_out(i);
+      igvn->rehash_node_delayed(u);
+      imax -= u->replace_edge(this, vt);
+      --i;
+    }
+    igvn->rehash_node_delayed(this);
+    assert(outcnt() == 0, "should be dead now");
+  }
+  ResourceMark rm;
+  Node_List casts;
+  for (uint i = 1; i < req(); ++i) {
+    Node* n = in(i);
+    while (n->is_ConstraintCast()) {
+      casts.push(n);
+      n = n->in(1);
+    }
+    if (phase->type(n)->is_zero_type()) {
+      n = InlineTypeNode::make_null(*phase, inline_klass);
+    } else if (n->is_Phi()) {
+      assert(can_reshape, "can only handle phis during IGVN");
+      n = phase->transform(n->as_Phi()->push_inline_types_down(phase, can_reshape, inline_klass));
+    }
+    while (casts.size() != 0) {
+      // Push the cast(s) through the InlineTypeNode
+      // TODO 8302217 Can we avoid cloning? See InlineTypeNode::clone_if_required
+      Node* cast = casts.pop()->clone();
+      cast->set_req_X(1, n->as_InlineType()->get_oop(), phase);
+      n = n->clone();
+      n->as_InlineType()->set_oop(*phase, phase->transform(cast));
+      n = phase->transform(n);
+    }
+    bool transform = !can_reshape && (i == (req()-1)); // Transform phis on last merge
+    vt->merge_with(phase, n->as_InlineType(), i, transform);
+  }
+  return vt;
+}
+
 // If the Phi's Region is in an irreducible loop, and the Region
 // has had an input removed, but not yet transformed, it could be
 // that the Region (and this Phi) are not reachable from Root.
 // If we allow the Phi to collapse before the Region, this may lead
 // to dead-loop data. Wait for the Region to check for reachability,
@@ -2357,10 +2415,12 @@
   // (MergeMemNode is not dead_loop_safe - need to check for dead loop.)
   if (progress == nullptr && can_reshape && type() == Type::MEMORY) {
     // see if this phi should be sliced
     uint merge_width = 0;
     bool saw_self = false;
+    // TODO revisit this with JDK-8247216
+    bool mergemem_only = true;
     for( uint i=1; i<req(); ++i ) {// For all paths in
       Node *ii = in(i);
       // TOP inputs should not be counted as safe inputs because if the
       // Phi references itself through all other inputs then splitting the
       // Phi through memory merges would create dead loop at later stage.
@@ -2369,15 +2429,17 @@
       }
       if (ii->is_MergeMem()) {
         MergeMemNode* n = ii->as_MergeMem();
         merge_width = MAX2(merge_width, n->req());
         saw_self = saw_self || (n->base_memory() == this);
+      } else {
+        mergemem_only = false;
       }
     }
 
     // This restriction is temporarily necessary to ensure termination:
-    if (!saw_self && adr_type() == TypePtr::BOTTOM)  merge_width = 0;
+    if (!mergemem_only && !saw_self && adr_type() == TypePtr::BOTTOM)  merge_width = 0;
 
     if (merge_width > Compile::AliasIdxRaw) {
       // found at least one non-empty MergeMem
       const TypePtr* at = adr_type();
       if (at != TypePtr::BOTTOM) {
@@ -2444,10 +2506,15 @@
         MergeMemNode* result = MergeMemNode::make(new_base);
         for (uint i = 1; i < req(); ++i) {
           Node *ii = in(i);
           if (ii->is_MergeMem()) {
             MergeMemNode* n = ii->as_MergeMem();
+            if (igvn) {
+              // TODO revisit this with JDK-8247216
+              // Put 'n' on the worklist because it might be modified by MergeMemStream::iteration_setup
+              igvn->_worklist.push(n);
+            }
             for (MergeMemStream mms(result, n); mms.next_non_empty2(); ) {
               // If we have not seen this slice yet, make a phi for it.
               bool made_new_phi = false;
               if (mms.is_empty()) {
                 Node* new_phi = new_base->slice_memory(mms.adr_type(phase->C));
@@ -2562,10 +2629,15 @@
       }
     }
   }
 #endif
 
+  Node* inline_type = try_push_inline_types_down(phase, can_reshape);
+  if (inline_type != this) {
+    return inline_type;
+  }
+
   // Try to convert a Phi with two duplicated convert nodes into a phi of the pre-conversion type and the convert node
   // proceeding the phi, to de-duplicate the convert node and compact the IR.
   if (can_reshape && progress == nullptr) {
     ConvertNode* convert = in(1)->isa_Convert();
     if (convert != nullptr) {
@@ -2605,10 +2677,105 @@
   }
 
   return progress;              // Return any progress
 }
 
+// Check recursively if inputs are either an inline type, constant null
+// or another Phi (including self references through data loops). If so,
+// push the inline types down through the phis to enable folding of loads.
+Node* PhiNode::try_push_inline_types_down(PhaseGVN* phase, const bool can_reshape) {
+  if (!can_be_inline_type()) {
+    return this;
+  }
+
+  ciInlineKlass* inline_klass;
+  if (can_push_inline_types_down(phase, can_reshape, inline_klass)) {
+    assert(inline_klass != nullptr, "must be");
+    return push_inline_types_down(phase, can_reshape, inline_klass);
+  }
+  return this;
+}
+
+bool PhiNode::can_push_inline_types_down(PhaseGVN* phase, const bool can_reshape, ciInlineKlass*& inline_klass) {
+  if (req() <= 2) {
+    // Dead phi.
+    return false;
+  }
+  inline_klass = nullptr;
+
+  // TODO 8302217 We need to prevent endless pushing through
+  bool only_phi = (outcnt() != 0);
+  for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) {
+    Node* n = fast_out(i);
+    if (n->is_InlineType() && n->in(1) == this) {
+      return false;
+    }
+    if (!n->is_Phi()) {
+      only_phi = false;
+    }
+  }
+  if (only_phi) {
+    return false;
+  }
+
+  ResourceMark rm;
+  Unique_Node_List worklist;
+  worklist.push(this);
+  Node_List casts;
+
+  for (uint next = 0; next < worklist.size(); next++) {
+    Node* phi = worklist.at(next);
+    for (uint i = 1; i < phi->req(); i++) {
+      Node* n = phi->in(i);
+      if (n == nullptr) {
+        return false;
+      }
+      while (n->is_ConstraintCast()) {
+        if (n->in(0) != nullptr && n->in(0)->is_top()) {
+          // Will die, don't optimize
+          return false;
+        }
+        casts.push(n);
+        n = n->in(1);
+      }
+      const Type* type = phase->type(n);
+      if (n->is_InlineType() && (inline_klass == nullptr || inline_klass == type->inline_klass())) {
+        inline_klass = type->inline_klass();
+      } else if (n->is_Phi() && can_reshape && n->bottom_type()->isa_ptr()) {
+        worklist.push(n);
+      } else if (!type->is_zero_type()) {
+        return false;
+      }
+    }
+  }
+  if (inline_klass == nullptr) {
+    return false;
+  }
+
+  // Check if cast nodes can be pushed through
+  const Type* t = Type::get_const_type(inline_klass);
+  while (casts.size() != 0 && t != nullptr) {
+    Node* cast = casts.pop();
+    if (t->filter(cast->bottom_type()) == Type::TOP) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+#ifdef ASSERT
+bool PhiNode::can_push_inline_types_down(PhaseGVN* phase) {
+  if (!can_be_inline_type()) {
+    return false;
+  }
+
+  ciInlineKlass* inline_klass;
+  return can_push_inline_types_down(phase, true, inline_klass);
+}
+#endif // ASSERT
+
 static int compare_types(const Type* const& e1, const Type* const& e2) {
   return (intptr_t)e1 - (intptr_t)e2;
 }
 
 // Collect types at casts that are going to be eliminated at that Phi and store them in a TypeTuple.
@@ -2987,10 +3154,16 @@
     return phase->C->top(); // dead code
   }
   // We only come from CatchProj, unless the CatchProj goes away.
   // If the CatchProj is optimized away, then we just carry the
   // exception oop through.
+
+  // CheckCastPPNode::Ideal() for inline types reuses the exception
+  // paths of a call to perform an allocation: we can see a Phi here.
+  if (in(1)->is_Phi()) {
+    return this;
+  }
   CallNode *call = in(1)->in(0)->as_Call();
 
   return (in(0)->is_CatchProj() && in(0)->in(0)->is_Catch() &&
           in(0)->in(0)->in(1) == in(1)) ? this : call->in(TypeFunc::Parms);
 }
