diff --git a/src/hotspot/share/ci/ciArrayKlass.cpp b/src/hotspot/share/ci/ciArrayKlass.cpp
index e4d66f247a4..c9cf6cf85e3 100644
--- a/src/hotspot/share/ci/ciArrayKlass.cpp
+++ b/src/hotspot/share/ci/ciArrayKlass.cpp
@@ -26,7 +26,8 @@
 #include "ci/ciArrayKlass.hpp"
 #include "ci/ciObjArrayKlass.hpp"
 #include "ci/ciTypeArrayKlass.hpp"
-#include "ci/ciUtilities.hpp"
+#include "ci/ciUtilities.inline.hpp"
+#include "memory/universe.hpp"
 
 // ciArrayKlass
 //
@@ -103,3 +104,4 @@ ciArrayKlass* ciArrayKlass::make(ciType* element_type) {
     return ciObjArrayKlass::make(element_type->as_klass());
   }
 }
+
diff --git a/src/hotspot/share/ci/ciArrayKlass.hpp b/src/hotspot/share/ci/ciArrayKlass.hpp
index a64d80b20f3..1aee9222741 100644
--- a/src/hotspot/share/ci/ciArrayKlass.hpp
+++ b/src/hotspot/share/ci/ciArrayKlass.hpp
@@ -56,6 +56,7 @@ public:
   bool is_array_klass() const { return true; }
 
   static ciArrayKlass* make(ciType* element_type);
+
 };
 
 #endif // SHARE_CI_CIARRAYKLASS_HPP
diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp
index 584e7d0b1ef..6bbb85fb850 100644
--- a/src/hotspot/share/ci/ciInstanceKlass.cpp
+++ b/src/hotspot/share/ci/ciInstanceKlass.cpp
@@ -69,6 +69,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
   _nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
   _has_injected_fields = -1;
   _implementor = NULL; // we will fill these lazily
+  _transitive_interfaces = NULL;
 
   // Ensure that the metadata wrapped by the ciMetadata is kept alive by GC.
   // This is primarily useful for metadata which is considered as weak roots
@@ -729,6 +730,31 @@ void ciInstanceKlass::dump_replay_instanceKlass(outputStream* out, InstanceKlass
   }
 }
 
+GrowableArray<ciInstanceKlass*>* ciInstanceKlass::transitive_interfaces() const{
+  if (_transitive_interfaces == NULL) {
+    const_cast<ciInstanceKlass*>(this)->compute_transitive_interfaces();
+  }
+  return _transitive_interfaces;
+}
+
+void ciInstanceKlass::compute_transitive_interfaces() {
+  GUARDED_VM_ENTRY(
+          InstanceKlass* ik = get_instanceKlass();
+          Array<InstanceKlass*>* interfaces = ik->transitive_interfaces();
+          Arena* arena = CURRENT_ENV->arena();
+          int len = interfaces->length() + (is_interface() ? 1 : 0);
+          GrowableArray<ciInstanceKlass*>* transitive_interfaces = new(arena)GrowableArray<ciInstanceKlass*>(arena, len,
+                                                                                                             0, NULL);
+          for (int i = 0; i < interfaces->length(); i++) {
+            transitive_interfaces->append(CURRENT_ENV->get_instance_klass(interfaces->at(i)));
+          }
+          if (is_interface()) {
+            transitive_interfaces->append(this);
+          }
+          _transitive_interfaces = transitive_interfaces;
+  );
+}
+
 void ciInstanceKlass::dump_replay_data(outputStream* out) {
   ResourceMark rm;
 
diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp
index 81f3be93bc6..c970232778a 100644
--- a/src/hotspot/share/ci/ciInstanceKlass.hpp
+++ b/src/hotspot/share/ci/ciInstanceKlass.hpp
@@ -76,9 +76,11 @@ private:
   //   A ciInstanceKlass that's not itself: one implementor.
   //   Itself: more than one implementor.
   ciInstanceKlass*       _implementor;
+  GrowableArray<ciInstanceKlass*>* _transitive_interfaces;
 
   void compute_injected_fields();
   bool compute_injected_fields_helper();
+  void compute_transitive_interfaces();
 
 protected:
   ciInstanceKlass(Klass* k);
@@ -292,6 +294,7 @@ public:
   bool has_trusted_loader() const {
     return _has_trusted_loader;
   }
+  GrowableArray<ciInstanceKlass*>* transitive_interfaces() const;
 
   // Replay support
 
diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp
index f1c2252cbff..d93cd4e4f56 100644
--- a/src/hotspot/share/ci/ciObjectFactory.cpp
+++ b/src/hotspot/share/ci/ciObjectFactory.cpp
@@ -167,6 +167,7 @@ void ciObjectFactory::init_shared_objects() {
       assert (obj->is_metadata(), "what else would it be?");
       if (obj->is_loaded() && obj->is_instance_klass()) {
         obj->as_instance_klass()->compute_nonstatic_fields();
+        obj->as_instance_klass()->transitive_interfaces();
       }
     }
   }
diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp
index 3f283ddf64e..836b5859e5e 100644
--- a/src/hotspot/share/opto/castnode.cpp
+++ b/src/hotspot/share/opto/castnode.cpp
@@ -403,83 +403,23 @@ const Type* CheckCastPPNode::Value(PhaseGVN* phase) const {
   const Type *inn = phase->type(in(1));
   if( inn == Type::TOP ) return Type::TOP;  // No information yet
 
-  const TypePtr *in_type   = inn->isa_ptr();
-  const TypePtr *my_type   = _type->isa_ptr();
+  if (inn->isa_oopptr() && _type->isa_oopptr()) {
+    return ConstraintCastNode::Value(phase);
+  }
+
+  const TypePtr *in_type = inn->isa_ptr();
+  const TypePtr *my_type = _type->isa_ptr();
   const Type *result = _type;
-  if( in_type != NULL && my_type != NULL ) {
-    TypePtr::PTR   in_ptr    = in_type->ptr();
+  if (in_type != NULL && my_type != NULL) {
+    TypePtr::PTR in_ptr = in_type->ptr();
     if (in_ptr == TypePtr::Null) {
       result = in_type;
-    } else if (in_ptr == TypePtr::Constant) {
-      if (my_type->isa_rawptr()) {
-        result = my_type;
-      } else {
-        const TypeOopPtr *jptr = my_type->isa_oopptr();
-        assert(jptr, "");
-        result = !in_type->higher_equal(_type)
-          ? my_type->cast_to_ptr_type(TypePtr::NotNull)
-          : in_type;
-      }
     } else {
-      result =  my_type->cast_to_ptr_type( my_type->join_ptr(in_ptr) );
+      result =  my_type->cast_to_ptr_type(my_type->join_ptr(in_ptr));
     }
   }
 
-  // This is the code from TypePtr::xmeet() that prevents us from
-  // having 2 ways to represent the same type. We have to replicate it
-  // here because we don't go through meet/join.
-  if (result->remove_speculative() == result->speculative()) {
-    result = result->remove_speculative();
-  }
-
-  // Same as above: because we don't go through meet/join, remove the
-  // speculative type if we know we won't use it.
-  return result->cleanup_speculative();
-
-  // JOIN NOT DONE HERE BECAUSE OF INTERFACE ISSUES.
-  // FIX THIS (DO THE JOIN) WHEN UNION TYPES APPEAR!
-
-  //
-  // Remove this code after overnight run indicates no performance
-  // loss from not performing JOIN at CheckCastPPNode
-  //
-  // const TypeInstPtr *in_oop = in->isa_instptr();
-  // const TypeInstPtr *my_oop = _type->isa_instptr();
-  // // If either input is an 'interface', return destination type
-  // assert (in_oop == NULL || in_oop->klass() != NULL, "");
-  // assert (my_oop == NULL || my_oop->klass() != NULL, "");
-  // if( (in_oop && in_oop->klass()->is_interface())
-  //   ||(my_oop && my_oop->klass()->is_interface()) ) {
-  //   TypePtr::PTR  in_ptr = in->isa_ptr() ? in->is_ptr()->_ptr : TypePtr::BotPTR;
-  //   // Preserve cast away nullness for interfaces
-  //   if( in_ptr == TypePtr::NotNull && my_oop && my_oop->_ptr == TypePtr::BotPTR ) {
-  //     return my_oop->cast_to_ptr_type(TypePtr::NotNull);
-  //   }
-  //   return _type;
-  // }
-  //
-  // // Neither the input nor the destination type is an interface,
-  //
-  // // history: JOIN used to cause weird corner case bugs
-  // //          return (in == TypeOopPtr::NULL_PTR) ? in : _type;
-  // // JOIN picks up NotNull in common instance-of/check-cast idioms, both oops.
-  // // JOIN does not preserve NotNull in other cases, e.g. RawPtr vs InstPtr
-  // const Type *join = in->join(_type);
-  // // Check if join preserved NotNull'ness for pointers
-  // if( join->isa_ptr() && _type->isa_ptr() ) {
-  //   TypePtr::PTR join_ptr = join->is_ptr()->_ptr;
-  //   TypePtr::PTR type_ptr = _type->is_ptr()->_ptr;
-  //   // If there isn't any NotNull'ness to preserve
-  //   // OR if join preserved NotNull'ness then return it
-  //   if( type_ptr == TypePtr::BotPTR  || type_ptr == TypePtr::Null ||
-  //       join_ptr == TypePtr::NotNull || join_ptr == TypePtr::Constant ) {
-  //     return join;
-  //   }
-  //   // ELSE return same old type as before
-  //   return _type;
-  // }
-  // // Not joining two pointers
-  // return join;
+  return result;
 }
 
 //=============================================================================
diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp
index 62e111e4632..ef32af8bd31 100644
--- a/src/hotspot/share/opto/cfgnode.cpp
+++ b/src/hotspot/share/opto/cfgnode.cpp
@@ -1180,42 +1180,12 @@ const Type* PhiNode::Value(PhaseGVN* phase) const {
     }
   }
 
-  // Until we have harmony between classes and interfaces in the type
-  // lattice, we must tread carefully around phis which implicitly
-  // convert the one to the other.
-  const TypePtr* ttp = _type->make_ptr();
-  const TypeInstPtr* ttip = (ttp != NULL) ? ttp->isa_instptr() : NULL;
-  const TypeInstKlassPtr* ttkp = (ttp != NULL) ? ttp->isa_instklassptr() : NULL;
-  bool is_intf = false;
-  if (ttip != NULL) {
-    if (ttip->is_interface())
-      is_intf = true;
-  }
-  if (ttkp != NULL) {
-    if (ttkp->is_interface())
-      is_intf = true;
-  }
-
   // Default case: merge all inputs
   const Type *t = Type::TOP;        // Merged type starting value
   for (uint i = 1; i < req(); ++i) {// For all paths in
     // Reachable control path?
     if (r->in(i) && phase->type(r->in(i)) == Type::CONTROL) {
       const Type* ti = phase->type(in(i));
-      // We assume that each input of an interface-valued Phi is a true
-      // subtype of that interface.  This might not be true of the meet
-      // of all the input types.  The lattice is not distributive in
-      // such cases.  Ward off asserts in type.cpp by refusing to do
-      // meets between interfaces and proper classes.
-      const TypePtr* tip = ti->make_ptr();
-      const TypeInstPtr* tiip = (tip != NULL) ? tip->isa_instptr() : NULL;
-      if (tiip) {
-        bool ti_is_intf = false;
-        if (tiip->is_interface())
-          ti_is_intf = true;
-        if (is_intf != ti_is_intf)
-          { t = _type; break; }
-      }
       t = t->meet_speculative(ti);
     }
   }
@@ -1239,60 +1209,13 @@ const Type* PhiNode::Value(PhaseGVN* phase) const {
   // The following logic has been moved into TypeOopPtr::filter.
   const Type* jt = t->join_speculative(_type);
   if (jt->empty()) {           // Emptied out???
-
-    // Check for evil case of 't' being a class and '_type' expecting an
-    // interface.  This can happen because the bytecodes do not contain
-    // enough type info to distinguish a Java-level interface variable
-    // from a Java-level object variable.  If we meet 2 classes which
-    // both implement interface I, but their meet is at 'j/l/O' which
-    // doesn't implement I, we have no way to tell if the result should
-    // be 'I' or 'j/l/O'.  Thus we'll pick 'j/l/O'.  If this then flows
-    // into a Phi which "knows" it's an Interface type we'll have to
-    // uplift the type.
-    if (!t->empty() && ttip && ttip->is_interface()) {
-      assert(ft == _type, ""); // Uplift to interface
-    } else if (!t->empty() && ttkp && ttkp->is_interface()) {
-      assert(ft == _type, ""); // Uplift to interface
-    } else {
-      // We also have to handle 'evil cases' of interface- vs. class-arrays
-      Type::get_arrays_base_elements(jt, _type, NULL, &ttip);
-      if (!t->empty() && ttip != NULL && ttip->is_interface()) {
-          assert(ft == _type, "");   // Uplift to array of interface
-      } else {
-        // Otherwise it's something stupid like non-overlapping int ranges
-        // found on dying counted loops.
-        assert(ft == Type::TOP, ""); // Canonical empty value
-      }
-    }
+    // Otherwise it's something stupid like non-overlapping int ranges
+    // found on dying counted loops.
+    assert(ft == Type::TOP, ""); // Canonical empty value
   }
 
   else {
 
-    // If we have an interface-typed Phi and we narrow to a class type, the join
-    // should report back the class.  However, if we have a J/L/Object
-    // class-typed Phi and an interface flows in, it's possible that the meet &
-    // join report an interface back out.  This isn't possible but happens
-    // because the type system doesn't interact well with interfaces.
-    const TypePtr *jtp = jt->make_ptr();
-    const TypeInstPtr *jtip = (jtp != NULL) ? jtp->isa_instptr() : NULL;
-    const TypeInstKlassPtr *jtkp = (jtp != NULL) ? jtp->isa_instklassptr() : NULL;
-    if (jtip && ttip) {
-      if (jtip->is_interface() &&
-          !ttip->is_interface()) {
-        assert(ft == ttip->cast_to_ptr_type(jtip->ptr()) ||
-               ft->isa_narrowoop() && ft->make_ptr() == ttip->cast_to_ptr_type(jtip->ptr()), "");
-        jt = ft;
-      }
-    }
-    if (jtkp && ttkp) {
-      if (jtkp->is_interface() &&
-          !jtkp->klass_is_exact() && // Keep exact interface klass (6894807)
-          ttkp->is_loaded() && !ttkp->is_interface()) {
-        assert(ft == ttkp->cast_to_ptr_type(jtkp->ptr()) ||
-               ft->isa_narrowklass() && ft->make_ptr() == ttkp->cast_to_ptr_type(jtkp->ptr()), "");
-        jt = ft;
-      }
-    }
     if (jt != ft && jt->base() == ft->base()) {
       if (jt->isa_int() &&
           jt->is_int()->_lo == ft->is_int()->_lo &&
diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp
index 278a0fc0f15..6cff45fcff9 100644
--- a/src/hotspot/share/opto/doCall.cpp
+++ b/src/hotspot/share/opto/doCall.cpp
@@ -597,7 +597,7 @@ void Parse::do_call() {
 
   if (receiver_constraint != NULL) {
     Node* receiver_node = stack(sp() - nargs);
-    Node* cls_node = makecon(TypeKlassPtr::make(receiver_constraint));
+    Node* cls_node = makecon(TypeKlassPtr::make(receiver_constraint, Type::trust_interfaces));
     Node* bad_type_ctrl = NULL;
     Node* casted_receiver = gen_checkcast(receiver_node, cls_node, &bad_type_ctrl);
     if (bad_type_ctrl != NULL) {
diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp
index 984533fe9f8..7859d9e5fd7 100644
--- a/src/hotspot/share/opto/graphKit.cpp
+++ b/src/hotspot/share/opto/graphKit.cpp
@@ -2182,7 +2182,7 @@ Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls, Prof
 
   // Should the klass from the profile be recorded in the speculative type?
   if (current_type->would_improve_type(exact_kls, jvms()->depth())) {
-    const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls);
+    const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls, Type::trust_interfaces);
     const TypeOopPtr* xtype = tklass->as_instance_type();
     assert(xtype->klass_is_exact(), "Should be exact");
     // Any reason to believe n is not null (from this profiling or a previous one)?
@@ -2636,7 +2636,7 @@ static IfNode* gen_subtype_check_compare(Node* ctrl, Node* in1, Node* in2, BoolT
   case T_ADDRESS: cmp = new CmpPNode(in1, in2); break;
   default: fatal("unexpected comparison type %s", type2name(bt));
   }
-  gvn.transform(cmp);
+  cmp = gvn.transform(cmp);
   Node* bol = gvn.transform(new BoolNode(cmp, test));
   IfNode* iff = new IfNode(ctrl, bol, p, COUNT_UNKNOWN);
   gvn.transform(iff);
@@ -2844,7 +2844,7 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass,
                                     Node* *casted_receiver) {
   assert(!klass->is_interface(), "no exact type check on interfaces");
 
-  const TypeKlassPtr* tklass = TypeKlassPtr::make(klass);
+  const TypeKlassPtr* tklass = TypeKlassPtr::make(klass, Type::trust_interfaces);
   Node* recv_klass = load_object_klass(receiver);
   Node* want_klass = makecon(tklass);
   Node* cmp = _gvn.transform(new CmpPNode(recv_klass, want_klass));
@@ -2873,7 +2873,7 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass,
 //------------------------------subtype_check_receiver-------------------------
 Node* GraphKit::subtype_check_receiver(Node* receiver, ciKlass* klass,
                                        Node** casted_receiver) {
-  const TypeKlassPtr* tklass = TypeKlassPtr::make(klass);
+  const TypeKlassPtr* tklass = TypeKlassPtr::make(klass, Type::trust_interfaces)->try_improve();
   Node* want_klass = makecon(tklass);
 
   Node* slow_ctl = gen_subtype_check(receiver, want_klass);
@@ -2996,7 +2996,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
   ciKlass* exact_kls = spec_klass == NULL ? profile_has_unique_klass() : spec_klass;
   if (exact_kls != NULL) {// no cast failures here
     if (require_klass == NULL ||
-        C->static_subtype_check(require_klass, TypeKlassPtr::make(exact_kls)) == Compile::SSC_always_true) {
+        C->static_subtype_check(require_klass, TypeKlassPtr::make(exact_kls, Type::trust_interfaces)) == Compile::SSC_always_true) {
       // If we narrow the type to match what the type profile sees or
       // the speculative type, we can then remove the rest of the
       // cast.
@@ -3182,8 +3182,8 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac
 Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
                               Node* *failure_control) {
   kill_dead_locals();           // Benefit all the uncommon traps
-  const TypeKlassPtr *tk = _gvn.type(superklass)->is_klassptr();
-  const Type *toop = tk->cast_to_exactness(false)->as_instance_type();
+  const TypeKlassPtr *tk = _gvn.type(superklass)->is_klassptr()->try_improve();
+  const TypeOopPtr *toop = tk->cast_to_exactness(false)->as_instance_type();
 
   // Fast cutout:  Check the case that the cast is vacuously true.
   // This detects the common cases where the test will short-circuit
diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp
index 17fe8f6b729..60047442961 100644
--- a/src/hotspot/share/opto/idealGraphPrinter.cpp
+++ b/src/hotspot/share/opto/idealGraphPrinter.cpp
@@ -500,9 +500,7 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) {
     if (t != NULL && (t->isa_instptr() || t->isa_instklassptr())) {
       const TypeInstPtr  *toop = t->isa_instptr();
       const TypeInstKlassPtr *tkls = t->isa_instklassptr();
-      if ((toop != NULL && toop->is_interface()) || (tkls != NULL && tkls->is_interface())) {
-        s2.print("  Interface:");
-      } else if (toop) {
+      if (toop) {
         s2.print("  Oop:");
       } else if (tkls) {
         s2.print("  Klass:");
diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp
index d54dc4e79e2..2bba12a05e6 100644
--- a/src/hotspot/share/opto/library_call.cpp
+++ b/src/hotspot/share/opto/library_call.cpp
@@ -3659,7 +3659,7 @@ bool LibraryCallKit::inline_Class_cast() {
       // Don't use intrinsic when class is not loaded.
       return false;
     } else {
-      int static_res = C->static_subtype_check(TypeKlassPtr::make(tm->as_klass()), tp->as_klass_type());
+      int static_res = C->static_subtype_check(TypeKlassPtr::make(tm->as_klass(), Type::trust_interfaces), tp->as_klass_type());
       if (static_res == Compile::SSC_always_true) {
         // isInstance() is true - fold the code.
         set_result(obj);
@@ -7161,7 +7161,7 @@ bool LibraryCallKit::inline_digestBase_implCompressMB(Node* digestBase_obj, ciIn
                                                       BasicType elem_type, address stubAddr, const char *stubName,
                                                       Node* src_start, Node* ofs, Node* limit) {
   const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_digestBase);
-  const TypeOopPtr* xtype = aklass->as_instance_type()->cast_to_ptr_type(TypePtr::NotNull);
+  const TypeOopPtr* xtype = aklass->cast_to_exactness(false)->as_instance_type()->cast_to_ptr_type(TypePtr::NotNull);
   Node* digest_obj = new CheckCastPPNode(control(), digestBase_obj, xtype);
   digest_obj = _gvn.transform(digest_obj);
 
diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp
index c68de55cb49..6d4ea188f1b 100644
--- a/src/hotspot/share/opto/memnode.cpp
+++ b/src/hotspot/share/opto/memnode.cpp
@@ -2032,7 +2032,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const {
         // (Folds up type checking code.)
         assert(Opcode() == Op_LoadKlass, "must load a klass from _primary_supers");
         ciKlass *ss = klass->super_of_depth(depth);
-        return ss ? TypeKlassPtr::make(ss) : TypePtr::NULL_PTR;
+        return ss ? TypeKlassPtr::make(ss, Type::trust_interfaces) : TypePtr::NULL_PTR;
       }
       const Type* aift = load_array_final_field(tkls, klass);
       if (aift != NULL)  return aift;
@@ -2063,7 +2063,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const {
           // (Folds up type checking code.)
           assert(Opcode() == Op_LoadKlass, "must load a klass from _primary_supers");
           ciKlass *ss = klass->super_of_depth(depth);
-          return ss ? TypeKlassPtr::make(ss) : TypePtr::NULL_PTR;
+          return ss ? TypeKlassPtr::make(ss, Type::trust_interfaces) : TypePtr::NULL_PTR;
         }
       }
     }
@@ -2323,14 +2323,14 @@ const Type* LoadNode::klass_value_common(PhaseGVN* phase) const {
             // klass.  Users of this result need to do a null check on the returned klass.
             return TypePtr::NULL_PTR;
           }
-          return TypeKlassPtr::make(ciArrayKlass::make(t));
+          return TypeKlassPtr::make(ciArrayKlass::make(t), Type::trust_interfaces);
         }
         if (!t->is_klass()) {
           // a primitive Class (e.g., int.class) has NULL for a klass field
           return TypePtr::NULL_PTR;
         }
         // (Folds up the 1st indirection in aClassConstant.getModifiers().)
-        return TypeKlassPtr::make(t->as_klass());
+        return TypeKlassPtr::make(t->as_klass(), Type::trust_interfaces);
       }
       // non-constant mirror, so we can't tell what's going on
     }
@@ -2368,7 +2368,7 @@ const Type* LoadNode::klass_value_common(PhaseGVN* phase) const {
       ciKlass* sup = tkls->is_instklassptr()->instance_klass()->super();
       // The field is Klass::_super.  Return its (constant) value.
       // (Folds up the 2nd indirection in aClassConstant.getSuperClass().)
-      return sup ? TypeKlassPtr::make(sup) : TypePtr::NULL_PTR;
+      return sup ? TypeKlassPtr::make(sup, Type::trust_interfaces) : TypePtr::NULL_PTR;
     }
   }
 
diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp
index 4790d1b010d..59e9d8fcbc9 100644
--- a/src/hotspot/share/opto/node.cpp
+++ b/src/hotspot/share/opto/node.cpp
@@ -2554,10 +2554,7 @@ void Node::dump(const char* suffix, bool mark, outputStream* st, DumpConfig* dc)
   if (t != NULL && (t->isa_instptr() || t->isa_instklassptr())) {
     const TypeInstPtr  *toop = t->isa_instptr();
     const TypeInstKlassPtr *tkls = t->isa_instklassptr();
-    ciKlass*           klass = toop ? toop->instance_klass() : (tkls ? tkls->instance_klass() : NULL );
-    if (klass && klass->is_loaded() && ((toop && toop->is_interface()) || (tkls && tkls->is_interface()))) {
-      st->print("  Interface:");
-    } else if (toop) {
+    if (toop) {
       st->print("  Oop:");
     } else if (tkls) {
       st->print("  Klass:");
diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp
index e885c766b26..790a83554ba 100644
--- a/src/hotspot/share/opto/parse1.cpp
+++ b/src/hotspot/share/opto/parse1.cpp
@@ -1199,7 +1199,7 @@ void Parse::do_method_entry() {
   // Narrow receiver type when it is too broad for the method being parsed.
   if (!method()->is_static()) {
     ciInstanceKlass* callee_holder = method()->holder();
-    const Type* holder_type = TypeInstPtr::make(TypePtr::BotPTR, callee_holder);
+    const Type* holder_type = TypeInstPtr::make(TypePtr::BotPTR, callee_holder, Type::trust_interfaces);
 
     Node* receiver_obj = local(0);
     const TypeInstPtr* receiver_type = _gvn.type(receiver_obj)->isa_instptr();
@@ -1212,7 +1212,7 @@ void Parse::do_method_entry() {
       assert(callee_holder->is_interface(), "missing subtype check");
 
       // Perform dynamic receiver subtype check against callee holder class w/ a halt on failure.
-      Node* holder_klass = _gvn.makecon(TypeKlassPtr::make(callee_holder));
+      Node* holder_klass = _gvn.makecon(TypeKlassPtr::make(callee_holder, Type::trust_interfaces));
       Node* not_subtype_ctrl = gen_subtype_check(receiver_obj, holder_klass);
       assert(!stopped(), "not a subtype");
 
@@ -2132,7 +2132,7 @@ void Parse::clinit_deopt() {
 
   set_parse_bci(0);
 
-  Node* holder = makecon(TypeKlassPtr::make(method()->holder()));
+  Node* holder = makecon(TypeKlassPtr::make(method()->holder(), Type::trust_interfaces));
   guard_klass_being_initialized(holder);
 }
 
@@ -2211,27 +2211,6 @@ void Parse::return_current(Node* value) {
     // cast from oop to interface allowed by the Verifier.  Make it explicit
     // here.
     Node* phi = _exits.argument(0);
-    const TypeInstPtr *tr = phi->bottom_type()->isa_instptr();
-    if (tr && tr->is_loaded() &&
-        tr->is_interface()) {
-      const TypeInstPtr *tp = value->bottom_type()->isa_instptr();
-      if (tp && tp->is_loaded() &&
-          !tp->is_interface()) {
-        // sharpen the type eagerly; this eases certain assert checking
-        if (tp->higher_equal(TypeInstPtr::NOTNULL))
-          tr = tr->join_speculative(TypeInstPtr::NOTNULL)->is_instptr();
-        value = _gvn.transform(new CheckCastPPNode(0, value, tr));
-      }
-    } else {
-      // Also handle returns of oop-arrays to an arrays-of-interface return
-      const TypeInstPtr* phi_tip;
-      const TypeInstPtr* val_tip;
-      Type::get_arrays_base_elements(phi->bottom_type(), value->bottom_type(), &phi_tip, &val_tip);
-      if (phi_tip != NULL && phi_tip->is_loaded() && phi_tip->is_interface() &&
-          val_tip != NULL && val_tip->is_loaded() && !val_tip->is_interface()) {
-        value = _gvn.transform(new CheckCastPPNode(0, value, phi->bottom_type()));
-      }
-    }
     phi->add_req(value);
   }
 
diff --git a/src/hotspot/share/opto/parse3.cpp b/src/hotspot/share/opto/parse3.cpp
index a6c1b73ec05..1f8f476ba48 100644
--- a/src/hotspot/share/opto/parse3.cpp
+++ b/src/hotspot/share/opto/parse3.cpp
@@ -277,7 +277,7 @@ void Parse::do_anewarray() {
 
   kill_dead_locals();
 
-  const TypeKlassPtr* array_klass_type = TypeKlassPtr::make(array_klass);
+  const TypeKlassPtr* array_klass_type = TypeKlassPtr::make(array_klass, Type::trust_interfaces);
   Node* count_val = pop();
   Node* obj = new_array(makecon(array_klass_type), count_val, 1);
   push(obj);
@@ -299,7 +299,7 @@ void Parse::do_newarray(BasicType elem_type) {
 Node* Parse::expand_multianewarray(ciArrayKlass* array_klass, Node* *lengths, int ndimensions, int nargs) {
   Node* length = lengths[0];
   assert(length != NULL, "");
-  Node* array = new_array(makecon(TypeKlassPtr::make(array_klass)), length, nargs);
+  Node* array = new_array(makecon(TypeKlassPtr::make(array_klass, Type::trust_interfaces)), length, nargs);
   if (ndimensions > 1) {
     jint length_con = find_int_con(length, -1);
     guarantee(length_con >= 0, "non-constant multianewarray");
@@ -385,7 +385,7 @@ void Parse::do_multianewarray() {
     c = make_runtime_call(RC_NO_LEAF | RC_NO_IO,
                           OptoRuntime::multianewarray_Type(ndimensions),
                           fun, NULL, TypeRawPtr::BOTTOM,
-                          makecon(TypeKlassPtr::make(array_klass)),
+                          makecon(TypeKlassPtr::make(array_klass, Type::trust_interfaces)),
                           length[0], length[1], length[2],
                           (ndimensions > 2) ? length[3] : NULL,
                           (ndimensions > 3) ? length[4] : NULL);
@@ -407,14 +407,14 @@ void Parse::do_multianewarray() {
     c = make_runtime_call(RC_NO_LEAF | RC_NO_IO,
                           OptoRuntime::multianewarrayN_Type(),
                           OptoRuntime::multianewarrayN_Java(), NULL, TypeRawPtr::BOTTOM,
-                          makecon(TypeKlassPtr::make(array_klass)),
+                          makecon(TypeKlassPtr::make(array_klass, Type::trust_interfaces)),
                           dims);
   }
   make_slow_call_ex(c, env()->Throwable_klass(), false);
 
   Node* res = _gvn.transform(new ProjNode(c, TypeFunc::Parms));
 
-  const Type* type = TypeOopPtr::make_from_klass_raw(array_klass);
+  const Type* type = TypeOopPtr::make_from_klass_raw(array_klass, Type::trust_interfaces);
 
   // Improve the type:  We know it's not null, exact, and of a given length.
   type = type->is_ptr()->cast_to_ptr_type(TypePtr::NotNull);
diff --git a/src/hotspot/share/opto/parseHelper.cpp b/src/hotspot/share/opto/parseHelper.cpp
index 199ffeae761..19619595c74 100644
--- a/src/hotspot/share/opto/parseHelper.cpp
+++ b/src/hotspot/share/opto/parseHelper.cpp
@@ -90,7 +90,7 @@ void Parse::do_checkcast() {
     return;
   }
 
-  Node* res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass)));
+  Node* res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass, Type::trust_interfaces)));
   if (stopped()) {
     return;
   }
@@ -129,7 +129,7 @@ void Parse::do_instanceof() {
   }
 
   // Push the bool result back on stack
-  Node* res = gen_instanceof(peek(), makecon(TypeKlassPtr::make(klass)), true);
+  Node* res = gen_instanceof(peek(), makecon(TypeKlassPtr::make(klass, Type::trust_interfaces)), true);
 
   // Pop from stack AFTER gen_instanceof because it can uncommon trap.
   pop();
diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp
index 570f5828f23..e08c0f24225 100644
--- a/src/hotspot/share/opto/subnode.cpp
+++ b/src/hotspot/share/opto/subnode.cpp
@@ -1047,7 +1047,7 @@ static inline Node* isa_const_java_mirror(PhaseGVN* phase, Node* n) {
 
   // return the ConP(Foo.klass)
   assert(mirror_type->is_klass(), "mirror_type should represent a Klass*");
-  return phase->makecon(TypeKlassPtr::make(mirror_type->as_klass()));
+  return phase->makecon(TypeKlassPtr::make(mirror_type->as_klass(), Type::trust_interfaces));
 }
 
 //------------------------------Ideal------------------------------------------
diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp
index 825274dbb90..a4ed2b332f9 100644
--- a/src/hotspot/share/opto/type.cpp
+++ b/src/hotspot/share/opto/type.cpp
@@ -120,6 +120,8 @@ const Type* Type::            _zero_type[T_CONFLICT+1];
 
 // Map basic types to array-body alias types.
 const TypeAryPtr* TypeAryPtr::_array_body_type[T_CONFLICT+1];
+const TypePtr::InterfaceSet* TypeAryPtr::_array_interfaces = NULL;
+const TypePtr::InterfaceSet* TypeAryKlassPtr::_array_interfaces = NULL;
 
 //=============================================================================
 // Convenience common pre-built types.
@@ -134,13 +136,13 @@ const Type *Type::RETURN_ADDRESS;
 const Type *Type::TOP;          // No values in set
 
 //------------------------------get_const_type---------------------------
-const Type* Type::get_const_type(ciType* type) {
+const Type* Type::get_const_type(ciType* type, InterfaceHandling interface_handling) {
   if (type == NULL) {
     return NULL;
   } else if (type->is_primitive_type()) {
     return get_const_basic_type(type->basic_type());
   } else {
-    return TypeOopPtr::make_from_klass(type->as_klass());
+    return TypeOopPtr::make_from_klass(type->as_klass(), interface_handling);
   }
 }
 
@@ -566,6 +568,12 @@ void Type::Initialize_shared(Compile* current) {
   mreg2type[Op_RegL] = TypeLong::LONG;
   mreg2type[Op_RegFlags] = TypeInt::CC;
 
+  GrowableArray<ciInstanceKlass*> array_interfaces;
+  array_interfaces.push(current->env()->Cloneable_klass());
+  array_interfaces.push(current->env()->Serializable_klass());
+  TypeAryPtr::_array_interfaces = new TypePtr::InterfaceSet(&array_interfaces);
+  TypeAryKlassPtr::_array_interfaces = TypeAryPtr::_array_interfaces;
+
   TypeAryPtr::RANGE   = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), NULL /* current->env()->Object_klass() */, false, arrayOopDesc::length_offset_in_bytes());
 
   TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), NULL /*ciArrayKlass::make(o)*/,  false,  Type::OffsetBot);
@@ -778,51 +786,6 @@ bool Type::is_nan()    const {
   return false;
 }
 
-//----------------------interface_vs_oop---------------------------------------
-#ifdef ASSERT
-bool Type::interface_vs_oop_helper(const Type *t) const {
-  bool result = false;
-
-  const TypePtr* this_ptr = this->make_ptr(); // In case it is narrow_oop
-  const TypePtr*    t_ptr =    t->make_ptr();
-  if( this_ptr == NULL || t_ptr == NULL )
-    return result;
-
-  const TypeInstPtr* this_inst = this_ptr->isa_instptr();
-  const TypeInstPtr*    t_inst =    t_ptr->isa_instptr();
-  if( this_inst && this_inst->is_loaded() && t_inst && t_inst->is_loaded() ) {
-    bool this_interface = this_inst->is_interface();
-    bool    t_interface =    t_inst->is_interface();
-    result = this_interface ^ t_interface;
-  }
-
-  return result;
-}
-
-bool Type::interface_vs_oop(const Type *t) const {
-  if (interface_vs_oop_helper(t)) {
-    return true;
-  }
-  // Now check the speculative parts as well
-  const TypePtr* this_spec = isa_ptr() != NULL ? is_ptr()->speculative() : NULL;
-  const TypePtr* t_spec = t->isa_ptr() != NULL ? t->is_ptr()->speculative() : NULL;
-  if (this_spec != NULL && t_spec != NULL) {
-    if (this_spec->interface_vs_oop_helper(t_spec)) {
-      return true;
-    }
-    return false;
-  }
-  if (this_spec != NULL && this_spec->interface_vs_oop_helper(t)) {
-    return true;
-  }
-  if (t_spec != NULL && interface_vs_oop_helper(t_spec)) {
-    return true;
-  }
-  return false;
-}
-
-#endif
-
 void Type::check_symmetrical(const Type* t, const Type* mt) const {
 #ifdef ASSERT
   const Type* mt2 = t->xmeet(this);
@@ -842,7 +805,7 @@ void Type::check_symmetrical(const Type* t, const Type* mt) const {
   // Interface:AnyNull meet Oop:AnyNull == Interface:AnyNull
   // Interface:NotNull meet Oop:NotNull == java/lang/Object:NotNull
 
-  if (!interface_vs_oop(t) && (t2t != t->_dual || t2this != this->_dual)) {
+  if (t2t != t->_dual || t2this != this->_dual) {
     tty->print_cr("=== Meet Not Symmetric ===");
     tty->print("t   =                   ");              t->dump(); tty->cr();
     tty->print("this=                   ");                 dump(); tty->cr();
@@ -2020,7 +1983,7 @@ const TypeTuple *TypeTuple::LONG_CC_PAIR;
 
 //------------------------------make-------------------------------------------
 // Make a TypeTuple from the range of a method signature
-const TypeTuple *TypeTuple::make_range(ciSignature* sig) {
+const TypeTuple *TypeTuple::make_range(ciSignature* sig, InterfaceHandling interface_handling) {
   ciType* return_type = sig->return_type();
   uint arg_cnt = return_type->size();
   const Type **field_array = fields(arg_cnt);
@@ -2041,7 +2004,7 @@ const TypeTuple *TypeTuple::make_range(ciSignature* sig) {
   case T_BYTE:
   case T_SHORT:
   case T_INT:
-    field_array[TypeFunc::Parms] = get_const_type(return_type);
+    field_array[TypeFunc::Parms] = get_const_type(return_type, interface_handling);
     break;
   case T_VOID:
     break;
@@ -2052,7 +2015,7 @@ const TypeTuple *TypeTuple::make_range(ciSignature* sig) {
 }
 
 // Make a TypeTuple from the domain of a method signature
-const TypeTuple *TypeTuple::make_domain(ciInstanceKlass* recv, ciSignature* sig) {
+const TypeTuple *TypeTuple::make_domain(ciInstanceKlass* recv, ciSignature* sig, InterfaceHandling interface_handling) {
   uint arg_cnt = sig->size();
 
   uint pos = TypeFunc::Parms;
@@ -2061,7 +2024,7 @@ const TypeTuple *TypeTuple::make_domain(ciInstanceKlass* recv, ciSignature* sig)
     arg_cnt++;
     field_array = fields(arg_cnt);
     // Use get_const_type here because it respects UseUniqueSubclasses:
-    field_array[pos++] = get_const_type(recv)->join_speculative(TypePtr::NOTNULL);
+    field_array[pos++] = get_const_type(recv, interface_handling)->join_speculative(TypePtr::NOTNULL);
   } else {
     field_array = fields(arg_cnt);
   }
@@ -2083,7 +2046,7 @@ const TypeTuple *TypeTuple::make_domain(ciInstanceKlass* recv, ciSignature* sig)
     case T_ARRAY:
     case T_FLOAT:
     case T_INT:
-      field_array[pos++] = get_const_type(type);
+      field_array[pos++] = get_const_type(type, interface_handling);
       break;
     case T_BOOLEAN:
     case T_CHAR:
@@ -2314,21 +2277,6 @@ const TypePtr* TypePtr::with_inline_depth(int depth) const {
   return make(AnyPtr, _ptr, _offset, _speculative, depth);
 }
 
-//----------------------interface_vs_oop---------------------------------------
-#ifdef ASSERT
-bool TypeAry::interface_vs_oop(const Type *t) const {
-  const TypeAry* t_ary = t->is_ary();
-  if (t_ary) {
-    const TypePtr* this_ptr = _elem->make_ptr(); // In case we have narrow_oops
-    const TypePtr*    t_ptr = t_ary->_elem->make_ptr();
-    if(this_ptr != NULL && t_ptr != NULL) {
-      return this_ptr->interface_vs_oop(t_ptr);
-    }
-  }
-  return false;
-}
-#endif
-
 //------------------------------dump2------------------------------------------
 #ifndef PRODUCT
 void TypeAry::dump2( Dict &d, uint depth, outputStream *st ) const {
@@ -3167,11 +3115,232 @@ void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
 // Convenience common pre-built type.
 const TypeOopPtr *TypeOopPtr::BOTTOM;
 
+TypePtr::InterfaceSet::InterfaceSet()
+        : _list(Compile::current()->type_arena(), 0, 0, NULL),
+          _hash_computed(0), _exact_klass_computed(0), _is_loaded_computed(0) {
+}
+
+TypePtr::InterfaceSet::InterfaceSet(GrowableArray<ciInstanceKlass*>* interfaces)
+        : _list(Compile::current()->type_arena(), interfaces->length(), 0, NULL),
+          _hash_computed(0), _exact_klass_computed(0), _is_loaded_computed(0) {
+  for (int i = 0; i < interfaces->length(); i++) {
+    add(interfaces->at(i));
+  }
+}
+
+
+int TypePtr::InterfaceSet::compare(ciKlass* const& k1, ciKlass* const& k2) {
+  if ((intptr_t)k1 < (intptr_t)k2) {
+    return -1;
+  } else if ((intptr_t)k1 > (intptr_t)k2) {
+    return 1;
+  }
+  return 0;
+}
+
+void TypePtr::InterfaceSet::add(ciKlass* interface) {
+  assert(interface->is_interface(), "for interfaces only");
+  _list.insert_sorted<compare>(interface);
+  verify();
+}
+
+void TypePtr::InterfaceSet::raw_add(ciKlass* interface) {
+  assert(interface->is_interface(), "for interfaces only");
+  _list.push(interface);
+}
+
+bool TypePtr::InterfaceSet::eq(const InterfaceSet& other) const {
+  if (_list.length() != other._list.length()) {
+    return false;
+  }
+  for (int i = 0; i < _list.length(); i++) {
+    ciKlass* k1 = _list.at(i);
+    ciKlass* k2 = other._list.at(i);
+    if (!k1->equals(k2)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+int TypePtr::InterfaceSet::hash() const {
+  if (_hash_computed) {
+    return _hash;
+  }
+  const_cast<InterfaceSet*>(this)->compute_hash();
+  assert(_hash_computed, "should be computed now");
+  return _hash;
+}
+
+void TypePtr::InterfaceSet::compute_hash() {
+  int hash = 0;
+  for (int i = 0; i < _list.length(); i++) {
+    ciKlass* k = _list.at(i);
+    hash += (jint)k->hash();
+  }
+  _hash_computed = 1;
+  _hash = hash;
+}
+
+void TypePtr::InterfaceSet::dump(outputStream *st) const {
+  if (_list.length() == 0) {
+    return;
+  }
+  st->print(" (");
+  for (int i = 0; i < _list.length(); i++) {
+    if (i > 0) {
+      st->print(",");
+    }
+    ciKlass* k = _list.at(i);
+    k->print_name_on(st);
+  }
+  st->print(")");
+}
+
+void TypePtr::InterfaceSet::verify() const {
+#ifdef DEBUG
+  for (int i = 1; i < _list.length(); i++) {
+    ciKlass* k1 = _list.at(i-1);
+    ciKlass* k2 = _list.at(i);
+    assert(compare(k2, k1) > 0, "should be ordered");
+    assert(k1 != k2, "no duplicate");
+  }
+#endif
+}
+
+TypePtr::InterfaceSet TypeOopPtr::InterfaceSet::union_with(const InterfaceSet& other) const {
+  InterfaceSet result;
+  int i = 0;
+  int j = 0;
+  while (i < _list.length() || j < other._list.length()) {
+    while (i < _list.length() &&
+           (j >= other._list.length() ||
+            compare(_list.at(i), other._list.at(j)) < 0)) {
+      result.raw_add(_list.at(i));
+      i++;
+    }
+    while (j < other._list.length() &&
+           (i >= _list.length() ||
+            compare(other._list.at(j), _list.at(i)) < 0)) {
+      result.raw_add(other._list.at(j));
+      j++;
+    }
+    if (i < _list.length() &&
+        j < other._list.length() &&
+        _list.at(i) == other._list.at(j)) {
+      result.raw_add(_list.at(i));
+      i++;
+      j++;
+    }
+  }
+  result.verify();
+#ifdef DEBUG
+  for (int i = 0; i < _list.length(); i++) {
+    assert(result.contains(_list.at(i)), "missing");
+  }
+  for (int i = 0; i < other._list.length(); i++) {
+    assert(result.contains(other._list.at(i)), "missing");
+  }
+  for (int i = 0; i < result._list.length(); i++) {
+    assert(_list.contains(result._list.at(i)) || other._list.contains(result._list.at(i)), "missing");
+  }
+#endif
+  return result;
+}
+
+TypePtr::InterfaceSet TypeOopPtr::InterfaceSet::intersection_with(const InterfaceSet& other) const {
+  InterfaceSet result;
+  int i = 0;
+  int j = 0;
+  while (i < _list.length() || j < other._list.length()) {
+    while (i < _list.length() &&
+           (j >= other._list.length() ||
+            compare(_list.at(i), other._list.at(j)) < 0)) {
+      i++;
+    }
+    while (j < other._list.length() &&
+           (i >= _list.length() ||
+            compare(other._list.at(j), _list.at(i)) < 0)) {
+      j++;
+    }
+    if (i < _list.length() &&
+        j < other._list.length() &&
+        _list.at(i) == other._list.at(j)) {
+      result.raw_add(_list.at(i));
+      i++;
+      j++;
+    }
+  }
+  result.verify();
+#ifdef DEBUG
+  for (int i = 0; i < _list.length(); i++) {
+    assert(!other._list.contains(_list.at(i)) || result.contains(_list.at(i)), "missing");
+  }
+  for (int i = 0; i < other._list.length(); i++) {
+    assert(!_list.contains(other._list.at(i)) || result.contains(other._list.at(i)), "missing");
+  }
+  for (int i = 0; i < result._list.length(); i++) {
+    assert(_list.contains(result._list.at(i)) && other._list.contains(result._list.at(i)), "missing");
+  }
+#endif
+  return result;
+}
+
+// Is there a single ciKlass* that can represent the interface set?
+ciKlass* TypePtr::InterfaceSet::exact_klass() const {
+  if (_exact_klass_computed) {
+    return _exact_klass;
+  }
+  const_cast<InterfaceSet*>(this)->compute_exact_klass();
+  assert(_exact_klass_computed, "should be computed now");
+  return _exact_klass;
+}
+
+void TypePtr::InterfaceSet::compute_exact_klass() {
+  if (_list.length() == 0) {
+    _exact_klass_computed = 1;
+    _exact_klass = NULL;
+    return;
+  }
+  ciKlass* res = NULL;
+  for (int i = 0; i < _list.length(); i++) {
+    ciKlass* interface = _list.at(i);
+    if (eq(interfaces(interface, false, true, false, trust_interfaces))) {
+      assert(res == NULL, "");
+      res = _list.at(i);
+    }
+  }
+  _exact_klass_computed = 1;
+  _exact_klass = res;
+}
+
+bool TypePtr::InterfaceSet::is_loaded() const {
+  if (_is_loaded_computed) {
+    return _is_loaded;
+  }
+  const_cast<InterfaceSet*>(this)->compute_is_loaded();
+  assert(_is_loaded_computed, "should be computed now");
+  return _is_loaded;
+}
+
+void TypePtr::InterfaceSet::compute_is_loaded() {
+  _is_loaded_computed = 1;
+  for (int i = 0; i < _list.length(); i++) {
+    ciKlass* interface = _list.at(i);
+    if (!interface->is_loaded()) {
+      _is_loaded = false;
+      return;
+    }
+  }
+  _is_loaded = true;
+}
+
 //------------------------------TypeOopPtr-------------------------------------
-TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset,
+TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset,
                        int instance_id, const TypePtr* speculative, int inline_depth)
   : TypePtr(t, ptr, offset, speculative, inline_depth),
     _const_oop(o), _klass(k),
+    _interfaces(interfaces),
     _klass_is_exact(xk),
     _is_ptr_to_narrowoop(false),
     _is_ptr_to_narrowklass(false),
@@ -3219,7 +3388,7 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int o
           }
           if (field != NULL) {
             BasicType basic_elem_type = field->layout_type();
-            _is_ptr_to_narrowoop = UseCompressedOops && is_reference_type(basic_elem_type);
+            _is_ptr_to_narrowoop = UseCompressedOops && ::is_reference_type(basic_elem_type);
           } else {
             // unsafe access
             _is_ptr_to_narrowoop = UseCompressedOops;
@@ -3229,7 +3398,7 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int o
           field = ik->get_field_by_offset(_offset, false);
           if (field != NULL) {
             BasicType basic_elem_type = field->layout_type();
-            _is_ptr_to_narrowoop = UseCompressedOops && is_reference_type(basic_elem_type);
+            _is_ptr_to_narrowoop = UseCompressedOops && ::is_reference_type(basic_elem_type);
           } else if (klass()->equals(ciEnv::current()->Object_klass())) {
             // Compile::find_alias_type() cast exactness on all types to verify
             // that it does not affect alias type.
@@ -3252,7 +3421,7 @@ const TypeOopPtr *TypeOopPtr::make(PTR ptr, int offset, int instance_id,
   ciKlass*  k = Compile::current()->env()->Object_klass();
   bool      xk = false;
   ciObject* o = NULL;
-  return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, instance_id, speculative, inline_depth))->hashcons();
+  return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, InterfaceSet(), xk, o, offset, instance_id, speculative, inline_depth))->hashcons();
 }
 
 
@@ -3365,12 +3534,12 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
 const Type *TypeOopPtr::xdual() const {
   assert(klass() == Compile::current()->env()->Object_klass(), "no klasses here");
   assert(const_oop() == NULL,             "no constants here");
-  return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
+  return new TypeOopPtr(_base, dual_ptr(), klass(), _interfaces, klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
 }
 
 //--------------------------make_from_klass_common-----------------------------
 // Computes the element-type given a klass.
-const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_change, bool try_for_exact) {
+const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact, InterfaceHandling interface_handling) {
   if (klass->is_instance_klass()) {
     Compile* C = Compile::current();
     Dependencies* deps = C->dependencies();
@@ -3397,16 +3566,18 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_
         klass_is_exact = true;
       }
     }
-    return TypeInstPtr::make(TypePtr::BotPTR, klass, klass_is_exact, NULL, 0);
+    const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling);
+    return TypeInstPtr::make(TypePtr::BotPTR, klass, interfaces, klass_is_exact, NULL, 0);
   } else if (klass->is_obj_array_klass()) {
     // Element is an object array. Recursively call ourself.
-    const TypeOopPtr *etype = TypeOopPtr::make_from_klass_common(klass->as_obj_array_klass()->element_klass(), false, try_for_exact);
+    ciKlass* eklass = klass->as_obj_array_klass()->element_klass();
+    const TypeOopPtr *etype = TypeOopPtr::make_from_klass_common(eklass, try_for_exact, false, interface_handling);
     bool xk = etype->klass_is_exact();
     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
     // We used to pass NotNull in here, asserting that the sub-arrays
     // are all not-null.  This is not true in generally, as code can
     // slam NULLs down in the subarrays.
-    const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, xk, 0);
+    const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, NULL, xk, 0);
     return arr;
   } else if (klass->is_type_array_klass()) {
     // Element is an typeArray
@@ -3440,7 +3611,7 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const
   } else if (klass->is_obj_array_klass()) {
     // Element is an object array. Recursively call ourself.
     const TypeOopPtr *etype =
-      TypeOopPtr::make_from_klass_raw(klass->as_obj_array_klass()->element_klass());
+      TypeOopPtr::make_from_klass_raw(klass->as_obj_array_klass()->element_klass(), trust_interfaces);
     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
     // We used to pass NotNull in here, asserting that the sub-arrays
     // are all not-null.  This is not true in generally, as code can
@@ -3498,42 +3669,9 @@ const Type *TypeOopPtr::filter_helper(const Type *kills, bool include_speculativ
   const TypeInstPtr* ktip = kills->isa_instptr();
 
   if (ft->empty()) {
-    // Check for evil case of 'this' being a class and 'kills' expecting an
-    // interface.  This can happen because the bytecodes do not contain
-    // enough type info to distinguish a Java-level interface variable
-    // from a Java-level object variable.  If we meet 2 classes which
-    // both implement interface I, but their meet is at 'j/l/O' which
-    // doesn't implement I, we have no way to tell if the result should
-    // be 'I' or 'j/l/O'.  Thus we'll pick 'j/l/O'.  If this then flows
-    // into a Phi which "knows" it's an Interface type we'll have to
-    // uplift the type.
-    if (!empty()) {
-      if (ktip != NULL && ktip->is_loaded() && ktip->klass()->is_interface()) {
-        return kills;           // Uplift to interface
-      }
-      // Also check for evil cases of 'this' being a class array
-      // and 'kills' expecting an array of interfaces.
-      Type::get_arrays_base_elements(ft, kills, NULL, &ktip);
-      if (ktip != NULL && ktip->is_loaded() && ktip->klass()->is_interface()) {
-        return kills;           // Uplift to array of interface
-      }
-    }
-
     return Type::TOP;           // Canonical empty value
   }
 
-  // If we have an interface-typed Phi or cast and we narrow to a class type,
-  // the join should report back the class.  However, if we have a J/L/Object
-  // class-typed Phi and an interface flows in, it's possible that the meet &
-  // join report an interface back out.  This isn't possible but happens
-  // because the type system doesn't interact well with interfaces.
-  if (ftip != NULL && ktip != NULL &&
-      ftip->is_loaded() &&  ftip->klass()->is_interface() &&
-      ktip->is_loaded() && !ktip->klass()->is_interface()) {
-    assert(!ftip->klass_is_exact(), "interface could not be exact");
-    return ktip->cast_to_ptr_type(ftip->ptr());
-  }
-
   return ft;
 }
 
@@ -3592,7 +3730,7 @@ bool TypeOopPtr::singleton(void) const {
 }
 
 //------------------------------add_offset-------------------------------------
-const TypePtr *TypeOopPtr::add_offset(intptr_t offset) const {
+const TypePtr* TypeOopPtr::add_offset(intptr_t offset) const {
   return make(_ptr, xadd_offset(offset), _instance_id, add_offset_speculative(offset), _inline_depth);
 }
 
@@ -3659,6 +3797,18 @@ int TypeOopPtr::dual_instance_id( ) const {
   return _instance_id;              // Map everything else into self
 }
 
+
+TypePtr::InterfaceSet TypeOopPtr::meet_interfaces(const TypeOopPtr* other) const {
+  if (above_centerline(_ptr) && above_centerline(other->_ptr)) {
+    return _interfaces.union_with(other->_interfaces);
+  } else if (above_centerline(_ptr) && !above_centerline(other->_ptr)) {
+    return other->_interfaces;
+  } else if (above_centerline(other->_ptr) && !above_centerline(_ptr)) {
+    return _interfaces;
+  }
+  return _interfaces.intersection_with(other->_interfaces);
+}
+
 /**
  * Check whether new profiling would improve speculative type
  *
@@ -3683,22 +3833,36 @@ const TypeInstPtr *TypeInstPtr::MIRROR;
 const TypeInstPtr *TypeInstPtr::MARK;
 const TypeInstPtr *TypeInstPtr::KLASS;
 
+// Is there a single ciKlass* that can represent that type?
 ciKlass* TypeInstPtr::exact_klass_helper() const {
-  return _klass;
+  if (_interfaces.empty()) {
+    return _klass;
+  }
+  if (_klass != ciEnv::current()->Object_klass()) {
+    ciKlass* k = _klass;
+    const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
+    if (_interfaces.eq(interfaces)) {
+      return _klass;
+    }
+    return NULL;
+  }
+  return _interfaces.exact_klass();
 }
 
 //------------------------------TypeInstPtr-------------------------------------
-TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off,
+TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int off,
                          int instance_id, const TypePtr* speculative, int inline_depth)
-  : TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative, inline_depth) {
-   assert(k != NULL &&
-          (k->is_loaded() || o == NULL),
-          "cannot have constants with non-loaded klass");
+  : TypeOopPtr(InstPtr, ptr, k, interfaces, xk, o, off, instance_id, speculative, inline_depth) {
+  assert(k == NULL || !k->is_loaded() || !k->is_interface(), "no interface here");
+  assert(k != NULL &&
+         (k->is_loaded() || o == NULL),
+         "cannot have constants with non-loaded klass");
 };
 
 //------------------------------make-------------------------------------------
 const TypeInstPtr *TypeInstPtr::make(PTR ptr,
                                      ciKlass* k,
+                                     const InterfaceSet& interfaces,
                                      bool xk,
                                      ciObject* o,
                                      int offset,
@@ -3719,16 +3883,50 @@ const TypeInstPtr *TypeInstPtr::make(PTR ptr,
   } else if (k->is_loaded()) {
     ciInstanceKlass* ik = k->as_instance_klass();
     if (!xk && ik->is_final())     xk = true;   // no inexact final klass
+    assert(!ik->is_interface(), "no interface here");
     if (xk && ik->is_interface())  xk = false;  // no exact interface
   }
 
   // Now hash this baby
   TypeInstPtr *result =
-    (TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o ,offset, instance_id, speculative, inline_depth))->hashcons();
+    (TypeInstPtr*)(new TypeInstPtr(ptr, k, interfaces, xk, o ,offset, instance_id, speculative, inline_depth))->hashcons();
 
   return result;
 }
 
+TypePtr::InterfaceSet TypePtr::interfaces(ciKlass*& k, bool klass, bool interface, bool array, InterfaceHandling interface_handling) {
+  if (k->is_instance_klass()) {
+    if (k->is_loaded()) {
+      if (k->is_interface() && interface_handling == ignore_interfaces) {
+        assert(interface, "no interface expected");
+        k = ciEnv::current()->Object_klass();
+        InterfaceSet interfaces;
+        return interfaces;
+      }
+      GrowableArray<ciInstanceKlass *> *k_interfaces = k->as_instance_klass()->transitive_interfaces();
+      InterfaceSet interfaces(k_interfaces);
+      if (k->is_interface()) {
+        assert(interface, "no interface expected");
+        k = ciEnv::current()->Object_klass();
+      } else {
+        assert(klass, "no instance klass expected");
+      }
+      return interfaces;
+    }
+    InterfaceSet interfaces;
+    return interfaces;
+  }
+  assert(array, "no array expected");
+  assert(k->is_array_klass(), "Not an array?");
+  ciType* e = k->as_array_klass()->base_element_type();
+  if (e->is_loaded() && e->is_instance_klass() && e->as_instance_klass()->is_interface()) {
+    if (interface_handling == ignore_interfaces) {
+      k = ciObjArrayKlass::make(ciEnv::current()->Object_klass(), k->as_array_klass()->dimension());
+    }
+  }
+  return *TypeAryPtr::_array_interfaces;
+}
+
 /**
  *  Create constant type for a constant boxed value
  */
@@ -3757,7 +3955,7 @@ const TypeInstPtr* TypeInstPtr::cast_to_ptr_type(PTR ptr) const {
   if( ptr == _ptr ) return this;
   // Reconstruct _sig info here since not a problem with later lazy
   // construction, _sig will show up on demand.
-  return make(ptr, klass(), klass_is_exact(), ptr == Constant ? const_oop() : NULL, _offset, _instance_id, _speculative, _inline_depth);
+  return make(ptr, klass(), _interfaces, klass_is_exact(), ptr == Constant ? const_oop() : NULL, _offset, _instance_id, _speculative, _inline_depth);
 }
 
 
@@ -3767,62 +3965,62 @@ const TypeInstPtr* TypeInstPtr::cast_to_exactness(bool klass_is_exact) const {
   if (!_klass->is_loaded())  return this;
   ciInstanceKlass* ik = _klass->as_instance_klass();
   if( (ik->is_final() || _const_oop) )  return this;  // cannot clear xk
-  if( ik->is_interface() )              return this;  // cannot set xk
-  return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id, _speculative, _inline_depth);
+  assert(!ik->is_interface(), "no interface here");
+  return make(ptr(), klass(), _interfaces, klass_is_exact, const_oop(), _offset, _instance_id, _speculative, _inline_depth);
 }
 
 //-----------------------------cast_to_instance_id----------------------------
 const TypeInstPtr* TypeInstPtr::cast_to_instance_id(int instance_id) const {
   if( instance_id == _instance_id ) return this;
-  return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id, _speculative, _inline_depth);
+  return make(_ptr, klass(),  _interfaces, _klass_is_exact, const_oop(), _offset, instance_id, _speculative, _inline_depth);
 }
 
 //------------------------------xmeet_unloaded---------------------------------
 // Compute the MEET of two InstPtrs when at least one is unloaded.
 // Assume classes are different since called after check for same name/class-loader
-const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
-    int off = meet_offset(tinst->offset());
-    PTR ptr = meet_ptr(tinst->ptr());
-    int instance_id = meet_instance_id(tinst->instance_id());
-    const TypePtr* speculative = xmeet_speculative(tinst);
-    int depth = meet_inline_depth(tinst->inline_depth());
+const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst, const InterfaceSet& interfaces) const {
+  int off = meet_offset(tinst->offset());
+  PTR ptr = meet_ptr(tinst->ptr());
+  int instance_id = meet_instance_id(tinst->instance_id());
+  const TypePtr* speculative = xmeet_speculative(tinst);
+  int depth = meet_inline_depth(tinst->inline_depth());
 
-    const TypeInstPtr *loaded    = is_loaded() ? this  : tinst;
-    const TypeInstPtr *unloaded  = is_loaded() ? tinst : this;
-    if( loaded->klass()->equals(ciEnv::current()->Object_klass()) ) {
-      //
-      // Meet unloaded class with java/lang/Object
-      //
-      // Meet
-      //          |                     Unloaded Class
-      //  Object  |   TOP    |   AnyNull | Constant |   NotNull |  BOTTOM   |
-      //  ===================================================================
-      //   TOP    | ..........................Unloaded......................|
-      //  AnyNull |  U-AN    |................Unloaded......................|
-      // Constant | ... O-NN .................................. |   O-BOT   |
-      //  NotNull | ... O-NN .................................. |   O-BOT   |
-      //  BOTTOM  | ........................Object-BOTTOM ..................|
-      //
-      assert(loaded->ptr() != TypePtr::Null, "insanity check");
-      //
-      if(      loaded->ptr() == TypePtr::TopPTR ) { return unloaded; }
-      else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make(ptr, unloaded->klass(), false, NULL, off, instance_id, speculative, depth); }
-      else if (loaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; }
-      else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) {
-        if (unloaded->ptr() == TypePtr::BotPTR  ) { return TypeInstPtr::BOTTOM;  }
-        else                                      { return TypeInstPtr::NOTNULL; }
-      }
-      else if( unloaded->ptr() == TypePtr::TopPTR )  { return unloaded; }
-
-      return unloaded->cast_to_ptr_type(TypePtr::AnyNull)->is_instptr();
+  const TypeInstPtr *loaded    = is_loaded() ? this  : tinst;
+  const TypeInstPtr *unloaded  = is_loaded() ? tinst : this;
+  if( loaded->klass()->equals(ciEnv::current()->Object_klass()) ) {
+    //
+    // Meet unloaded class with java/lang/Object
+    //
+    // Meet
+    //          |                     Unloaded Class
+    //  Object  |   TOP    |   AnyNull | Constant |   NotNull |  BOTTOM   |
+    //  ===================================================================
+    //   TOP    | ..........................Unloaded......................|
+    //  AnyNull |  U-AN    |................Unloaded......................|
+    // Constant | ... O-NN .................................. |   O-BOT   |
+    //  NotNull | ... O-NN .................................. |   O-BOT   |
+    //  BOTTOM  | ........................Object-BOTTOM ..................|
+    //
+    assert(loaded->ptr() != TypePtr::Null, "insanity check");
+    //
+    if (loaded->ptr() == TypePtr::TopPTR)        { return unloaded; }
+    else if (loaded->ptr() == TypePtr::AnyNull)  { return make(ptr, unloaded->klass(), interfaces, false, NULL, off, instance_id, speculative, depth); }
+    else if (loaded->ptr() == TypePtr::BotPTR)   { return TypeInstPtr::BOTTOM; }
+    else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) {
+      if (unloaded->ptr() == TypePtr::BotPTR)    { return TypeInstPtr::BOTTOM;  }
+      else                                       { return TypeInstPtr::NOTNULL; }
     }
+    else if (unloaded->ptr() == TypePtr::TopPTR) { return unloaded; }
 
-    // Both are unloaded, not the same class, not Object
-    // Or meet unloaded with a different loaded class, not java/lang/Object
-    if( ptr != TypePtr::BotPTR ) {
-      return TypeInstPtr::NOTNULL;
-    }
-    return TypeInstPtr::BOTTOM;
+    return unloaded->cast_to_ptr_type(TypePtr::AnyNull)->is_instptr();
+  }
+
+  // Both are unloaded, not the same class, not Object
+  // Or meet unloaded with a different loaded class, not java/lang/Object
+  if (ptr != TypePtr::BotPTR) {
+    return TypeInstPtr::NOTNULL;
+  }
+  return TypeInstPtr::BOTTOM;
 }
 
 
@@ -3875,7 +4073,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
       int instance_id = meet_instance_id(InstanceTop);
       const TypePtr* speculative = xmeet_speculative(tp);
       int depth = meet_inline_depth(tp->inline_depth());
-      return make(ptr, klass(), klass_is_exact(),
+      return make(ptr, klass(), _interfaces, klass_is_exact(),
                   (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth);
     }
     case NotNull:
@@ -3903,7 +4101,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
       // else fall through to AnyNull
     case TopPTR:
     case AnyNull: {
-      return make(ptr, klass(), klass_is_exact(),
+      return make(ptr, klass(), _interfaces, klass_is_exact(),
                   (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth);
     }
     case NotNull:
@@ -3937,18 +4135,19 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
     int instance_id = meet_instance_id(tinst->instance_id());
     const TypePtr* speculative = xmeet_speculative(tinst);
     int depth = meet_inline_depth(tinst->inline_depth());
+    InterfaceSet interfaces = meet_interfaces(tinst);
+
     ciKlass* tinst_klass = tinst->klass();
     ciKlass* this_klass  = klass();
-    bool tinst_xk = tinst->klass_is_exact();
-    bool this_xk  = klass_is_exact();
 
     ciKlass* res_klass = NULL;
     bool res_xk = false;
     const Type* res;
-    MeetResult kind = meet_instptr(ptr, this_klass, tinst_klass, this_xk, tinst_xk, this->_ptr, tinst->_ptr, res_klass, res_xk);
+    MeetResult kind = meet_instptr(ptr, interfaces, this, tinst, res_klass, res_xk);
+
     if (kind == UNLOADED) {
       // One of these classes has not been loaded
-      const TypeInstPtr* unloaded_meet = xmeet_unloaded(tinst);
+      const TypeInstPtr* unloaded_meet = xmeet_unloaded(tinst, interfaces);
 #ifndef PRODUCT
       if (PrintOpto && Verbose) {
         tty->print("meet of unloaded classes resulted in: ");
@@ -3985,7 +4184,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
         } else
           ptr = NotNull;
       }
-      res = make(ptr, res_klass, res_xk, o, off, instance_id, speculative, depth);
+      res = make(ptr, res_klass, interfaces, res_xk, o, off, instance_id, speculative, depth);
     }
 
     return res;
@@ -3996,66 +4195,31 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
   return this;                  // Return the double constant
 }
 
-TypePtr::MeetResult TypePtr::meet_instptr(PTR &ptr, ciKlass* this_klass, ciKlass* tinst_klass, bool this_xk, bool tinst_xk,
-                                          PTR this_ptr,
-                                          PTR tinst_ptr, ciKlass*&res_klass, bool &res_xk) {
-
+template<class T> TypePtr::MeetResult TypePtr::meet_instptr(PTR& ptr, InterfaceSet& interfaces, const T* this_type, const T* other_type,
+                      ciKlass*& res_klass, bool& res_xk) {
+  ciKlass* this_klass = this_type->klass();
+  ciKlass* other_klass = other_type->klass();
+  bool this_xk = this_type->klass_is_exact();
+  bool other_xk = other_type->klass_is_exact();
+  PTR this_ptr = this_type->ptr();
+  PTR other_ptr = other_type->ptr();
+  InterfaceSet this_interfaces = this_type->interfaces();
+  InterfaceSet other_interfaces = other_type->interfaces();
   // Check for easy case; klasses are equal (and perhaps not loaded!)
   // If we have constants, then we created oops so classes are loaded
   // and we can handle the constants further down.  This case handles
   // both-not-loaded or both-loaded classes
-  if (ptr != Constant && this_klass->equals(tinst_klass) && this_xk == tinst_xk) {
+  if (ptr != Constant && this_klass->equals(other_klass) && this_xk == other_xk) {
     res_klass = this_klass;
     res_xk = this_xk;
     return QUICK;
   }
 
   // Classes require inspection in the Java klass hierarchy.  Must be loaded.
-  if (!tinst_klass->is_loaded() || !this_klass->is_loaded()) {
+  if (!other_klass->is_loaded() || !this_klass->is_loaded()) {
     return UNLOADED;
   }
 
-  // Handle mixing oops and interfaces first.
-  if (this_klass->is_interface() && !(tinst_klass->is_interface() ||
-                                      tinst_klass == ciEnv::current()->Object_klass())) {
-    ciKlass *tmp = tinst_klass; // Swap interface around
-    tinst_klass = this_klass;
-    this_klass = tmp;
-    bool tmp2 = tinst_xk;
-    tinst_xk = this_xk;
-    this_xk = tmp2;
-  }
-  if (tinst_klass->is_interface() &&
-      !(this_klass->is_interface() ||
-        // Treat java/lang/Object as an honorary interface,
-        // because we need a bottom for the interface hierarchy.
-        this_klass == ciEnv::current()->Object_klass())) {
-    // Oop meets interface!
-
-    // See if the oop subtypes (implements) interface.
-    if (this_klass->is_subtype_of(tinst_klass)) {
-      // Oop indeed subtypes.  Now keep oop or interface depending
-      // on whether we are both above the centerline or either is
-      // below the centerline.  If we are on the centerline
-      // (e.g., Constant vs. AnyNull interface), use the constant.
-      res_klass  = below_centerline(ptr) ? tinst_klass : this_klass;
-      // If we are keeping this_klass, keep its exactness too.
-      res_xk = below_centerline(ptr) ? tinst_xk    : this_xk;
-      return SUBTYPE;
-    } else {                  // Does not implement, fall to Object
-      // Oop does not implement interface, so mixing falls to Object
-      // just like the verifier does (if both are above the
-      // centerline fall to interface)
-      res_klass = above_centerline(ptr) ? tinst_klass : ciEnv::current()->Object_klass();
-      res_xk = above_centerline(ptr) ? tinst_xk : false;
-      // Watch out for Constant vs. AnyNull interface.
-      if (ptr == Constant)  ptr = NotNull;   // forget it was a constant
-      return NOT_SUBTYPE;
-    }
-  }
-
-  // Either oop vs oop or interface vs interface or interface vs Object
-
   // !!! Here's how the symmetry requirement breaks down into invariants:
   // If we split one up & one down AND they subtype, take the down man.
   // If we split one up & one down AND they do NOT subtype, "fall hard".
@@ -4081,40 +4245,42 @@ TypePtr::MeetResult TypePtr::meet_instptr(PTR &ptr, ciKlass* this_klass, ciKlass
   // centerline and or-ed above it.  (N.B. Constants are always exact.)
 
   // Check for subtyping:
-  ciKlass *subtype = NULL;
+  const T* subtype = NULL;
   bool subtype_exact = false;
-  if (tinst_klass->equals(this_klass)) {
-    subtype = this_klass;
-    subtype_exact = below_centerline(ptr) ? (this_xk && tinst_xk) : (this_xk || tinst_xk);
-  } else if (!tinst_xk && this_klass->is_subtype_of(tinst_klass)) {
-    subtype = this_klass;     // Pick subtyping class
+  InterfaceSet subtype_interfaces;
+
+  if (this_type->is_same_java_type_as(other_type)) {
+    subtype = this_type;
+    subtype_exact = below_centerline(ptr) ? (this_xk && other_xk) : (this_xk || other_xk);
+  } else if (!other_xk && this_type->is_meet_subtype_of(other_type)) {
+    subtype = this_type;     // Pick subtyping class
     subtype_exact = this_xk;
-  } else if (!this_xk && tinst_klass->is_subtype_of(this_klass)) {
-    subtype = tinst_klass;    // Pick subtyping class
-    subtype_exact = tinst_xk;
+  } else if(!this_xk && other_type->is_meet_subtype_of(this_type)) {
+    subtype = other_type;    // Pick subtyping class
+    subtype_exact = other_xk;
   }
 
   if (subtype) {
     if (above_centerline(ptr)) { // both are up?
-      this_klass = tinst_klass = subtype;
-      this_xk = tinst_xk = subtype_exact;
-    } else if (above_centerline(this_ptr) && !above_centerline(tinst_ptr)) {
-      this_klass = tinst_klass; // tinst is down; keep down man
-      this_xk = tinst_xk;
-    } else if (above_centerline(tinst_ptr) && !above_centerline(this_ptr)) {
-      tinst_klass = this_klass; // this is down; keep down man
-      tinst_xk = this_xk;
+      this_type = other_type = subtype;
+      this_xk = other_xk = subtype_exact;
+    } else if (above_centerline(this_ptr) && !above_centerline(other_ptr)) {
+      this_type = other_type; // tinst is down; keep down man
+      this_xk = other_xk;
+    } else if (above_centerline(other_ptr) && !above_centerline(this_ptr)) {
+      other_type = this_type; // this is down; keep down man
+      other_xk = this_xk;
     } else {
       this_xk = subtype_exact;  // either they are equal, or we'll do an LCA
     }
   }
 
   // Check for classes now being equal
-  if (tinst_klass->equals(this_klass)) {
+  if (this_type->is_same_java_type_as(other_type)) {
     // If the klasses are equal, the constants may still differ.  Fall to
     // NotNull if they do (neither constant is NULL; that is a special case
     // handled elsewhere).
-    res_klass = this_klass;
+    res_klass = this_type->klass();
     res_xk = this_xk;
     return SUBTYPE;
   } // Else classes are not equal
@@ -4125,8 +4291,10 @@ TypePtr::MeetResult TypePtr::meet_instptr(PTR &ptr, ciKlass* this_klass, ciKlass
     ptr = NotNull;
   }
 
+  interfaces = this_interfaces.intersection_with(other_interfaces);
+
   // Now we find the LCA of Java classes
-  ciKlass* k = this_klass->least_common_ancestor(tinst_klass);
+  ciKlass* k = this_klass->least_common_ancestor(other_klass);
 
   res_klass = k;
   res_xk = false;
@@ -4134,7 +4302,6 @@ TypePtr::MeetResult TypePtr::meet_instptr(PTR &ptr, ciKlass* this_klass, ciKlass
   return LCA;
 }
 
-
 //------------------------java_mirror_type--------------------------------------
 ciType* TypeInstPtr::java_mirror_type() const {
   // must be a singleton type
@@ -4151,7 +4318,7 @@ ciType* TypeInstPtr::java_mirror_type() const {
 // Dual: do NOT dual on klasses.  This means I do NOT understand the Java
 // inheritance mechanism.
 const Type *TypeInstPtr::xdual() const {
-  return new TypeInstPtr(dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
+  return new TypeInstPtr(dual_ptr(), klass(), _interfaces, klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
 }
 
 //------------------------------eq---------------------------------------------
@@ -4160,77 +4327,28 @@ bool TypeInstPtr::eq( const Type *t ) const {
   const TypeInstPtr *p = t->is_instptr();
   return
     klass()->equals(p->klass()) &&
+    _interfaces.eq(p->_interfaces) &&
     TypeOopPtr::eq(p);          // Check sub-type stuff
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeInstPtr::hash(void) const {
-  int hash = java_add((jint)klass()->hash(), (jint)TypeOopPtr::hash());
+  int hash = java_add(java_add((jint)klass()->hash(), (jint)TypeOopPtr::hash()), _interfaces.hash());
   return hash;
 }
 
 bool TypeInstPtr::is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const {
-  if (!is_loaded() || !other->is_loaded()) {
-    return false;
-  }
-  if (!other->isa_instptr()) {
-    return false;
-  }
-
-  if (!other_exact) {
-    return false;
-  }
-
-  if (other->klass()->equals(ciEnv::current()->Object_klass())) {
-    return true;
-  }
-
-  if (!this_exact && klass()->is_interface()) {
-    return false;
-  }
-
-  return _klass->is_subtype_of(other->klass());
+  return TypePtr::is_java_subtype_of_helper_for_instance(this, other, this_exact, other_exact);
 }
 
-bool TypeInstPtr::is_same_java_type_as(const TypeOopPtr* other) const {
-  if (!is_loaded() || !other->is_loaded()) {
-    return false;
-  }
-  if (!other->isa_instptr()) {
-    return false;
-  }
-  return _klass->equals(other->_klass);
+
+bool TypeInstPtr::is_same_java_type_as_helper(const TypeOopPtr* other) const {
+  return TypePtr::is_same_java_type_as_helper_for_instance(this, other);
 }
 
 bool TypeInstPtr::maybe_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const {
-  if (!is_loaded() || !other->is_loaded()) {
-    return true;
-  }
-
-  if (other->isa_aryptr()) {
-    return !this_exact && (_klass->equals(ciEnv::current()->Object_klass()) || _klass->is_interface());
-  }
-
-  if ((_klass->is_interface() && !this_exact) || (other->klass()->is_interface() /*&& !other_exact*/)) {
-    return true;
-  }
-
-  assert(other->isa_instptr(), "unsupported");
-
-  if (this_exact && other_exact) {
-    return is_java_subtype_of(other);
-  }
-
-  if (!_klass->is_subtype_of(other->_klass) && !other->_klass->is_subtype_of(_klass)) {
-    return false;
-  }
-
-  if (this_exact) {
-    return _klass->is_subtype_of(other->_klass);
-  }
-
-  return true;
+  return TypePtr::maybe_java_subtype_of_helper_for_instance(this, other, this_exact, other_exact);
 }
 
 
@@ -4240,6 +4358,7 @@ bool TypeInstPtr::maybe_java_subtype_of_helper(const TypeOopPtr* other, bool thi
 void TypeInstPtr::dump2(Dict &d, uint depth, outputStream* st) const {
   // Print the name of the klass.
   klass()->print_name_on(st);
+  _interfaces.dump(st);
 
   switch( _ptr ) {
   case Constant:
@@ -4289,12 +4408,12 @@ void TypeInstPtr::dump2(Dict &d, uint depth, outputStream* st) const {
 
 //------------------------------add_offset-------------------------------------
 const TypePtr* TypeInstPtr::add_offset(intptr_t offset) const {
-  return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset),
+  return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), xadd_offset(offset),
               _instance_id, add_offset_speculative(offset), _inline_depth);
 }
 
 const TypeInstPtr* TypeInstPtr::with_offset(intptr_t offset) const {
-  return make(_ptr, klass(), klass_is_exact(), const_oop(), offset,
+  return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), offset,
               _instance_id, with_offset_speculative(offset), _inline_depth);
 }
 
@@ -4303,32 +4422,99 @@ const TypeInstPtr* TypeInstPtr::remove_speculative() const {
     return this;
   }
   assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
-  return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset,
+  return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset,
               _instance_id, NULL, _inline_depth);
 }
 
-const TypePtr *TypeInstPtr::with_inline_depth(int depth) const {
+const TypePtr* TypeInstPtr::with_inline_depth(int depth) const {
   if (!UseInlineDepthForSpeculativeTypes) {
     return this;
   }
-  return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative, depth);
+  return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, _instance_id, _speculative, depth);
 }
 
-const TypePtr *TypeInstPtr::with_instance_id(int instance_id) const {
+const TypePtr* TypeInstPtr::with_instance_id(int instance_id) const {
   assert(is_known_instance(), "should be known");
-  return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, instance_id, _speculative, _inline_depth);
+  return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, instance_id, _speculative, _inline_depth);
 }
 
 const TypeKlassPtr* TypeInstPtr::as_klass_type(bool try_for_exact) const {
   bool xk = klass_is_exact();
   ciInstanceKlass* ik = klass()->as_instance_klass();
-  if (try_for_exact && !xk && !ik->has_subklass() && !ik->is_final() && !ik->is_interface()) {
-    Compile* C = Compile::current();
-    Dependencies* deps = C->dependencies();
-    deps->assert_leaf_type(ik);
-    xk = true;
+  if (try_for_exact && !xk && !ik->has_subklass() && !ik->is_final()) {
+    ciKlass* k = ik;
+    TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
+    assert(k == ik, "");
+    if (interfaces.eq(_interfaces)) {
+      Compile *C = Compile::current();
+      Dependencies* deps = C->dependencies();
+      deps->assert_leaf_type(ik);
+      xk = true;
+    }
   }
-  return TypeInstKlassPtr::make(xk ? TypePtr::Constant : TypePtr::NotNull, klass(), 0);
+  return TypeInstKlassPtr::make(xk ? TypePtr::Constant : TypePtr::NotNull, klass(), _interfaces, 0);
+}
+
+template <class T1, class T2> bool TypePtr::is_meet_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_xk, bool other_xk) {
+  static_assert(std::is_base_of<T2, T1>::value, "");
+
+  if (!this_one->is_instance_type(other)) {
+    return false;
+  }
+
+  if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces.empty()) {
+    return true;
+  }
+
+  return this_one->klass()->is_subtype_of(other->klass()) &&
+         (!this_xk || this_one->_interfaces.contains(other->_interfaces));
+}
+
+
+bool TypeInstPtr::is_meet_subtype_of_helper(const TypeOopPtr *other, bool this_xk, bool other_xk) const {
+  return TypePtr::is_meet_subtype_of_helper_for_instance(this, other, this_xk, other_xk);
+}
+
+template <class T1, class T2>  bool TypePtr::is_meet_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_xk, bool other_xk) {
+  static_assert(std::is_base_of<T2, T1>::value, "");
+  if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces.empty()) {
+    return true;
+  }
+
+  if (this_one->is_instance_type(other)) {
+    return other->klass() == ciEnv::current()->Object_klass() && this_one->_interfaces.contains(other->_interfaces);
+  }
+
+  int dummy;
+  bool this_top_or_bottom = (this_one->base_element_type(dummy) == Type::TOP || this_one->base_element_type(dummy) == Type::BOTTOM);
+  if (this_top_or_bottom) {
+    return false;
+  }
+
+  const T1* other_ary = this_one->is_array_type(other);
+  const TypePtr* other_elem = other_ary->elem()->make_ptr();
+  const TypePtr* this_elem = this_one->elem()->make_ptr();
+  if (other_elem != NULL && this_elem != NULL) {
+    return this_one->is_reference_type(this_elem)->is_meet_subtype_of_helper(this_one->is_reference_type(other_elem), this_xk, other_xk);
+  }
+
+  if (other_elem == NULL && this_elem == NULL) {
+    return this_one->_klass->is_subtype_of(other->_klass);
+  }
+
+  return false;
+}
+
+bool TypeAryPtr::is_meet_subtype_of_helper(const TypeOopPtr *other, bool this_xk, bool other_xk) const {
+  return TypePtr::is_meet_subtype_of_helper_for_array(this, other, this_xk, other_xk);
+}
+
+bool TypeInstKlassPtr::is_meet_subtype_of_helper(const TypeKlassPtr *other, bool this_xk, bool other_xk) const {
+  return TypePtr::is_meet_subtype_of_helper_for_instance(this, other, this_xk, other_xk);
+}
+
+bool TypeAryKlassPtr::is_meet_subtype_of_helper(const TypeKlassPtr *other, bool this_xk, bool other_xk) const {
+  return TypePtr::is_meet_subtype_of_helper_for_array(this, other, this_xk, other_xk);
 }
 
 //=============================================================================
@@ -4351,6 +4537,10 @@ const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool
          "integral arrays must be pre-equipped with a class");
   if (!xk)  xk = ary->ary_must_be_exact();
   assert(instance_id <= 0 || xk, "instances are always exactly typed");
+  if (k != NULL && k->is_loaded() && k->is_obj_array_klass() &&
+      k->as_obj_array_klass()->base_element_klass()->is_interface()) {
+    k = NULL;
+  }
   return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id, false, speculative, inline_depth))->hashcons();
 }
 
@@ -4363,6 +4553,10 @@ const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciK
   assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
   if (!xk)  xk = (o != NULL) || ary->ary_must_be_exact();
   assert(instance_id <= 0 || xk, "instances are always exactly typed");
+  if (k != NULL && k->is_loaded() && k->is_obj_array_klass() &&
+      k->as_obj_array_klass()->base_element_klass()->is_interface()) {
+    k = NULL;
+  }
   return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache, speculative, inline_depth))->hashcons();
 }
 
@@ -4390,7 +4584,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_instance_id(int instance_id) const {
 //-----------------------------max_array_length-------------------------------
 // A wrapper around arrayOopDesc::max_array_length(etype) with some input normalization.
 jint TypeAryPtr::max_array_length(BasicType etype) {
-  if (!is_java_primitive(etype) && !is_reference_type(etype)) {
+  if (!is_java_primitive(etype) && !::is_reference_type(etype)) {
     if (etype == T_NARROWOOP) {
       etype = T_OBJECT;
     } else if (etype == T_ILLEGAL) { // bottom[]
@@ -4498,71 +4692,15 @@ int TypeAryPtr::hash(void) const {
 }
 
 bool TypeAryPtr::is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const {
-  if (other->klass() == ciEnv::current()->Object_klass() && other_exact) {
-    return true;
-  }
-
-  if (!is_loaded() || !other->is_loaded() || other->klass() == NULL || klass() == NULL) {
-    return false;
-  }
-  if (other->isa_instptr()) {
-    return _klass->is_subtype_of(other->_klass) && other_exact;
-  }
-  if (klass() == NULL) {
-    return false;
-  }
-  assert(other->isa_aryptr(), "");
-  const TypeAryPtr* other_ary = other->isa_aryptr();
-  if (other_ary->elem()->make_oopptr() && elem()->make_oopptr()) {
-    return elem()->make_oopptr()->is_java_subtype_of_helper(other_ary->elem()->make_oopptr(), this_exact, other_exact);
-  }
-  if (!other_ary->elem()->make_oopptr() && !elem()->make_oopptr()) {
-    return _klass->is_subtype_of(other->_klass);
-  }
-  return false;
+  return TypePtr::is_java_subtype_of_helper_for_array(this, other, this_exact, other_exact);
 }
 
-bool TypeAryPtr::is_same_java_type_as(const TypeOopPtr* other) const {
-  if (!other->isa_aryptr() ||
-      !is_loaded() || !other->is_loaded() || klass() == NULL || other->klass() == NULL) {
-    return false;
-  }
-  const TypeAryPtr* other_ary = other->isa_aryptr();
-  if (other_ary->elem()->make_oopptr() && elem()->make_oopptr()) {
-    return elem()->make_oopptr()->is_same_java_type_as(other_ary->elem()->make_oopptr());
-  }
-  if (!other_ary->elem()->make_oopptr() && !elem()->make_oopptr()) {
-    return _klass->equals(other->_klass);
-  }
-  return false;
+bool TypeAryPtr::is_same_java_type_as_helper(const TypeOopPtr* other) const {
+  return TypePtr::is_same_java_type_as_helper_for_array(this, other);
 }
 
 bool TypeAryPtr::maybe_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const {
-  if (other->klass() == ciEnv::current()->Object_klass()) {
-    return true;
-  }
-
-  if (!is_loaded() || !other->is_loaded() || klass() == NULL || other->klass() == NULL) {
-    return true;
-  }
-  if (other->isa_instptr()) {
-    return (!other_exact && other->_klass->is_interface()) || _klass->is_subtype_of(other->_klass);
-  }
-  assert(other->isa_aryptr(), "");
-
-  if (this_exact && other_exact) {
-    return is_java_subtype_of(other);
-  }
-
-  const TypeAryPtr* other_ary = other->isa_aryptr();
-  if (other_ary->elem()->make_oopptr() && elem()->make_oopptr()) {
-    return elem()->make_oopptr()->maybe_java_subtype_of_helper(other_ary->elem()->make_oopptr(), this_exact,
-                                                               other_exact);
-  }
-  if (!other_ary->elem()->make_oopptr() && !elem()->make_oopptr()) {
-    return _klass->is_subtype_of(other->_klass);
-  }
-  return false;
+  return TypePtr::maybe_java_subtype_of_helper_for_array(this, other, this_exact, other_exact);
 }
 //------------------------------meet-------------------------------------------
 // Compute the MEET of two types.  It returns a new Type object.
@@ -4657,7 +4795,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
     ciKlass* res_klass = NULL;
     bool res_xk = false;
     const Type* elem = tary->_elem;
-    if (meet_aryptr(ptr, elem, this->klass(), tap->klass(), this->klass_is_exact(), tap->klass_is_exact(), this->ptr(), tap->ptr(), res_klass, res_xk) == NOT_SUBTYPE) {
+    if (meet_aryptr(ptr, elem, this, tap, res_klass, res_xk) == NOT_SUBTYPE) {
       instance_id = InstanceBot;
     }
 
@@ -4687,19 +4825,24 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
     int instance_id = meet_instance_id(tp->instance_id());
     const TypePtr* speculative = xmeet_speculative(tp);
     int depth = meet_inline_depth(tp->inline_depth());
+    InterfaceSet interfaces = meet_interfaces(tp);
+    InterfaceSet tp_interfaces = tp->_interfaces;
+    InterfaceSet this_interfaces = _interfaces;
+
     switch (ptr) {
     case TopPTR:
     case AnyNull:                // Fall 'down' to dual of object klass
       // For instances when a subclass meets a superclass we fall
       // below the centerline when the superclass is exact. We need to
       // do the same here.
-      if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) {
-        return make(ptr, _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
+      if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces.contains(tp_interfaces) && !tp->klass_is_exact()) {
+        return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
       } else {
         // cannot subclass, so the meet has to fall badly below the centerline
         ptr = NotNull;
         instance_id = InstanceBot;
-        return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative, depth);
+        interfaces = this_interfaces.intersection_with(tp_interfaces);
+        return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, NULL,offset, instance_id, speculative, depth);
       }
     case Constant:
     case NotNull:
@@ -4711,7 +4854,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
         // For instances when a subclass meets a superclass we fall
         // below the centerline when the superclass is exact. We need
         // to do the same here.
-        if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) {
+        if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces.contains(tp_interfaces) && !tp->klass_is_exact()) {
           // that is, my array type is a subtype of 'tp' klass
           return make(ptr, (ptr == Constant ? const_oop() : NULL),
                       _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
@@ -4725,7 +4868,8 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
       if (instance_id > 0) {
         instance_id = InstanceBot;
       }
-      return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative, depth);
+      interfaces = this_interfaces.intersection_with(tp_interfaces);
+      return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, NULL, offset, instance_id, speculative, depth);
     default: typerr(t);
     }
   }
@@ -4734,15 +4878,22 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
 }
 
 
-TypePtr::MeetResult TypePtr::meet_aryptr(PTR& ptr, const Type*& elem, ciKlass* this_klass, ciKlass* tap_klass, bool this_xk, bool tap_xk, PTR this_ptr, PTR tap_ptr, ciKlass*& res_klass, bool& res_xk) {
+template<class T> TypePtr::MeetResult TypePtr::meet_aryptr(PTR& ptr, const Type*& elem, const T* this_ary,
+                                                           const T* other_ary, ciKlass*& res_klass, bool& res_xk) {
+  ciKlass* this_klass = this_ary->klass();
+  ciKlass* other_klass = other_ary->klass();
+  bool this_xk = this_ary->klass_is_exact();
+  bool other_xk = other_ary->klass_is_exact();
+  PTR this_ptr = this_ary->ptr();
+  PTR other_ptr = other_ary->ptr();
   res_klass = NULL;
   MeetResult result = SUBTYPE;
   if (elem->isa_int()) {
     // Integral array element types have irrelevant lattice relations.
     // It is the klass that determines array layout, not the element type.
     if (this_klass == NULL)
-      res_klass = tap_klass;
-    else if (tap_klass == NULL || tap_klass == this_klass) {
+      res_klass = other_klass;
+    else if (other_klass == NULL || other_klass == this_klass) {
       res_klass = this_klass;
     } else {
       // Something like byte[int+] meets char[int+].
@@ -4751,18 +4902,21 @@ TypePtr::MeetResult TypePtr::meet_aryptr(PTR& ptr, const Type*& elem, ciKlass* t
       elem = Type::BOTTOM;
       result = NOT_SUBTYPE;
     }
-  } else // Non integral arrays.
+  } else {// Non integral arrays.
     // Must fall to bottom if exact klasses in upper lattice
     // are not equal or super klass is exact.
-    if ((above_centerline(ptr) || ptr == Constant) && this_klass != tap_klass &&
+    int dummy;
+    bool this_top_or_bottom = (this_ary->base_element_type(dummy) == Type::TOP || this_ary->base_element_type(dummy) == Type::BOTTOM);
+    bool other_top_or_bottom = (other_ary->base_element_type(dummy) == Type::TOP || other_ary->base_element_type(dummy) == Type::BOTTOM);
+    if ((above_centerline(ptr) || ptr == Constant) && !this_ary->is_same_java_type_as(other_ary) &&
         // meet with top[] and bottom[] are processed further down:
-        tap_klass != NULL  && this_klass != NULL   &&
+        !this_top_or_bottom && !other_top_or_bottom &&
         // both are exact and not equal:
-        ((tap_xk && this_xk) ||
+        ((other_xk && this_xk) ||
          // 'tap'  is exact and super or unrelated:
-         (tap_xk && !tap_klass->is_subtype_of(this_klass)) ||
+         (other_xk && !other_ary->is_meet_subtype_of(this_ary)) ||
          // 'this' is exact and super or unrelated:
-         (this_xk && !this_klass->is_subtype_of(tap_klass)))) {
+         (this_xk && !this_ary->is_meet_subtype_of(other_ary)))) {
       if (above_centerline(ptr) || (elem->make_ptr() && above_centerline(elem->make_ptr()->_ptr))) {
         elem = Type::BOTTOM;
       }
@@ -4770,16 +4924,17 @@ TypePtr::MeetResult TypePtr::meet_aryptr(PTR& ptr, const Type*& elem, ciKlass* t
       res_xk = false;
       return NOT_SUBTYPE;
     }
+  }
 
   res_xk = false;
-  switch (tap_ptr) {
+  switch (other_ptr) {
     case AnyNull:
     case TopPTR:
       // Compute new klass on demand, do not use tap->_klass
       if (below_centerline(this_ptr)) {
         res_xk = this_xk;
       } else {
-        res_xk = (tap_xk || this_xk);
+        res_xk = (other_xk || this_xk);
       }
       return result;
     case Constant: {
@@ -4789,7 +4944,7 @@ TypePtr::MeetResult TypePtr::meet_aryptr(PTR& ptr, const Type*& elem, ciKlass* t
         res_xk = true;
       } else {
         // Only precise for identical arrays
-        res_xk = this_xk && (this_klass == tap_klass);
+        res_xk = this_xk && this_ary->is_same_java_type_as(other_ary);
       }
       return result;
     }
@@ -4797,10 +4952,10 @@ TypePtr::MeetResult TypePtr::meet_aryptr(PTR& ptr, const Type*& elem, ciKlass* t
     case BotPTR:
       // Compute new klass on demand, do not use tap->_klass
       if (above_centerline(this_ptr)) {
-        res_xk = tap_xk;
+        res_xk = other_xk;
       } else {
-        res_xk = (tap_xk && this_xk) &&
-          (this_klass == tap_klass); // Only precise for identical arrays
+        res_xk = (other_xk && this_xk) &&
+                 (this_ary->is_same_java_type_as(other_ary)); // Only precise for identical arrays
       }
       return result;
     default:  {
@@ -4818,21 +4973,12 @@ const Type *TypeAryPtr::xdual() const {
   return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative(), dual_inline_depth());
 }
 
-//----------------------interface_vs_oop---------------------------------------
-#ifdef ASSERT
-bool TypeAryPtr::interface_vs_oop(const Type *t) const {
-  const TypeAryPtr* t_aryptr = t->isa_aryptr();
-  if (t_aryptr) {
-    return _ary->interface_vs_oop(t_aryptr->_ary);
-  }
-  return false;
-}
-#endif
-
 //------------------------------dump2------------------------------------------
 #ifndef PRODUCT
 void TypeAryPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
   _ary->dump2(d,depth,st);
+  _interfaces.dump(st);
+
   switch( _ptr ) {
   case Constant:
     const_oop()->print(st);
@@ -4885,7 +5031,7 @@ bool TypeAryPtr::empty(void) const {
 }
 
 //------------------------------add_offset-------------------------------------
-const TypePtr *TypeAryPtr::add_offset(intptr_t offset) const {
+const TypePtr* TypeAryPtr::add_offset(intptr_t offset) const {
   return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id, add_offset_speculative(offset), _inline_depth);
 }
 
@@ -4905,14 +5051,14 @@ const TypeAryPtr* TypeAryPtr::remove_speculative() const {
   return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, NULL, _inline_depth);
 }
 
-const TypePtr *TypeAryPtr::with_inline_depth(int depth) const {
+const TypePtr* TypeAryPtr::with_inline_depth(int depth) const {
   if (!UseInlineDepthForSpeculativeTypes) {
     return this;
   }
   return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, _speculative, depth);
 }
 
-const TypePtr *TypeAryPtr::with_instance_id(int instance_id) const {
+const TypePtr* TypeAryPtr::with_instance_id(int instance_id) const {
   assert(is_known_instance(), "should be known");
   return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, instance_id, _speculative, _inline_depth);
 }
@@ -5097,7 +5243,7 @@ bool TypeMetadataPtr::singleton(void) const {
 }
 
 //------------------------------add_offset-------------------------------------
-const TypePtr *TypeMetadataPtr::add_offset( intptr_t offset ) const {
+const TypePtr* TypeMetadataPtr::add_offset( intptr_t offset ) const {
   return make( _ptr, _metadata, xadd_offset(offset));
 }
 
@@ -5272,28 +5418,43 @@ const TypeKlassPtr* TypeAryPtr::as_klass_type(bool try_for_exact) const {
   return TypeAryKlassPtr::make(xk ? TypePtr::Constant : TypePtr::NotNull, elem, klass(), 0);
 }
 
-const TypeKlassPtr* TypeKlassPtr::make(ciKlass *klass) {
+const TypeKlassPtr* TypeKlassPtr::make(ciKlass *klass, InterfaceHandling interface_handling) {
   if (klass->is_instance_klass()) {
-    return TypeInstKlassPtr::make(klass);
+    return TypeInstKlassPtr::make(klass, interface_handling);
   }
-  return TypeAryKlassPtr::make(klass);
+  return TypeAryKlassPtr::make(klass, interface_handling);
 }
 
-const TypeKlassPtr* TypeKlassPtr::make(PTR ptr, ciKlass* klass, int offset) {
+const TypeKlassPtr* TypeKlassPtr::make(PTR ptr, ciKlass* klass, int offset, InterfaceHandling interface_handling) {
   if (klass->is_instance_klass()) {
-    return TypeInstKlassPtr::make(ptr, klass, offset);
+    const InterfaceSet interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling);
+    return TypeInstKlassPtr::make(ptr, klass, interfaces, offset);
   }
-  return TypeAryKlassPtr::make(ptr, klass, offset);
+  return TypeAryKlassPtr::make(ptr, klass, offset, interface_handling);
 }
 
 
 //------------------------------TypeKlassPtr-----------------------------------
-TypeKlassPtr::TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, int offset)
-  : TypePtr(t, ptr, offset), _klass(klass) {
+TypeKlassPtr::TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const InterfaceSet& interfaces, int offset)
+  : TypePtr(t, ptr, offset), _klass(klass), _interfaces(interfaces) {
+  assert(klass == NULL || !klass->is_loaded() || (klass->is_instance_klass() && !klass->is_interface()) ||
+         klass->is_type_array_klass() || !klass->as_obj_array_klass()->base_element_klass()->is_interface(), "no interface here");
 }
 
+// Is there a single ciKlass* that can represent that type?
 ciKlass* TypeKlassPtr::exact_klass_helper() const {
-  return _klass;
+  assert(_klass->is_instance_klass() && !_klass->is_interface(), "No interface");
+  if (_interfaces.empty()) {
+    return _klass;
+  }
+  if (_klass != ciEnv::current()->Object_klass()) {
+    ciKlass* k = _klass;
+    if (_interfaces.eq(TypePtr::interfaces(k, true, false, true, ignore_interfaces))) {
+      return _klass;
+    }
+    return NULL;
+  }
+  return _interfaces.exact_klass();
 }
 
 //------------------------------eq---------------------------------------------
@@ -5301,13 +5462,14 @@ ciKlass* TypeKlassPtr::exact_klass_helper() const {
 bool TypeKlassPtr::eq(const Type *t) const {
   const TypeKlassPtr *p = t->is_klassptr();
   return
+    _interfaces.eq(p->_interfaces) &&
     TypePtr::eq(p);
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeKlassPtr::hash(void) const {
-  return TypePtr::hash();
+  return java_add((jint)TypePtr::hash(), _interfaces.hash());
 }
 
 //------------------------------singleton--------------------------------------
@@ -5328,24 +5490,23 @@ const Type *TypeKlassPtr::filter_helper(const Type *kills, bool include_speculat
   const TypeKlassPtr* ktkp = kills->isa_instklassptr();
 
   if (ft->empty()) {
-    if (!empty() && ktkp != NULL && ktkp->klass()->is_loaded() && ktkp->klass()->is_interface())
-      return kills;             // Uplift to interface
-
     return Type::TOP;           // Canonical empty value
   }
 
-  // Interface klass type could be exact in opposite to interface type,
-  // return it here instead of incorrect Constant ptr J/L/Object (6894807).
-  if (ftkp != NULL && ktkp != NULL &&
-      ftkp->is_loaded() &&  ftkp->klass()->is_interface() &&
-      !ftkp->klass_is_exact() && // Keep exact interface klass
-      ktkp->is_loaded() && !ktkp->klass()->is_interface()) {
-    return ktkp->cast_to_ptr_type(ftkp->ptr());
-  }
-
   return ft;
 }
 
+TypePtr::InterfaceSet TypeKlassPtr::meet_interfaces(const TypeKlassPtr* other) const {
+  if (above_centerline(_ptr) && above_centerline(other->_ptr)) {
+    return _interfaces.union_with(other->_interfaces);
+  } else if (above_centerline(_ptr) && !above_centerline(other->_ptr)) {
+    return other->_interfaces;
+  } else if (above_centerline(other->_ptr) && !above_centerline(_ptr)) {
+    return _interfaces;
+  }
+  return _interfaces.intersection_with(other->_interfaces);
+}
+
 //------------------------------get_con----------------------------------------
 intptr_t TypeKlassPtr::get_con() const {
   assert( _ptr == Null || _ptr == Constant, "" );
@@ -5383,6 +5544,7 @@ void TypeKlassPtr::dump2(Dict & d, uint depth, outputStream *st) const {
       } else {
         ShouldNotReachHere();
       }
+      _interfaces.dump(st);
     }
   case BotPTR:
     if (!WizardMode && !Verbose && _ptr != Constant) break;
@@ -5423,28 +5585,28 @@ int TypeInstKlassPtr::hash(void) const {
   return java_add((jint)klass()->hash(), TypeKlassPtr::hash());
 }
 
-const TypeInstKlassPtr *TypeInstKlassPtr::make(PTR ptr, ciKlass* k, int offset) {
+const TypeInstKlassPtr *TypeInstKlassPtr::make(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, int offset) {
   TypeInstKlassPtr *r =
-    (TypeInstKlassPtr*)(new TypeInstKlassPtr(ptr, k, offset))->hashcons();
+    (TypeInstKlassPtr*)(new TypeInstKlassPtr(ptr, k, interfaces, offset))->hashcons();
 
   return r;
 }
 
 //------------------------------add_offset-------------------------------------
 // Access internals of klass object
-const TypePtr *TypeInstKlassPtr::add_offset( intptr_t offset ) const {
-  return make( _ptr, klass(), xadd_offset(offset) );
+const TypePtr* TypeInstKlassPtr::add_offset( intptr_t offset ) const {
+  return make( _ptr, klass(), _interfaces, xadd_offset(offset) );
 }
 
 const TypeInstKlassPtr* TypeInstKlassPtr::with_offset(intptr_t offset) const {
-  return make(_ptr, klass(), offset);
+  return make(_ptr, klass(), _interfaces, offset);
 }
 
 //------------------------------cast_to_ptr_type-------------------------------
 const TypeInstKlassPtr* TypeInstKlassPtr::cast_to_ptr_type(PTR ptr) const {
   assert(_base == InstKlassPtr, "subclass must override cast_to_ptr_type");
   if( ptr == _ptr ) return this;
-  return make(ptr, _klass, _offset);
+  return make(ptr, _klass, _interfaces, _offset);
 }
 
 
@@ -5460,7 +5622,7 @@ const TypeKlassPtr* TypeInstKlassPtr::cast_to_exactness(bool klass_is_exact) con
   if (klass_is_exact == (_ptr == Constant)) return this;
   if (must_be_exact()) return this;
   ciKlass* k = klass();
-  return make(klass_is_exact ? Constant : NotNull, k, _offset);
+  return make(klass_is_exact ? Constant : NotNull, k, _interfaces, _offset);
 }
 
 
@@ -5475,6 +5637,7 @@ const TypeOopPtr* TypeInstKlassPtr::as_instance_type(bool klass_change) const {
   assert((deps != NULL) == (C->method() != NULL && C->method()->code_size() > 0), "sanity");
   // Element is an instance
   bool klass_is_exact = false;
+  TypePtr::InterfaceSet interfaces = _interfaces;
   if (k->is_loaded()) {
     // Try to set klass_is_exact.
     ciInstanceKlass* ik = k->as_instance_klass();
@@ -5483,13 +5646,18 @@ const TypeOopPtr* TypeInstKlassPtr::as_instance_type(bool klass_change) const {
         && deps != NULL && UseUniqueSubclasses) {
       ciInstanceKlass* sub = ik->unique_concrete_subklass();
       if (sub != NULL) {
-        deps->assert_abstract_with_unique_concrete_subtype(ik, sub);
-        k = ik = sub;
-        xk = sub->is_final();
+        ciKlass* sub_k = sub;
+        TypePtr::InterfaceSet sub_interfaces = TypePtr::interfaces(sub_k, true, false, false, ignore_interfaces);
+        assert(sub_k == sub, "");
+        if (sub_interfaces.eq(_interfaces)) {
+          deps->assert_abstract_with_unique_concrete_subtype(ik, sub);
+          k = ik = sub;
+          xk = sub->is_final();
+        }
       }
     }
   }
-  return TypeInstPtr::make(TypePtr::BotPTR, k, xk, NULL, 0);
+  return TypeInstPtr::make(TypePtr::BotPTR, k, interfaces, xk, NULL, 0);
 }
 
 //------------------------------xmeet------------------------------------------
@@ -5530,7 +5698,7 @@ const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {
     case Null:
       if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
     case AnyNull:
-      return make( ptr, klass(), offset );
+      return make( ptr, klass(), _interfaces, offset );
     case BotPTR:
     case NotNull:
       return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
@@ -5565,14 +5733,11 @@ const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {
     const TypeInstKlassPtr *tkls = t->is_instklassptr();
     int  off     = meet_offset(tkls->offset());
     PTR  ptr     = meet_ptr(tkls->ptr());
-    ciKlass* tkls_klass = tkls->klass();
-    ciKlass* this_klass  = klass();
-    bool tkls_xk = tkls->klass_is_exact();
-    bool this_xk  = klass_is_exact();
+    InterfaceSet interfaces = meet_interfaces(tkls);
 
     ciKlass* res_klass = NULL;
     bool res_xk = false;
-    switch(meet_instptr(ptr, this_klass, tkls_klass, this_xk, tkls_xk, this->_ptr, tkls->_ptr, res_klass, res_xk)) {
+    switch(meet_instptr(ptr, interfaces, this, tkls, res_klass, res_xk)) {
       case UNLOADED:
         ShouldNotReachHere();
       case SUBTYPE:
@@ -5580,8 +5745,8 @@ const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {
       case LCA:
       case QUICK: {
         assert(res_xk == (ptr == Constant), "");
-        const Type* res1 = make(ptr, res_klass, off);
-        return res1;
+        const Type* res = make(ptr, res_klass, interfaces, off);
+        return res;
       }
       default:
         ShouldNotReachHere();
@@ -5591,6 +5756,9 @@ const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {
     const TypeAryKlassPtr *tp = t->is_aryklassptr();
     int offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
+    InterfaceSet interfaces = meet_interfaces(tp);
+    InterfaceSet tp_interfaces = tp->_interfaces;
+    InterfaceSet this_interfaces = _interfaces;
 
     switch (ptr) {
     case TopPTR:
@@ -5598,12 +5766,13 @@ const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {
       // For instances when a subclass meets a superclass we fall
       // below the centerline when the superclass is exact. We need to
       // do the same here.
-      if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) {
+      if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces.contains(this_interfaces) && !klass_is_exact()) {
         return TypeAryKlassPtr::make(ptr, tp->elem(), tp->klass(), offset);
       } else {
         // cannot subclass, so the meet has to fall badly below the centerline
         ptr = NotNull;
-        return make(ptr, ciEnv::current()->Object_klass(), offset);
+        interfaces = _interfaces.intersection_with(tp->_interfaces);
+        return make(ptr, ciEnv::current()->Object_klass(), interfaces, offset);
       }
     case Constant:
     case NotNull:
@@ -5615,7 +5784,7 @@ const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {
         // For instances when a subclass meets a superclass we fall
         // below the centerline when the superclass is exact. We need
         // to do the same here.
-        if (klass()->equals(ciEnv::current()->Object_klass())) {
+        if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces.contains(this_interfaces) && !klass_is_exact()) {
           // that is, tp's array type is a subtype of my klass
           return TypeAryKlassPtr::make(ptr,
                                        tp->elem(), tp->klass(), offset);
@@ -5625,7 +5794,8 @@ const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {
       // The meet falls down to Object class below centerline.
       if( ptr == Constant )
          ptr = NotNull;
-      return make(ptr, ciEnv::current()->Object_klass(), offset);
+      interfaces = this_interfaces.intersection_with(tp_interfaces);
+      return make(ptr, ciEnv::current()->Object_klass(), interfaces, offset);
     default: typerr(t);
     }
   }
@@ -5637,14 +5807,15 @@ const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {
 //------------------------------xdual------------------------------------------
 // Dual: compute field-by-field dual
 const Type    *TypeInstKlassPtr::xdual() const {
-  return new TypeInstKlassPtr(dual_ptr(), klass(), dual_offset());
+  return new TypeInstKlassPtr(dual_ptr(), klass(), _interfaces, dual_offset());
 }
 
-bool TypeInstKlassPtr::is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const {
-  if (!is_loaded() || !other->is_loaded()) {
+template <class T1, class T2> bool TypePtr::is_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact) {
+  static_assert(std::is_base_of<T2, T1>::value, "");
+  if (!this_one->is_loaded() || !other->is_loaded()) {
     return false;
   }
-  if (!other->isa_instklassptr()) {
+  if (!this_one->is_instance_type(other)) {
     return false;
   }
 
@@ -5652,79 +5823,117 @@ bool TypeInstKlassPtr::is_java_subtype_of_helper(const TypeKlassPtr* other, bool
     return false;
   }
 
-  if (other->_klass->equals(ciEnv::current()->Object_klass())) {
+  if (other->klass()->equals(ciEnv::current()->Object_klass()) && other->_interfaces.empty()) {
     return true;
   }
 
-  if (!this_exact && klass()->is_interface()) {
-    return false;
-  }
-
-  return _klass->is_subtype_of(other->_klass);
+  return this_one->_klass->is_subtype_of(other->_klass) && this_one->_interfaces.contains(other->_interfaces);
 }
 
-bool TypeInstKlassPtr::is_same_java_type_as(const TypeKlassPtr* other) const {
-  if (!is_loaded() || !other->is_loaded()) {
-    return false;
-  }
-  if (!other->isa_instklassptr()) {
-    return false;
-  }
-  return _klass->equals(other->_klass);
+bool TypeInstKlassPtr::is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const {
+  return TypePtr::is_java_subtype_of_helper_for_instance(this, other, this_exact, other_exact);
 }
 
-bool TypeInstKlassPtr::maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const {
-  if (!is_loaded() || !other->is_loaded()) {
+template <class T1, class T2> bool TypePtr::is_same_java_type_as_helper_for_instance(const T1* this_one, const T2* other) {
+  static_assert(std::is_base_of<T2, T1>::value, "");
+  if (!this_one->is_loaded() || !other->is_loaded()) {
+    return false;
+  }
+  if (!this_one->is_instance_type(other)) {
+    return false;
+  }
+  return this_one->_klass->equals(other->_klass) && this_one->_interfaces.eq(other->_interfaces);
+}
+
+bool TypeInstKlassPtr::is_same_java_type_as_helper(const TypeKlassPtr* other) const {
+  return TypePtr::is_same_java_type_as_helper_for_instance(this, other);
+}
+
+template <class T1, class T2> bool TypePtr::maybe_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact) {
+  static_assert(std::is_base_of<T2, T1>::value, "");
+  if (!this_one->is_loaded() || !other->is_loaded()) {
     return true;
   }
 
-  if (other->isa_aryklassptr()) {
-    return !this_exact && (_klass->equals(ciEnv::current()->Object_klass()) || _klass->is_interface());
+  if (this_one->is_array_type(other)) {
+    return !this_exact && this_one->_klass->equals(ciEnv::current()->Object_klass())  && other->_interfaces.contains(this_one->_interfaces);
   }
 
-  if ((_klass->is_interface() && !this_exact) || (other->klass()->is_interface() /*&& !other_exact*/)) {
-    return true;
-  }
-
-  assert(other->isa_instklassptr(), "unsupported");
+  assert(this_one->is_instance_type(other), "unsupported");
 
   if (this_exact && other_exact) {
-    return is_java_subtype_of(other);
+    return this_one->is_java_subtype_of(other);
   }
 
-  if (!_klass->is_subtype_of(other->_klass) && !other->_klass->is_subtype_of(_klass)) {
+  if (!this_one->_klass->is_subtype_of(other->_klass) && !other->_klass->is_subtype_of(this_one->_klass)) {
     return false;
   }
 
   if (this_exact) {
-    return _klass->is_subtype_of(other->_klass);
+    return this_one->_klass->is_subtype_of(other->_klass) && this_one->_interfaces.contains(other->_interfaces);
   }
 
   return true;
 }
 
+bool TypeInstKlassPtr::maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const {
+  return TypePtr::maybe_java_subtype_of_helper_for_instance(this, other, this_exact, other_exact);
+}
+
+const TypeKlassPtr* TypeInstKlassPtr::try_improve() const {
+  if (!UseUniqueSubclasses) {
+    return this;
+  }
+  ciKlass* k = klass();
+  Compile* C = Compile::current();
+  Dependencies* deps = C->dependencies();
+  assert((deps != NULL) == (C->method() != NULL && C->method()->code_size() > 0), "sanity");
+  TypePtr::InterfaceSet interfaces = _interfaces;
+  if (k->is_loaded()) {
+    ciInstanceKlass* ik = k->as_instance_klass();
+    bool klass_is_exact = ik->is_final();
+    if (!klass_is_exact &&
+        deps != NULL) {
+      ciInstanceKlass* sub = ik->unique_concrete_subklass();
+      if (sub != NULL) {
+        ciKlass *sub_k = sub;
+        TypePtr::InterfaceSet sub_interfaces = TypePtr::interfaces(sub_k, true, false, false, ignore_interfaces);
+        assert(sub_k == sub, "");
+        if (sub_interfaces.eq(_interfaces)) {
+          deps->assert_abstract_with_unique_concrete_subtype(ik, sub);
+          k = ik = sub;
+          klass_is_exact = sub->is_final();
+          return TypeKlassPtr::make(klass_is_exact ? Constant : _ptr, k, _offset);
+        }
+      }
+    }
+  }
+  return this;
+}
+
+
 const TypeAryKlassPtr *TypeAryKlassPtr::make(PTR ptr, const Type* elem, ciKlass* k, int offset) {
   return (TypeAryKlassPtr*)(new TypeAryKlassPtr(ptr, elem, k, offset))->hashcons();
 }
 
-const TypeAryKlassPtr *TypeAryKlassPtr::make(PTR ptr, ciKlass* klass, int offset) {
-  if (klass->is_obj_array_klass()) {
+const TypeAryKlassPtr *TypeAryKlassPtr::make(PTR ptr, ciKlass* k, int offset, InterfaceHandling interface_handling) {
+  if (k->is_obj_array_klass()) {
     // Element is an object array. Recursively call ourself.
-    ciKlass* eklass = klass->as_obj_array_klass()->element_klass();
-    const TypeKlassPtr *etype = TypeKlassPtr::make(eklass)->cast_to_exactness(false);
+    ciKlass* eklass = k->as_obj_array_klass()->element_klass();
+    const TypeKlassPtr *etype = TypeKlassPtr::make(eklass, interface_handling)->cast_to_exactness(false);
     return TypeAryKlassPtr::make(ptr, etype, NULL, offset);
-  } else if (klass->is_type_array_klass()) {
+  } else if (k->is_type_array_klass()) {
     // Element is an typeArray
-    const Type* etype = get_const_basic_type(klass->as_type_array_klass()->element_type());
-    return TypeAryKlassPtr::make(ptr, etype, klass, offset);
+    const Type* etype = get_const_basic_type(k->as_type_array_klass()->element_type());
+    return TypeAryKlassPtr::make(ptr, etype, k, offset);
   } else {
     ShouldNotReachHere();
     return NULL;
   }
 }
 
-const TypeAryKlassPtr* TypeAryKlassPtr::make(ciKlass* klass) {
-  return TypeAryKlassPtr::make(Constant, klass, 0);
+const TypeAryKlassPtr* TypeAryKlassPtr::make(ciKlass* klass, InterfaceHandling interface_handling) {
+  return TypeAryKlassPtr::make(Constant, klass, 0, interface_handling);
 }
 
 //------------------------------eq---------------------------------------------
@@ -5756,14 +5965,9 @@ ciKlass* TypeAryPtr::compute_klass(DEBUG_ONLY(bool verify)) const {
 
   // Get element klass
   if ((tinst = el->isa_instptr()) != NULL) {
-    // Compute array klass from element klass
-    k_ary = ciObjArrayKlass::make(tinst->klass());
+    // Leave k_ary at NULL.
   } else if ((tary = el->isa_aryptr()) != NULL) {
-    // Compute array klass from element klass
-    ciKlass* k_elem = tary->klass();
-    // If element type is something like bottom[], k_elem will be null.
-    if (k_elem != NULL)
-      k_ary = ciObjArrayKlass::make(k_elem);
+    // Leave k_ary at NULL.
   } else if ((el->base() == Type::Top) ||
              (el->base() == Type::Bottom)) {
     // element type of Bottom occurs from meet of basic type
@@ -5821,15 +6025,11 @@ ciKlass* TypeAryPtr::klass() const {
     // a bit less efficient than caching, but calls to
     // TypeAryPtr::OOPS->klass() are not common enough to matter.
     ((TypeAryPtr*)this)->_klass = k_ary;
-    if (UseCompressedOops && k_ary != NULL && k_ary->is_obj_array_klass() &&
-        _offset != 0 && _offset != arrayOopDesc::length_offset_in_bytes() &&
-        _offset != arrayOopDesc::klass_offset_in_bytes()) {
-      ((TypeAryPtr*)this)->_is_ptr_to_narrowoop = true;
-    }
   }
   return k_ary;
 }
 
+// Is there a single ciKlass* that can represent that type?
 ciKlass* TypeAryPtr::exact_klass_helper() const {
   if (_ary->_elem->make_ptr() && _ary->_elem->make_ptr()->isa_oopptr()) {
     ciKlass* k = _ary->_elem->make_ptr()->is_oopptr()->exact_klass_helper();
@@ -5855,7 +6055,7 @@ const Type* TypeAryPtr::base_element_type(int& dims) const {
 
 //------------------------------add_offset-------------------------------------
 // Access internals of klass object
-const TypePtr *TypeAryKlassPtr::add_offset(intptr_t offset) const {
+const TypePtr* TypeAryKlassPtr::add_offset(intptr_t offset) const {
   return make(_ptr, elem(), klass(), xadd_offset(offset));
 }
 
@@ -5985,7 +6185,7 @@ const Type    *TypeAryKlassPtr::xmeet( const Type *t ) const {
     PTR ptr = meet_ptr(tap->ptr());
     ciKlass* res_klass = NULL;
     bool res_xk = false;
-    meet_aryptr(ptr, elem, this->klass(), tap->klass(), this->klass_is_exact(), tap->klass_is_exact(), this->ptr(), tap->ptr(), res_klass, res_xk);
+    meet_aryptr(ptr, elem, this, tap, res_klass, res_xk);
     assert(res_xk == (ptr == Constant), "");
     return make(ptr, elem, res_klass, off);
   } // End of case KlassPtr
@@ -5993,6 +6193,9 @@ const Type    *TypeAryKlassPtr::xmeet( const Type *t ) const {
     const TypeInstKlassPtr *tp = t->is_instklassptr();
     int offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
+    InterfaceSet interfaces = meet_interfaces(tp);
+    InterfaceSet tp_interfaces = tp->_interfaces;
+    InterfaceSet this_interfaces = _interfaces;
 
     switch (ptr) {
     case TopPTR:
@@ -6000,12 +6203,13 @@ const Type    *TypeAryKlassPtr::xmeet( const Type *t ) const {
       // For instances when a subclass meets a superclass we fall
       // below the centerline when the superclass is exact. We need to
       // do the same here.
-      if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) {
+      if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces.intersection_with(tp_interfaces).eq(tp_interfaces) && !tp->klass_is_exact()) {
         return TypeAryKlassPtr::make(ptr, _elem, _klass, offset);
       } else {
         // cannot subclass, so the meet has to fall badly below the centerline
         ptr = NotNull;
-        return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), offset);
+        interfaces = this_interfaces.intersection_with(tp->_interfaces);
+        return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, offset);
       }
     case Constant:
     case NotNull:
@@ -6017,7 +6221,7 @@ const Type    *TypeAryKlassPtr::xmeet( const Type *t ) const {
         // For instances when a subclass meets a superclass we fall
         // below the centerline when the superclass is exact. We need
         // to do the same here.
-        if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) {
+        if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces.intersection_with(tp_interfaces).eq(tp_interfaces) && !tp->klass_is_exact()) {
           // that is, my array type is a subtype of 'tp' klass
           return make(ptr, _elem, _klass, offset);
         }
@@ -6026,7 +6230,8 @@ const Type    *TypeAryKlassPtr::xmeet( const Type *t ) const {
       // The meet falls down to Object class below centerline.
       if (ptr == Constant)
          ptr = NotNull;
-      return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), offset);
+      interfaces = this_interfaces.intersection_with(tp_interfaces);
+      return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, offset);
     default: typerr(t);
     }
   }
@@ -6035,70 +6240,116 @@ const Type    *TypeAryKlassPtr::xmeet( const Type *t ) const {
   return this;                  // Return the double constant
 }
 
-bool TypeAryKlassPtr::is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const {
-  if (other->klass() == ciEnv::current()->Object_klass() && other_exact) {
+template <class T1, class T2> bool TypePtr::is_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact) {
+  static_assert(std::is_base_of<T2, T1>::value, "");
+
+  if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces.empty() && other_exact) {
     return true;
   }
 
-  if (!is_loaded() || !other->is_loaded() || other->klass() == NULL || klass() == NULL) {
+  int dummy;
+  bool this_top_or_bottom = (this_one->base_element_type(dummy) == Type::TOP || this_one->base_element_type(dummy) == Type::BOTTOM);
+
+  if (!this_one->is_loaded() || !other->is_loaded() || this_top_or_bottom) {
     return false;
   }
-  if (other->isa_instklassptr()) {
-    return _klass->is_subtype_of(other->_klass) && other_exact;
+
+  if (this_one->is_instance_type(other)) {
+    return other->klass() == ciEnv::current()->Object_klass() && other->_interfaces.intersection_with(this_one->_interfaces).eq(other->_interfaces) && other_exact;
   }
-  if (klass() == NULL) {
+
+  assert(this_one->is_array_type(other), "");
+  const T1* other_ary = this_one->is_array_type(other);
+  bool other_top_or_bottom = (other_ary->base_element_type(dummy) == Type::TOP || other_ary->base_element_type(dummy) == Type::BOTTOM);
+  if (other_top_or_bottom) {
     return false;
   }
-  assert(other->isa_aryklassptr(), "");
-  const TypeAryKlassPtr* other_ary = other->isa_aryklassptr();
-  if (other_ary->_elem->isa_klassptr() && _elem->isa_klassptr()) {
-    return _elem->is_klassptr()->is_java_subtype_of_helper(other_ary->_elem->is_klassptr(), this_exact, other_exact);
+
+  const TypePtr* other_elem = other_ary->elem()->make_ptr();
+  const TypePtr* this_elem = this_one->elem()->make_ptr();
+  if (this_elem != NULL && other_elem != NULL) {
+    return this_one->is_reference_type(this_elem)->is_java_subtype_of_helper(this_one->is_reference_type(other_elem), this_exact, other_exact);
   }
-  if (!other_ary->_elem->isa_klassptr() && !_elem->isa_klassptr()) {
-    return _klass->is_subtype_of(other->_klass);
+  if (this_elem == NULL && other_elem == NULL) {
+    return this_one->_klass->is_subtype_of(other->_klass);
   }
   return false;
 }
 
-bool TypeAryKlassPtr::is_same_java_type_as(const TypeKlassPtr* other) const {
-  if (!other->isa_aryklassptr() ||
-      !is_loaded() || !other->is_loaded() || klass() == NULL || other->klass() == NULL) {
+bool TypeAryKlassPtr::is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const {
+  return TypePtr::is_java_subtype_of_helper_for_array(this, other, this_exact, other_exact);
+}
+
+template <class T1, class T2> bool TypePtr::is_same_java_type_as_helper_for_array(const T1* this_one, const T2* other) {
+  static_assert(std::is_base_of<T2, T1>::value, "");
+
+  int dummy;
+  bool this_top_or_bottom = (this_one->base_element_type(dummy) == Type::TOP || this_one->base_element_type(dummy) == Type::BOTTOM);
+
+  if (!this_one->is_array_type(other) ||
+      !this_one->is_loaded() || !other->is_loaded() || this_top_or_bottom) {
     return false;
   }
-  const TypeAryKlassPtr* other_ary = other->isa_aryklassptr();
-  if (other_ary->_elem->isa_klassptr() && _elem->isa_klassptr()) {
-    return _elem->is_klassptr()->is_same_java_type_as(other_ary->_elem->is_klassptr());
+  const T1* other_ary = this_one->is_array_type(other);
+  bool other_top_or_bottom = (other_ary->base_element_type(dummy) == Type::TOP || other_ary->base_element_type(dummy) == Type::BOTTOM);
+
+  if (other_top_or_bottom) {
+    return false;
   }
-  if (!other_ary->_elem->isa_klassptr() && !_elem->isa_klassptr()) {
-    return _klass->equals(other->_klass);
+
+  const TypePtr* other_elem = other_ary->elem()->make_ptr();
+  const TypePtr* this_elem = this_one->elem()->make_ptr();
+  if (other_elem != NULL && this_elem != NULL) {
+    return this_one->is_reference_type(this_elem)->is_same_java_type_as(this_one->is_reference_type(other_elem));
+  }
+  if (other_elem == NULL && this_elem == NULL) {
+    assert(this_one->_klass != NULL && other->_klass != NULL, "");
+    return this_one->_klass->equals(other->_klass);
+  }
+  return false;
+}
+
+bool TypeAryKlassPtr::is_same_java_type_as_helper(const TypeKlassPtr* other) const {
+  return TypePtr::is_same_java_type_as_helper_for_array(this, other);
+}
+
+template <class T1, class T2> bool TypePtr::maybe_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact) {
+  static_assert(std::is_base_of<T2, T1>::value, "");
+  if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces.empty() && other_exact) {
+    return true;
+  }
+  int dummy;
+  bool this_top_or_bottom = (this_one->base_element_type(dummy) == Type::TOP || this_one->base_element_type(dummy) == Type::BOTTOM);
+  if (!this_one->is_loaded() || !other->is_loaded() || this_top_or_bottom) {
+    return true;
+  }
+  if (this_one->is_instance_type(other)) {
+    return other->_klass->equals(ciEnv::current()->Object_klass()) && other->_interfaces.intersection_with(this_one->_interfaces).eq(other->_interfaces);
+  }
+  assert(this_one->is_array_type(other), "");
+
+  const T1* other_ary = this_one->is_array_type(other);
+  bool other_top_or_bottom = (other_ary->base_element_type(dummy) == Type::TOP || other_ary->base_element_type(dummy) == Type::BOTTOM);
+  if (other_top_or_bottom) {
+    return true;
+  }
+  if (this_exact && other_exact) {
+    return this_one->is_java_subtype_of(other);
+  }
+
+  const TypePtr* this_elem = this_one->elem()->make_ptr();
+  const TypePtr* other_elem = other_ary->elem()->make_ptr();
+  if (other_elem != NULL && this_elem != NULL) {
+    return this_one->is_reference_type(this_elem)->maybe_java_subtype_of_helper(this_one->is_reference_type(other_elem), this_exact, other_exact);
+  }
+  if (other_elem == NULL && this_elem == NULL) {
+    return this_one->_klass->is_subtype_of(other->_klass);
   }
   return false;
 }
 
 bool TypeAryKlassPtr::maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const {
-  if (other->klass() == ciEnv::current()->Object_klass()) {
-    return true;
-  }
-  if (!is_loaded() || !other->is_loaded() || klass() == NULL || other->klass() == NULL) {
-    return true;
-  }
-  if (other->isa_instklassptr()) {
-    return (!other_exact && other->_klass->is_interface()) || _klass->is_subtype_of(other->_klass);
-  }
-  assert(other->isa_aryklassptr(), "");
-
-  if (this_exact && other_exact) {
-    return is_java_subtype_of(other);
-  }
-
-  const TypeAryKlassPtr* other_ary = other->isa_aryklassptr();
-  if (other_ary->_elem->isa_klassptr() && _elem->isa_klassptr()) {
-    return _elem->is_klassptr()->maybe_java_subtype_of_helper(other_ary->_elem->is_klassptr(), this_exact, other_exact);
-  }
-  if (!other_ary->_elem->isa_klassptr() && !_elem->isa_klassptr()) {
-    return _klass->is_subtype_of(other->_klass);
-  }
-  return false;
+  return TypePtr::maybe_java_subtype_of_helper_for_array(this, other, this_exact, other_exact);
 }
 
 //------------------------------xdual------------------------------------------
@@ -6107,7 +6358,7 @@ const Type    *TypeAryKlassPtr::xdual() const {
   return new TypeAryKlassPtr(dual_ptr(), elem()->dual(), klass(), dual_offset());
 }
 
-//------------------------------get_con----------------------------------------
+// Is there a single ciKlass* that can represent that type?
 ciKlass* TypeAryKlassPtr::exact_klass_helper() const {
   if (elem()->isa_klassptr()) {
     ciKlass* k = elem()->is_klassptr()->exact_klass_helper();
@@ -6127,15 +6378,12 @@ ciKlass* TypeAryKlassPtr::klass() const {
   }
   ciKlass* k = NULL;
   if (elem()->isa_klassptr()) {
-    k = elem()->is_klassptr()->klass();
-    if (k != NULL) {
-      k = ciObjArrayKlass::make(k);
-      ((TypeAryKlassPtr*)this)->_klass = k;
-    }
+    // leave NULL
   } else if ((elem()->base() == Type::Top) ||
              (elem()->base() == Type::Bottom)) {
   } else {
     k = ciTypeArrayKlass::make(elem()->basic_type());
+    ((TypeAryKlassPtr*)this)->_klass = k;
   }
   return k;
 }
@@ -6151,6 +6399,7 @@ void TypeAryKlassPtr::dump2( Dict & d, uint depth, outputStream *st ) const {
     {
       st->print("[");
       _elem->dump2(d, depth, st);
+      _interfaces.dump(st);
       st->print(": ");
     }
   case BotPTR:
@@ -6199,11 +6448,11 @@ const TypeFunc *TypeFunc::make(ciMethod* method) {
   if (tf != NULL)  return tf;  // The hit rate here is almost 50%.
   const TypeTuple *domain;
   if (method->is_static()) {
-    domain = TypeTuple::make_domain(NULL, method->signature());
+    domain = TypeTuple::make_domain(NULL, method->signature(), ignore_interfaces);
   } else {
-    domain = TypeTuple::make_domain(method->holder(), method->signature());
+    domain = TypeTuple::make_domain(method->holder(), method->signature(), ignore_interfaces);
   }
-  const TypeTuple *range  = TypeTuple::make_range(method->signature());
+  const TypeTuple *range  = TypeTuple::make_range(method->signature(), ignore_interfaces);
   tf = TypeFunc::make(domain, range);
   C->set_last_tf(method, tf);  // fill cache
   return tf;
diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp
index bd5fe8c9d6b..8bd36f66613 100644
--- a/src/hotspot/share/opto/type.hpp
+++ b/src/hotspot/share/opto/type.hpp
@@ -168,10 +168,6 @@ private:
   // lazily, on demand, and cached in _dual.
   const Type *_dual;            // Cached dual value
 
-#ifdef ASSERT
-  // One type is interface, the other is oop
-  virtual bool interface_vs_oop_helper(const Type *t) const;
-#endif
 
   const Type *meet_helper(const Type *t, bool include_speculative) const;
   void check_symmetrical(const Type *t, const Type *mt) const;
@@ -260,7 +256,6 @@ public:
 
   // Modified version of JOIN adapted to the needs Node::Value.
   // Normalizes all empty values to TOP.  Does not kill _widen bits.
-  // Currently, it also works around limitations involving interface types.
   // Variant that drops the speculative part of the types
   const Type *filter(const Type *kills) const {
     return filter_helper(kills, false);
@@ -270,11 +265,6 @@ public:
     return filter_helper(kills, true)->cleanup_speculative();
   }
 
-#ifdef ASSERT
-  // One type is interface, the other is oop
-  virtual bool interface_vs_oop(const Type *t) const;
-#endif
-
   // Returns true if this pointer points at memory which contains a
   // compressed oop references.
   bool is_ptr_to_narrowoop() const;
@@ -404,8 +394,12 @@ public:
   // Mapping to the array element's basic type.
   BasicType array_element_basic_type() const;
 
+  enum InterfaceHandling {
+      trust_interfaces,
+      ignore_interfaces
+  };
   // Create standard type for a ciType:
-  static const Type* get_const_type(ciType* type);
+  static const Type* get_const_type(ciType* type, InterfaceHandling interface_handling = ignore_interfaces);
 
   // Create standard zero value:
   static const Type* get_zero_type(BasicType type) {
@@ -724,8 +718,8 @@ public:
   }
 
   static const TypeTuple *make( uint cnt, const Type **fields );
-  static const TypeTuple *make_range(ciSignature *sig);
-  static const TypeTuple *make_domain(ciInstanceKlass* recv, ciSignature *sig);
+  static const TypeTuple *make_range(ciSignature *sig, InterfaceHandling interface_handling = ignore_interfaces);
+  static const TypeTuple *make_domain(ciInstanceKlass* recv, ciSignature *sig, InterfaceHandling interface_handling);
 
   // Subroutine call type with space allocated for argument types
   // Memory for Control, I_O, Memory, FramePtr, and ReturnAdr is allocated implicitly
@@ -776,10 +770,6 @@ public:
   bool ary_must_be_exact() const;  // true if arrays of such are never generic
   virtual const TypeAry* remove_speculative() const;
   virtual const Type* cleanup_speculative() const;
-#ifdef ASSERT
-  // One type is interface, the other is oop
-  virtual bool interface_vs_oop(const Type *t) const;
-#endif
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint, outputStream *st  ) const; // Specialized per-Type dumping
 #endif
@@ -885,6 +875,52 @@ public:
 // and the class will be inherited from.
 class TypePtr : public Type {
   friend class TypeNarrowPtr;
+  friend class Type;
+protected:
+  class InterfaceSet {
+  private:
+    GrowableArray<ciKlass*> _list;
+    void raw_add(ciKlass* interface);
+    void add(ciKlass* interface);
+    void verify() const;
+    int _hash_computed:1;
+    int _exact_klass_computed:1;
+    int _is_loaded_computed:1;
+    int _hash;
+    ciKlass* _exact_klass;
+    bool _is_loaded;
+    void compute_hash();
+    void compute_exact_klass();
+  public:
+    InterfaceSet();
+    InterfaceSet(GrowableArray<ciInstanceKlass*>* interfaces);
+    bool eq(const InterfaceSet& other) const;
+    int hash() const;
+    void dump(outputStream *st) const;
+    InterfaceSet union_with(const InterfaceSet& other) const;
+    InterfaceSet intersection_with(const InterfaceSet& other) const;
+    bool contains(const InterfaceSet& other) const {
+      return intersection_with(other).eq(other);
+    }
+    bool empty() const { return _list.length() == 0; }
+
+    inline void* operator new(size_t x) throw() {
+      Compile* compile = Compile::current();
+      return compile->type_arena()->AmallocWords(x);
+    }
+    inline void operator delete( void* ptr ) {
+      ShouldNotReachHere();
+    }
+    ciKlass* exact_klass() const;
+    bool is_loaded() const;
+
+    static int compare(ciKlass* const &, ciKlass* const & k2);
+
+    void compute_is_loaded();
+  };
+
+  static InterfaceSet interfaces(ciKlass*& k, bool klass, bool interface, bool array, InterfaceHandling interface_handling);
+
 public:
   enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR };
 protected:
@@ -943,12 +979,20 @@ protected:
     NOT_SUBTYPE,
     LCA
   };
-  static MeetResult
-  meet_instptr(PTR &ptr, ciKlass* this_klass, ciKlass* tinst_klass, bool this_xk, bool tinst_xk, PTR this_ptr,
-               PTR tinst_ptr, ciKlass*&res_klass, bool &res_xk);
-  static MeetResult
-  meet_aryptr(PTR& ptr, const Type*& elem, ciKlass* this_klass, ciKlass* tap_klass, bool this_xk, bool tap_xk, PTR this_ptr, PTR tap_ptr, ciKlass*& res_klass, bool& res_xk);
+  template<class T> static TypePtr::MeetResult meet_instptr(PTR& ptr, InterfaceSet& interfaces, const T* this_type,
+                                                            const T* other_type, ciKlass*& res_klass, bool& res_xk);
 
+  template<class T> static MeetResult meet_aryptr(PTR& ptr, const Type*& elem, const T* this_ary, const T* other_ary,
+                                                  ciKlass*& res_klass, bool& res_xk);
+
+  template <class T1, class T2> static bool is_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
+  template <class T1, class T2> static bool is_same_java_type_as_helper_for_instance(const T1* this_one, const T2* other);
+  template <class T1, class T2> static bool maybe_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
+  template <class T1, class T2> static bool is_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
+  template <class T1, class T2> static bool is_same_java_type_as_helper_for_array(const T1* this_one, const T2* other);
+  template <class T1, class T2> static bool maybe_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
+  template <class T1, class T2> static bool is_meet_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_xk, bool other_xk);
+  template <class T1, class T2> static bool is_meet_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_xk, bool other_xk);
 public:
   const int _offset;            // Offset into oop, with TOP & BOT
   const PTR _ptr;               // Pointer equivalence class
@@ -1057,7 +1101,7 @@ class TypeOopPtr : public TypePtr {
   friend class TypeInstPtr;
   friend class TypeAryPtr;
 protected:
-  TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id,
+ TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset, int instance_id,
              const TypePtr* speculative, int inline_depth);
 public:
   virtual bool eq( const Type *t ) const;
@@ -1073,6 +1117,9 @@ protected:
   ciObject*     _const_oop;   // Constant oop
   // If _klass is NULL, then so is _sig.  This is an unloaded klass.
   ciKlass*      _klass;       // Klass object
+
+  const InterfaceSet _interfaces;
+
   // Does the type exclude subclasses of the klass?  (Inexact == polymorphic.)
   bool          _klass_is_exact;
   bool          _is_ptr_to_narrowoop;
@@ -1084,11 +1131,13 @@ protected:
   // This is the node index of the allocation node creating this instance.
   int           _instance_id;
 
-  static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact);
+  static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact, InterfaceHandling interface_handling);
 
   int dual_instance_id() const;
   int meet_instance_id(int uid) const;
 
+  InterfaceSet meet_interfaces(const TypeOopPtr* other) const;
+
   // Do not allow interface-vs.-noninterface joins to collapse to top.
   virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
 
@@ -1100,7 +1149,15 @@ public:
   bool is_java_subtype_of(const TypeOopPtr* other) const {
     return is_java_subtype_of_helper(other, klass_is_exact(), other->klass_is_exact());
   }
-  virtual bool is_same_java_type_as(const TypeOopPtr* other) const { ShouldNotReachHere(); return false; }
+
+  bool is_same_java_type_as(const TypePtr* other) const {
+    return is_same_java_type_as_helper(other->is_oopptr());
+  }
+
+  virtual bool is_same_java_type_as_helper(const TypeOopPtr* other) const {
+    ShouldNotReachHere(); return false;
+  }
+
   bool maybe_java_subtype_of(const TypeOopPtr* other) const {
     return maybe_java_subtype_of_helper(other, klass_is_exact(), other->klass_is_exact());
   }
@@ -1111,18 +1168,18 @@ public:
   // Creates a type given a klass. Correctly handles multi-dimensional arrays
   // Respects UseUniqueSubclasses.
   // If the klass is final, the resulting type will be exact.
-  static const TypeOopPtr* make_from_klass(ciKlass* klass) {
-    return make_from_klass_common(klass, true, false);
+  static const TypeOopPtr* make_from_klass(ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces) {
+    return make_from_klass_common(klass, true, false, interface_handling);
   }
   // Same as before, but will produce an exact type, even if
   // the klass is not final, as long as it has exactly one implementation.
-  static const TypeOopPtr* make_from_klass_unique(ciKlass* klass) {
-    return make_from_klass_common(klass, true, true);
+  static const TypeOopPtr* make_from_klass_unique(ciKlass* klass, InterfaceHandling interface_handling= ignore_interfaces) {
+    return make_from_klass_common(klass, true, true, interface_handling);
   }
   // Same as before, but does not respects UseUniqueSubclasses.
   // Use this only for creating array element types.
-  static const TypeOopPtr* make_from_klass_raw(ciKlass* klass) {
-    return make_from_klass_common(klass, false, false);
+  static const TypeOopPtr* make_from_klass_raw(ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces) {
+    return make_from_klass_common(klass, false, false, interface_handling);
   }
   // Creates a singleton type given an object.
   // If the object cannot be rendered as a constant,
@@ -1141,8 +1198,8 @@ public:
   ciKlass* exact_klass(bool maybe_null = false) const { assert(klass_is_exact(), ""); ciKlass* k = exact_klass_helper(); assert(k != NULL || maybe_null, ""); return k;  }
   ciKlass* unloaded_klass() const { assert(!is_loaded(), "only for unloaded types"); return klass(); }
 
-  virtual bool  is_loaded() const { return klass()->is_loaded(); }
-  bool klass_is_exact()    const { return _klass_is_exact; }
+  virtual bool  is_loaded() const { return klass()->is_loaded() && _interfaces.is_loaded(); }
+  virtual bool klass_is_exact()    const { return _klass_is_exact; }
 
   // Returns true if this pointer points at memory which contains a
   // compressed oop references.
@@ -1184,13 +1241,37 @@ public:
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
 #endif
+private:
+  virtual bool is_meet_subtype_of(const TypePtr* other) const {
+    return is_meet_subtype_of_helper(other->is_oopptr(), klass_is_exact(), other->is_oopptr()->klass_is_exact());
+  }
+
+  virtual bool is_meet_subtype_of_helper(const TypeOopPtr* other, bool this_xk, bool other_xk) const {
+    ShouldNotReachHere(); return false;
+  }
+
+  virtual const InterfaceSet interfaces() const {
+    return _interfaces;
+  };
+
+  const TypeOopPtr* is_reference_type(const Type* other) const {
+    return other->isa_oopptr();
+  }
+
+  const TypeAryPtr* is_array_type(const TypeOopPtr* other) const {
+    return other->isa_aryptr();
+  }
+
+  const TypeInstPtr* is_instance_type(const TypeOopPtr* other) const {
+    return other->isa_instptr();
+  }
 };
 
 //------------------------------TypeInstPtr------------------------------------
 // Class of Java object pointers, pointing either to non-array Java instances
 // or to a Klass* (including array klasses).
 class TypeInstPtr : public TypeOopPtr {
-  TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id,
+  TypeInstPtr(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset, int instance_id,
               const TypePtr* speculative, int inline_depth);
   virtual bool eq( const Type *t ) const;
   virtual int  hash() const;             // Type specific hashing
@@ -1201,46 +1282,55 @@ public:
 
   // Instance klass, ignoring any interface
   ciInstanceKlass* instance_klass() const {
-    if (klass()->is_loaded() && klass()->is_interface()) {
-      return Compile::current()->env()->Object_klass();
-    }
+    assert(!(klass()->is_loaded() && klass()->is_interface()), "");
     return klass()->as_instance_klass();
   }
 
-  bool is_same_java_type_as(const TypeOopPtr* other) const;
+  bool is_same_java_type_as_helper(const TypeOopPtr* other) const;
   bool is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const;
   bool maybe_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const;
 
   // Make a pointer to a constant oop.
   static const TypeInstPtr *make(ciObject* o) {
-    return make(TypePtr::Constant, o->klass(), true, o, 0, InstanceBot);
+    ciKlass* k = o->klass();
+    const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
+    return make(TypePtr::Constant, k, interfaces, true, o, 0, InstanceBot);
   }
   // Make a pointer to a constant oop with offset.
   static const TypeInstPtr *make(ciObject* o, int offset) {
-    return make(TypePtr::Constant, o->klass(), true, o, offset, InstanceBot);
+    ciKlass* k = o->klass();
+    const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
+    return make(TypePtr::Constant, k, interfaces, true, o, offset, InstanceBot);
   }
 
   // Make a pointer to some value of type klass.
-  static const TypeInstPtr *make(PTR ptr, ciKlass* klass) {
-    return make(ptr, klass, false, NULL, 0, InstanceBot);
+  static const TypeInstPtr *make(PTR ptr, ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces) {
+    const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling);
+    return make(ptr, klass, interfaces, false, NULL, 0, InstanceBot);
   }
 
   // Make a pointer to some non-polymorphic value of exactly type klass.
   static const TypeInstPtr *make_exact(PTR ptr, ciKlass* klass) {
-    return make(ptr, klass, true, NULL, 0, InstanceBot);
+    const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, false, false, ignore_interfaces);
+    return make(ptr, klass, interfaces, true, NULL, 0, InstanceBot);
   }
 
   // Make a pointer to some value of type klass with offset.
   static const TypeInstPtr *make(PTR ptr, ciKlass* klass, int offset) {
-    return make(ptr, klass, false, NULL, offset, InstanceBot);
+    const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, false, false, ignore_interfaces);
+    return make(ptr, klass, interfaces, false, NULL, offset, InstanceBot);
   }
 
-  // Make a pointer to an oop.
-  static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset,
+  static const TypeInstPtr *make(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset,
                                  int instance_id = InstanceBot,
                                  const TypePtr* speculative = NULL,
                                  int inline_depth = InlineDepthBottom);
 
+  static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot) {
+    const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
+    return make(ptr, k, interfaces, xk, o, offset, instance_id);
+  }
+
   /** Create constant type for a constant boxed value */
   const Type* get_const_boxed_value() const;
 
@@ -1265,13 +1355,11 @@ public:
 
   // the core of the computation of the meet of 2 types
   virtual const Type *xmeet_helper(const Type *t) const;
-  virtual const TypeInstPtr *xmeet_unloaded( const TypeInstPtr *t ) const;
+  virtual const TypeInstPtr *xmeet_unloaded(const TypeInstPtr *t, const InterfaceSet& interfaces) const;
   virtual const Type *xdual() const;    // Compute dual right now.
 
   const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const;
 
-  bool is_interface() const { return is_loaded() && klass()->is_interface(); }
-
   // Convenience common pre-built types.
   static const TypeInstPtr *NOTNULL;
   static const TypeInstPtr *BOTTOM;
@@ -1281,34 +1369,38 @@ public:
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
 #endif
+
+private:
+  virtual bool is_meet_subtype_of_helper(const TypeOopPtr* other, bool this_xk, bool other_xk) const;
+
+  virtual bool is_meet_same_type_as(const TypePtr* other) const {
+    return _klass->equals(other->is_instptr()->_klass) && _interfaces.eq(other->is_instptr()->_interfaces);
+  }
+
 };
 
 //------------------------------TypeAryPtr-------------------------------------
 // Class of Java array pointers
 class TypeAryPtr : public TypeOopPtr {
+  friend class Type;
+  friend class TypePtr;
+
   TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk,
               int offset, int instance_id, bool is_autobox_cache,
               const TypePtr* speculative, int inline_depth)
-    : TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative, inline_depth),
+    : TypeOopPtr(AryPtr,ptr,k,*_array_interfaces,xk,o,offset, instance_id, speculative, inline_depth),
     _ary(ary),
     _is_autobox_cache(is_autobox_cache)
  {
-#ifdef ASSERT
-    if (k != NULL) {
-      // Verify that specified klass and TypeAryPtr::klass() follow the same rules.
-      ciKlass* ck = compute_klass(true);
-      if (k != ck) {
-        this->dump(); tty->cr();
-        tty->print(" k: ");
-        k->print(); tty->cr();
-        tty->print("ck: ");
-        if (ck != NULL) ck->print();
-        else tty->print("<NULL>");
-        tty->cr();
-        assert(false, "unexpected TypeAryPtr::_klass");
-      }
+    int dummy;
+    bool top_or_bottom = (base_element_type(dummy) == Type::TOP || base_element_type(dummy) == Type::BOTTOM);
+
+    if (UseCompressedOops && (elem()->make_oopptr() != NULL && !top_or_bottom) &&
+        _offset != 0 && _offset != arrayOopDesc::length_offset_in_bytes() &&
+        _offset != arrayOopDesc::klass_offset_in_bytes()) {
+      _is_ptr_to_narrowoop = true;
     }
-#endif
+
   }
   virtual bool eq( const Type *t ) const;
   virtual int hash() const;     // Type specific hashing
@@ -1317,12 +1409,16 @@ class TypeAryPtr : public TypeOopPtr {
 
   ciKlass* compute_klass(DEBUG_ONLY(bool verify = false)) const;
 
+  // A pointer to delay allocation to Type::Initialize_shared()
+
+  static const InterfaceSet* _array_interfaces;
   ciKlass* exact_klass_helper() const;
+  // Only guaranteed non null for array of basic types
   ciKlass* klass() const;
 
 public:
 
-  bool is_same_java_type_as(const TypeOopPtr* other) const;
+  bool is_same_java_type_as_helper(const TypeOopPtr* other) const;
   bool is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const;
   bool maybe_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const;
 
@@ -1399,13 +1495,11 @@ public:
   }
   static const TypeAryPtr *_array_body_type[T_CONFLICT+1];
   // sharpen the type of an int which is used as an array size
-#ifdef ASSERT
-  // One type is interface, the other is oop
-  virtual bool interface_vs_oop(const Type *t) const;
-#endif
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
 #endif
+private:
+  virtual bool is_meet_subtype_of_helper(const TypeOopPtr* other, bool this_xk, bool other_xk) const;
 };
 
 //------------------------------TypeMetadataPtr-------------------------------------
@@ -1453,8 +1547,9 @@ public:
 class TypeKlassPtr : public TypePtr {
   friend class TypeInstKlassPtr;
   friend class TypeAryKlassPtr;
+  friend class TypePtr;
 protected:
-  TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, int offset);
+  TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const InterfaceSet& interfaces, int offset);
 
   virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
 
@@ -1466,7 +1561,8 @@ public:
 protected:
 
   ciKlass* _klass;
-
+  const InterfaceSet _interfaces;
+  InterfaceSet meet_interfaces(const TypeKlassPtr* other) const;
   virtual bool must_be_exact() const { ShouldNotReachHere(); return false; }
   virtual ciKlass* exact_klass_helper() const;
   virtual ciKlass* klass() const { return  _klass; }
@@ -1476,20 +1572,23 @@ public:
   bool is_java_subtype_of(const TypeKlassPtr* other) const {
     return is_java_subtype_of_helper(other, klass_is_exact(), other->klass_is_exact());
   }
+  bool is_same_java_type_as(const TypePtr* other) const {
+    return is_same_java_type_as_helper(other->is_klassptr());
+  }
+
   bool maybe_java_subtype_of(const TypeKlassPtr* other) const {
     return maybe_java_subtype_of_helper(other, klass_is_exact(), other->klass_is_exact());
   }
-  virtual bool is_same_java_type_as(const TypeKlassPtr* other) const { ShouldNotReachHere(); return false; }
+  virtual bool is_same_java_type_as_helper(const TypeKlassPtr* other) const { ShouldNotReachHere(); return false; }
   virtual bool is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const { ShouldNotReachHere(); return false; }
   virtual bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const { ShouldNotReachHere(); return false; }
 
   // Exact klass, possibly an interface or an array of interface
   ciKlass* exact_klass(bool maybe_null = false) const { assert(klass_is_exact(), ""); ciKlass* k = exact_klass_helper(); assert(k != NULL || maybe_null, ""); return k;  }
+  virtual bool klass_is_exact()    const { return _ptr == Constant; }
 
-  bool klass_is_exact()    const { return _ptr == Constant; }
-
-  static const TypeKlassPtr* make(ciKlass* klass);
-  static const TypeKlassPtr *make(PTR ptr, ciKlass* klass, int offset);
+  static const TypeKlassPtr* make(ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces);
+  static const TypeKlassPtr *make(PTR ptr, ciKlass* klass, int offset, InterfaceHandling interface_handling = ignore_interfaces);
 
   virtual bool  is_loaded() const { return _klass->is_loaded(); }
 
@@ -1508,16 +1607,43 @@ public:
 
   virtual const TypeKlassPtr* with_offset(intptr_t offset) const { ShouldNotReachHere(); return NULL; }
 
+  virtual const TypeKlassPtr* try_improve() const { return this; }
+
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
 #endif
+private:
+  virtual bool is_meet_subtype_of(const TypePtr* other) const {
+    return is_meet_subtype_of_helper(other->is_klassptr(), klass_is_exact(), other->is_klassptr()->klass_is_exact());
+  }
+
+  virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const {
+    ShouldNotReachHere(); return false;
+  }
+
+  virtual const InterfaceSet interfaces() const {
+    return _interfaces;
+  };
+
+  const TypeKlassPtr* is_reference_type(const Type* other) const {
+    return other->isa_klassptr();
+  }
+
+  const TypeAryKlassPtr* is_array_type(const TypeKlassPtr* other) const {
+    return other->isa_aryklassptr();
+  }
+
+  const TypeInstKlassPtr* is_instance_type(const TypeKlassPtr* other) const {
+    return other->isa_instklassptr();
+  }
 };
 
 // Instance klass pointer, mirrors TypeInstPtr
 class TypeInstKlassPtr : public TypeKlassPtr {
 
-  TypeInstKlassPtr(PTR ptr, ciKlass* klass, int offset)
-    : TypeKlassPtr(InstKlassPtr, ptr, klass, offset) {
+  TypeInstKlassPtr(PTR ptr, ciKlass* klass, const InterfaceSet& interfaces, int offset)
+    : TypeKlassPtr(InstKlassPtr, ptr, klass, interfaces, offset) {
+    assert(klass->is_instance_klass() && (!klass->is_loaded() || !klass->is_interface()), "");
   }
 
   virtual bool must_be_exact() const;
@@ -1525,20 +1651,24 @@ class TypeInstKlassPtr : public TypeKlassPtr {
 public:
   // Instance klass ignoring any interface
   ciInstanceKlass* instance_klass() const {
-    if (klass()->is_interface()) {
-      return Compile::current()->env()->Object_klass();
-    }
+    assert(!klass()->is_interface(), "");
     return klass()->as_instance_klass();
   }
 
-  bool is_same_java_type_as(const TypeKlassPtr* other) const;
+  bool is_same_java_type_as_helper(const TypeKlassPtr* other) const;
   bool is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
   bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
 
-  static const TypeInstKlassPtr *make(ciKlass* k) {
-    return make(TypePtr::Constant, k, 0);
+  static const TypeInstKlassPtr *make(ciKlass* k, InterfaceHandling interface_handling) {
+    InterfaceSet interfaces = TypePtr::interfaces(k, true, true, false, interface_handling);
+    return make(TypePtr::Constant, k, interfaces, 0);
+  }
+  static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, int offset);
+
+  static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, int offset) {
+    const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
+    return make(ptr, k, interfaces, offset);
   }
-  static const TypeInstKlassPtr *make(PTR ptr, ciKlass* k, int offset);
 
   virtual const TypeInstKlassPtr* cast_to_ptr_type(PTR ptr) const;
 
@@ -1554,23 +1684,31 @@ public:
   virtual const Type    *xdual() const;
   virtual const TypeInstKlassPtr* with_offset(intptr_t offset) const;
 
-  bool is_interface() const { return klass()->is_interface(); }
+  virtual const TypeKlassPtr* try_improve() const;
 
   // Convenience common pre-built types.
   static const TypeInstKlassPtr* OBJECT; // Not-null object klass or below
   static const TypeInstKlassPtr* OBJECT_OR_NULL; // Maybe-null version of same
+private:
+  virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const;
 };
 
 // Array klass pointer, mirrors TypeAryPtr
 class TypeAryKlassPtr : public TypeKlassPtr {
   friend class TypeInstKlassPtr;
+  friend class Type;
+  friend class TypePtr;
+
   const Type *_elem;
 
+  static const InterfaceSet* _array_interfaces;
   TypeAryKlassPtr(PTR ptr, const Type *elem, ciKlass* klass, int offset)
-    : TypeKlassPtr(AryKlassPtr, ptr, klass, offset), _elem(elem) {
+    : TypeKlassPtr(AryKlassPtr, ptr, klass, *_array_interfaces, offset), _elem(elem) {
+    assert(klass == NULL || klass->is_type_array_klass() || !klass->as_obj_array_klass()->base_element_klass()->is_interface(), "");
   }
 
   virtual ciKlass* exact_klass_helper() const;
+  // Only guaranteed non null for array of basic types
   virtual ciKlass* klass() const;
 
   virtual bool must_be_exact() const;
@@ -1580,16 +1718,16 @@ public:
   // returns base element type, an instance klass (and not interface) for object arrays
   const Type* base_element_type(int& dims) const;
 
-  static const TypeAryKlassPtr *make(PTR ptr, ciKlass* k, int offset);
+  static const TypeAryKlassPtr *make(PTR ptr, ciKlass* k, int offset, InterfaceHandling interface_handling);
 
-  bool is_same_java_type_as(const TypeKlassPtr* other) const;
+  bool is_same_java_type_as_helper(const TypeKlassPtr* other) const;
   bool is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
   bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
 
   bool  is_loaded() const { return (_elem->isa_klassptr() ? _elem->is_klassptr()->is_loaded() : true); }
 
   static const TypeAryKlassPtr *make(PTR ptr, const Type *elem, ciKlass* k, int offset);
-  static const TypeAryKlassPtr* make(ciKlass* klass);
+  static const TypeAryKlassPtr* make(ciKlass* klass, InterfaceHandling interface_handling);
 
   const Type *elem() const { return _elem; }
 
@@ -1616,6 +1754,8 @@ public:
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
 #endif
+private:
+  virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const;
 };
 
 class TypeNarrowPtr : public Type {
diff --git a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java
index 4815a981c76..79433ef355d 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java
@@ -132,7 +132,7 @@ public class CastNullCheckDroppingsTest {
         t.runTest(methodClassCastNull, false, svalue);
         t.runTest(methodNullClassCast, false, svalue);
         t.runTest(methodClassCastObj,  false, svalue);
-        t.runTest(methodObjClassCast,  true,  svalue);
+        t.runTest(methodObjClassCast,  false,  svalue);
         t.runTest(methodClassCastInt,  false, svalue);
         t.runTest(methodIntClassCast,  true,  svalue);
         t.runTest(methodClassCastint,  false, svalue);