From 1d2458db34ed6acdd20bb8c165b7619cdbc32f47 Mon Sep 17 00:00:00 2001
From: Roland Westrelin <roland@openjdk.org>
Date: Tue, 14 Sep 2021 08:35:09 +0000
Subject: [PATCH] 8266550: C2: mirror TypeOopPtr/TypeInstPtr/TypeAryPtr with
 TypeKlassPtr/TypeInstKlassPtr/TypeAryKlassPtr

Reviewed-by: vlivanov, thartmann
---
 src/hotspot/share/oops/arrayKlass.cpp         |   16 +-
 src/hotspot/share/opto/callnode.cpp           |    2 +
 src/hotspot/share/opto/cfgnode.cpp            |    4 +-
 src/hotspot/share/opto/compile.cpp            |    6 +-
 src/hotspot/share/opto/doCall.cpp             |    8 +-
 src/hotspot/share/opto/escape.cpp             |    2 +-
 src/hotspot/share/opto/graphKit.cpp           |    4 +-
 src/hotspot/share/opto/idealGraphPrinter.cpp  |    2 +-
 src/hotspot/share/opto/library_call.cpp       |   18 +-
 src/hotspot/share/opto/memnode.cpp            |    2 +-
 src/hotspot/share/opto/memnode.hpp            |    2 +-
 src/hotspot/share/opto/parseHelper.cpp        |    2 +-
 src/hotspot/share/opto/subtypenode.cpp        |    2 +-
 src/hotspot/share/opto/type.cpp               | 1140 ++++++++++++-----
 src/hotspot/share/opto/type.hpp               |  219 +++-
 src/hotspot/share/utilities/growableArray.hpp |    2 +-
 .../compiler/lib/ir_framework/IRNode.java     |   12 +-
 .../ir_framework/tests/TestIRMatching.java    |    6 +-
 18 files changed, 992 insertions(+), 457 deletions(-)

diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp
index bec6eb2f0d2..b1ad66db041 100644
--- a/src/hotspot/share/oops/arrayKlass.cpp
+++ b/src/hotspot/share/oops/arrayKlass.cpp
@@ -88,14 +88,14 @@ ArrayKlass::ArrayKlass(Symbol* name, KlassID id) :
   _dimension(1),
   _higher_dimension(NULL),
   _lower_dimension(NULL) {
-    // Arrays don't add any new methods, so their vtable is the same size as
-    // the vtable of klass Object.
-    set_vtable_length(Universe::base_vtable_size());
-    set_name(name);
-    set_super(Universe::is_bootstrapping() ? NULL : vmClasses::Object_klass());
-    set_layout_helper(Klass::_lh_neutral_value);
-    set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5)
-    JFR_ONLY(INIT_ID(this);)
+  // Arrays don't add any new methods, so their vtable is the same size as
+  // the vtable of klass Object.
+  set_vtable_length(Universe::base_vtable_size());
+  set_name(name);
+  set_super(Universe::is_bootstrapping() ? NULL : vmClasses::Object_klass());
+  set_layout_helper(Klass::_lh_neutral_value);
+  set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5)
+  JFR_ONLY(INIT_ID(this);)
 }
 
 
diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp
index 6cab7d6c678..7345f49cbf1 100644
--- a/src/hotspot/share/opto/callnode.cpp
+++ b/src/hotspot/share/opto/callnode.cpp
@@ -378,6 +378,8 @@ static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, c
       st->print(" %s%d]=#Ptr" INTPTR_FORMAT,msg,i,p2i(t->isa_oopptr()->const_oop()));
       break;
     case Type::KlassPtr:
+    case Type::AryKlassPtr:
+    case Type::InstKlassPtr:
       st->print(" %s%d]=#Ptr" INTPTR_FORMAT,msg,i,p2i(t->make_ptr()->isa_klassptr()->klass()));
       break;
     case Type::MetadataPtr:
diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp
index b1b32dee3de..51e4b9887d0 100644
--- a/src/hotspot/share/opto/cfgnode.cpp
+++ b/src/hotspot/share/opto/cfgnode.cpp
@@ -1140,7 +1140,7 @@ const Type* PhiNode::Value(PhaseGVN* phase) const {
   // convert the one to the other.
   const TypePtr* ttp = _type->make_ptr();
   const TypeInstPtr* ttip = (ttp != NULL) ? ttp->isa_instptr() : NULL;
-  const TypeKlassPtr* ttkp = (ttp != NULL) ? ttp->isa_klassptr() : NULL;
+  const TypeKlassPtr* ttkp = (ttp != NULL) ? ttp->isa_instklassptr() : NULL;
   bool is_intf = false;
   if (ttip != NULL) {
     ciKlass* k = ttip->klass();
@@ -1233,7 +1233,7 @@ const Type* PhiNode::Value(PhaseGVN* phase) const {
     // 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 TypeKlassPtr *jtkp = (jtp != NULL) ? jtp->isa_klassptr() : NULL;
+    const TypeKlassPtr *jtkp = (jtp != NULL) ? jtp->isa_instklassptr() : NULL;
     if( jtip && ttip ) {
       if( jtip->is_loaded() &&  jtip->klass()->is_interface() &&
           ttip->is_loaded() && !ttip->klass()->is_interface() ) {
diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp
index 7e5f527e63a..27627dcd8eb 100644
--- a/src/hotspot/share/opto/compile.cpp
+++ b/src/hotspot/share/opto/compile.cpp
@@ -1410,7 +1410,7 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
     if ( offset == Type::OffsetBot || (offset >= 0 && (size_t)offset < sizeof(Klass)) ) {
 
       tj = tk = TypeKlassPtr::make(TypePtr::NotNull,
-                                   TypeKlassPtr::OBJECT->klass(),
+                                   TypeInstKlassPtr::OBJECT->klass(),
                                    offset);
     }
 
@@ -1457,7 +1457,9 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
     case Type::RawPtr:   tj = TypeRawPtr::BOTTOM;   break;
     case Type::AryPtr:   // do not distinguish arrays at all
     case Type::InstPtr:  tj = TypeInstPtr::BOTTOM;  break;
-    case Type::KlassPtr: tj = TypeKlassPtr::OBJECT; break;
+    case Type::KlassPtr:
+    case Type::AryKlassPtr:
+    case Type::InstKlassPtr: tj = TypeInstKlassPtr::OBJECT; break;
     case Type::AnyPtr:   tj = TypePtr::BOTTOM;      break;  // caller checks it
     default: ShouldNotReachHere();
     }
diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp
index c9e5a80005e..283a364dfec 100644
--- a/src/hotspot/share/opto/doCall.cpp
+++ b/src/hotspot/share/opto/doCall.cpp
@@ -916,7 +916,7 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) {
   Node* ex_klass_node = NULL;
   if (has_ex_handler() && !ex_type->klass_is_exact()) {
     Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes());
-    ex_klass_node = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
+    ex_klass_node = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT));
 
     // Compute the exception klass a little more cleverly.
     // Obvious solution is to simple do a LoadKlass from the 'ex_node'.
@@ -925,7 +925,7 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) {
     // I'm loading the class from, I can replace the LoadKlass with the
     // klass constant for the exception oop.
     if (ex_node->is_Phi()) {
-      ex_klass_node = new PhiNode(ex_node->in(0), TypeKlassPtr::OBJECT);
+      ex_klass_node = new PhiNode(ex_node->in(0), TypeInstKlassPtr::OBJECT);
       for (uint i = 1; i < ex_node->req(); i++) {
         Node* ex_in = ex_node->in(i);
         if (ex_in == top() || ex_in == NULL) {
@@ -934,10 +934,10 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) {
           continue;
         }
         Node* p = basic_plus_adr(ex_in, ex_in, oopDesc::klass_offset_in_bytes());
-        Node* k = _gvn.transform( LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
+        Node* k = _gvn.transform( LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT));
         ex_klass_node->init_req( i, k );
       }
-      _gvn.set_type(ex_klass_node, TypeKlassPtr::OBJECT);
+      _gvn.set_type(ex_klass_node, TypeInstKlassPtr::OBJECT);
 
     }
   }
diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp
index 6729f5f47b0..54d1d2f2ea5 100644
--- a/src/hotspot/share/opto/escape.cpp
+++ b/src/hotspot/share/opto/escape.cpp
@@ -3117,7 +3117,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *>  &alloc_worklist,
       // to the actual Array type.
       if (alloc->is_Allocate() && n->as_Type()->type() == TypeInstPtr::NOTNULL
           && (alloc->is_AllocateArray() ||
-              igvn->type(alloc->in(AllocateNode::KlassNode)) != TypeKlassPtr::OBJECT)) {
+              igvn->type(alloc->in(AllocateNode::KlassNode)) != TypeInstKlassPtr::OBJECT)) {
         Node *cast2 = NULL;
         for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
           Node *use = n->fast_out(i);
diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp
index 200a902ea96..7fcdd60f886 100644
--- a/src/hotspot/share/opto/graphKit.cpp
+++ b/src/hotspot/share/opto/graphKit.cpp
@@ -2867,7 +2867,7 @@ Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, No
   if (might_be_cache && mem != NULL) {
     kmem = mem->is_MergeMem() ? mem->as_MergeMem()->memory_at(C->get_alias_index(gvn.type(p2)->is_ptr())) : mem;
   }
-  Node *nkls = gvn.transform(LoadKlassNode::make(gvn, NULL, kmem, p2, gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
+  Node *nkls = gvn.transform(LoadKlassNode::make(gvn, NULL, kmem, p2, gvn.type(p2)->is_ptr(), TypeInstKlassPtr::OBJECT_OR_NULL));
 
   // Compile speed common case: ARE a subtype and we canNOT fail
   if( superklass == nkls )
@@ -3798,7 +3798,7 @@ Node* GraphKit::new_instance(Node* klass_node,
   // (Actually, it need not be precise if this is a reflective allocation.)
   // It's what we cast the result to.
   const TypeKlassPtr* tklass = _gvn.type(klass_node)->isa_klassptr();
-  if (!tklass)  tklass = TypeKlassPtr::OBJECT;
+  if (!tklass)  tklass = TypeInstKlassPtr::OBJECT;
   const TypeOopPtr* oop_type = tklass->as_instance_type();
 
   // Now generate allocation code
diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp
index b1e4a353832..736e796c16c 100644
--- a/src/hotspot/share/opto/idealGraphPrinter.cpp
+++ b/src/hotspot/share/opto/idealGraphPrinter.cpp
@@ -545,7 +545,7 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) {
         } else {
           print_prop(short_name, "L");
         }
-      } else if (t->base() == Type::KlassPtr) {
+      } else if (t->base() == Type::KlassPtr || t->base() == Type::InstKlassPtr || t->base() == Type::AryKlassPtr) {
         const TypeKlassPtr *typeKlass = t->is_klassptr();
         print_prop(short_name, "CP");
       } else if (t->base() == Type::Control) {
diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp
index aa5b5f11a0b..2dbd3dc1c4c 100644
--- a/src/hotspot/share/opto/library_call.cpp
+++ b/src/hotspot/share/opto/library_call.cpp
@@ -2838,7 +2838,7 @@ bool LibraryCallKit::inline_native_classID() {
   IdealVariable result(ideal); __ declarations_done();
   Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(),
                                                  basic_plus_adr(cls, java_lang_Class::klass_offset()),
-                                                 TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL));
+                                                 TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL));
 
 
   __ if_then(kls, BoolTest::ne, null()); {
@@ -2868,7 +2868,7 @@ bool LibraryCallKit::inline_native_classID() {
   } __ else_(); {
     Node* array_kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(),
                                                    basic_plus_adr(cls, java_lang_Class::array_klass_offset()),
-                                                   TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL));
+                                                   TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL));
     __ if_then(array_kls, BoolTest::ne, null()); {
       Node* array_kls_trace_id_addr = basic_plus_adr(array_kls, in_bytes(KLASS_TRACE_ID_OFFSET));
       Node* array_kls_trace_id_raw = ideal.load(ideal.ctrl(), array_kls_trace_id_addr, TypeLong::LONG, T_LONG, Compile::AliasIdxRaw);
@@ -2961,7 +2961,7 @@ Node* LibraryCallKit::load_klass_from_mirror_common(Node* mirror,
                                                     int offset) {
   if (region == NULL)  never_see_null = true;
   Node* p = basic_plus_adr(mirror, offset);
-  const TypeKlassPtr*  kls_type = TypeKlassPtr::OBJECT_OR_NULL;
+  const TypeKlassPtr*  kls_type = TypeInstKlassPtr::OBJECT_OR_NULL;
   Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type));
   Node* null_ctl = top();
   kls = null_check_oop(kls, &null_ctl, never_see_null);
@@ -3150,7 +3150,7 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
       phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror())));
     // If we fall through, it's a plain class.  Get its _super.
     p = basic_plus_adr(kls, in_bytes(Klass::super_offset()));
-    kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL));
+    kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL));
     null_ctl = top();
     kls = null_check_oop(kls, &null_ctl);
     if (null_ctl != top()) {
@@ -3292,7 +3292,7 @@ bool LibraryCallKit::inline_native_subtype_check() {
   record_for_igvn(region);
 
   const TypePtr* adr_type = TypeRawPtr::BOTTOM;   // memory type of loads
-  const TypeKlassPtr* kls_type = TypeKlassPtr::OBJECT_OR_NULL;
+  const TypeKlassPtr* kls_type = TypeInstKlassPtr::OBJECT_OR_NULL;
   int class_klass_offset = java_lang_Class::klass_offset();
 
   // First null-check both mirrors and load each mirror's klass metaobject.
@@ -6004,7 +6004,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) {
 
   ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass();
   const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_AESCrypt);
-  const TypeOopPtr* xtype = aklass->as_instance_type();
+  const TypeOopPtr* xtype = aklass->as_instance_type()->cast_to_ptr_type(TypePtr::NotNull);
   Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype);
   aescrypt_object = _gvn.transform(aescrypt_object);
 
@@ -6092,7 +6092,7 @@ bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) {
 
   ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass();
   const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_AESCrypt);
-  const TypeOopPtr* xtype = aklass->as_instance_type();
+  const TypeOopPtr* xtype = aklass->as_instance_type()->cast_to_ptr_type(TypePtr::NotNull);
   Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype);
   aescrypt_object = _gvn.transform(aescrypt_object);
 
@@ -6163,7 +6163,7 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) {
   assert(klass_AESCrypt->is_loaded(), "predicate checks that this class is loaded");
   ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass();
   const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_AESCrypt);
-  const TypeOopPtr* xtype = aklass->as_instance_type();
+  const TypeOopPtr* xtype = aklass->as_instance_type()->cast_to_ptr_type(TypePtr::NotNull);
   Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype);
   aescrypt_object = _gvn.transform(aescrypt_object);
   // we need to get the start of the aescrypt_object's expanded key array
@@ -6681,7 +6681,7 @@ bool LibraryCallKit::inline_digestBase_implCompressMB(Node* digestBase_obj, ciIn
                                                       const char* state_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();
+  const TypeOopPtr* xtype = aklass->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 587a6778d80..c4485d28c3d 100644
--- a/src/hotspot/share/opto/memnode.cpp
+++ b/src/hotspot/share/opto/memnode.cpp
@@ -1972,7 +1972,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const {
         return con_type;
       }
     }
-  } else if (tp->base() == Type::KlassPtr) {
+  } else if (tp->base() == Type::KlassPtr || tp->base() == Type::InstKlassPtr || tp->base() == Type::AryKlassPtr) {
     assert( off != Type::OffsetBot ||
             // arrays can be cast to Objects
             tp->is_klassptr()->klass()->is_java_lang_Object() ||
diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp
index 386c53ce1f0..06fa7d0724e 100644
--- a/src/hotspot/share/opto/memnode.hpp
+++ b/src/hotspot/share/opto/memnode.hpp
@@ -528,7 +528,7 @@ public:
 
   // Polymorphic factory method:
   static Node* make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at,
-                    const TypeKlassPtr* tk = TypeKlassPtr::OBJECT);
+                    const TypeKlassPtr* tk = TypeInstKlassPtr::OBJECT);
 };
 
 //------------------------------LoadNKlassNode---------------------------------
diff --git a/src/hotspot/share/opto/parseHelper.cpp b/src/hotspot/share/opto/parseHelper.cpp
index 957a6f7ea46..c16d3250c48 100644
--- a/src/hotspot/share/opto/parseHelper.cpp
+++ b/src/hotspot/share/opto/parseHelper.cpp
@@ -168,7 +168,7 @@ void Parse::array_store_check() {
   if (MonomorphicArrayCheck
       && !too_many_traps(Deoptimization::Reason_array_check)
       && !tak->klass_is_exact()
-      && tak != TypeKlassPtr::OBJECT) {
+      && tak != TypeInstKlassPtr::OBJECT) {
       // Regarding the fourth condition in the if-statement from above:
       //
       // If the compiler has determined that the type of array 'ary' (represented
diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp
index 508d62fd04c..10604cfebcc 100644
--- a/src/hotspot/share/opto/subtypenode.cpp
+++ b/src/hotspot/share/opto/subtypenode.cpp
@@ -234,7 +234,7 @@ bool SubTypeCheckNode::verify(PhaseGVN* phase) {
           chk_off_X = phase->transform(new ConvI2LNode(chk_off_X));
 #endif
           Node* p2 = phase->transform(new AddPNode(subklass, subklass, chk_off_X));
-          Node* nkls = phase->transform(LoadKlassNode::make(*phase, NULL, C->immutable_memory(), p2, phase->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
+          Node* nkls = phase->transform(LoadKlassNode::make(*phase, NULL, C->immutable_memory(), p2, phase->type(p2)->is_ptr(), TypeInstKlassPtr::OBJECT_OR_NULL));
 
           return verify_helper(phase, nkls, cached_t);
         }
diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp
index b6fd1c17c7f..459cbef03b7 100644
--- a/src/hotspot/share/opto/type.cpp
+++ b/src/hotspot/share/opto/type.cpp
@@ -94,6 +94,8 @@ const Type::TypeInfo Type::_type_info[Type::lastype] = {
   { Bad,             T_OBJECT,     "ary:",          true,  Op_RegP,              relocInfo::oop_type      },  // AryPtr
   { Bad,             T_METADATA,   "metadata:",     false, Op_RegP,              relocInfo::metadata_type },  // MetadataPtr
   { Bad,             T_METADATA,   "klass:",        false, Op_RegP,              relocInfo::metadata_type },  // KlassPtr
+  { Bad,             T_METADATA,   "instklass:",    false, Op_RegP,              relocInfo::metadata_type },  // InstKlassPtr
+  { Bad,             T_METADATA,   "aryklass:",     false, Op_RegP,              relocInfo::metadata_type },  // AryKlassPtr
   { Bad,             T_OBJECT,     "func",          false, 0,                    relocInfo::none          },  // Function
   { Abio,            T_ILLEGAL,    "abIO",          false, 0,                    relocInfo::none          },  // Abio
   { Return_Address,  T_ADDRESS,    "return_address",false, Op_RegP,              relocInfo::none          },  // Return_Address
@@ -599,8 +601,8 @@ void Type::Initialize_shared(Compile* current) {
   TypeAryPtr::_array_body_type[T_FLOAT]   = TypeAryPtr::FLOATS;
   TypeAryPtr::_array_body_type[T_DOUBLE]  = TypeAryPtr::DOUBLES;
 
-  TypeKlassPtr::OBJECT = TypeKlassPtr::make( TypePtr::NotNull, current->env()->Object_klass(), 0 );
-  TypeKlassPtr::OBJECT_OR_NULL = TypeKlassPtr::make( TypePtr::BotPTR, current->env()->Object_klass(), 0 );
+  TypeInstKlassPtr::OBJECT = TypeInstKlassPtr::make(TypePtr::NotNull, current->env()->Object_klass(), 0);
+  TypeInstKlassPtr::OBJECT_OR_NULL = TypeInstKlassPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), 0);
 
   const Type **fi2c = TypeTuple::fields(2);
   fi2c[TypeFunc::Parms+0] = TypeInstPtr::BOTTOM; // Method*
@@ -933,6 +935,8 @@ const Type *Type::xmeet( const Type *t ) const {
 
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
     return t->xmeet(this);
 
   case AryPtr:
@@ -1104,6 +1108,8 @@ Type::Category Type::category() const {
     case Type::AryPtr:
     case Type::MetadataPtr:
     case Type::KlassPtr:
+    case Type::InstKlassPtr:
+    case Type::AryKlassPtr:
     case Type::Function:
     case Type::Return_Address:
     case Type::FloatTop:
@@ -1190,6 +1196,8 @@ const Type *TypeF::xmeet( const Type *t ) const {
   case AryPtr:
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
   case NarrowOop:
   case NarrowKlass:
   case Int:
@@ -1301,6 +1309,8 @@ const Type *TypeD::xmeet( const Type *t ) const {
   case AryPtr:
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
   case NarrowOop:
   case NarrowKlass:
   case Int:
@@ -1472,6 +1482,8 @@ const Type *TypeInt::xmeet( const Type *t ) const {
   case AryPtr:
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
   case NarrowOop:
   case NarrowKlass:
   case Long:
@@ -1733,6 +1745,8 @@ const Type *TypeLong::xmeet( const Type *t ) const {
   case AryPtr:
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
   case NarrowOop:
   case NarrowKlass:
   case Int:
@@ -2580,6 +2594,8 @@ const Type *TypePtr::xmeet_helper(const Type *t) const {
   case AryPtr:
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
     return t->xmeet(this);      // Call in reverse direction
   default:                      // All else is a mistake
     typerr(t);
@@ -2967,7 +2983,7 @@ const TypeRawPtr *TypeRawPtr::make( address bits ) {
 }
 
 //------------------------------cast_to_ptr_type-------------------------------
-const Type *TypeRawPtr::cast_to_ptr_type(PTR ptr) const {
+const TypeRawPtr* TypeRawPtr::cast_to_ptr_type(PTR ptr) const {
   assert( ptr != Constant, "what is the constant?" );
   assert( ptr != Null, "Use TypePtr for NULL" );
   assert( _bits==0, "Why cast a constant address?");
@@ -3011,6 +3027,8 @@ const Type *TypeRawPtr::xmeet( const Type *t ) const {
   case AryPtr:
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
     return TypePtr::BOTTOM;     // Oop meet raw is not well defined
   default:                      // All else is a mistake
     typerr(t);
@@ -3177,7 +3195,7 @@ const TypeOopPtr *TypeOopPtr::make(PTR ptr, int offset, int instance_id,
 
 
 //------------------------------cast_to_ptr_type-------------------------------
-const Type *TypeOopPtr::cast_to_ptr_type(PTR ptr) const {
+const TypeOopPtr* TypeOopPtr::cast_to_ptr_type(PTR ptr) const {
   assert(_base == OopPtr, "subclass must override cast_to_ptr_type");
   if( ptr == _ptr ) return this;
   return make(ptr, _offset, _instance_id, _speculative, _inline_depth);
@@ -3201,13 +3219,9 @@ const Type *TypeOopPtr::cast_to_exactness(bool klass_is_exact) const {
 //------------------------------as_klass_type----------------------------------
 // Return the klass type corresponding to this instance or array type.
 // It is the type that is loaded from an object of this type.
-const TypeKlassPtr* TypeOopPtr::as_klass_type() const {
-  ciKlass* k = klass();
-  bool    xk = klass_is_exact();
-  if (k == NULL)
-    return TypeKlassPtr::OBJECT;
-  else
-    return TypeKlassPtr::make(xk? Constant: NotNull, k, 0);
+const TypeKlassPtr* TypeOopPtr::as_klass_type(bool try_for_exact) const {
+  ShouldNotReachHere();
+  return NULL;
 }
 
 //------------------------------meet-------------------------------------------
@@ -3240,6 +3254,8 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
   case RawPtr:
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
     return TypePtr::BOTTOM;     // Oop meet raw is not well defined
 
   case AnyPtr: {
@@ -3668,7 +3684,7 @@ const Type* TypeInstPtr::get_const_boxed_value() const {
 }
 
 //------------------------------cast_to_ptr_type-------------------------------
-const Type *TypeInstPtr::cast_to_ptr_type(PTR ptr) const {
+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.
@@ -3770,6 +3786,8 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
 
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
   case RawPtr: return TypePtr::BOTTOM;
 
   case AryPtr: {                // All arrays inherit from Object class
@@ -3845,181 +3863,208 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
   case InstPtr: {                // Meeting 2 Oops?
     // Found an InstPtr sub-type vs self-InstPtr type
     const TypeInstPtr *tinst = t->is_instptr();
-    int off = meet_offset( tinst->offset() );
-    PTR ptr = meet_ptr( tinst->ptr() );
+    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());
-
-    // 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 && klass()->equals(tinst->klass()) && klass_is_exact() == tinst->klass_is_exact()) {
-      return make(ptr, klass(), klass_is_exact(), NULL, off, instance_id, speculative, depth);
-    }
-
-    // Classes require inspection in the Java klass hierarchy.  Must be loaded.
     ciKlass* tinst_klass = tinst->klass();
-    ciKlass* this_klass  = this->klass();
+    ciKlass* this_klass  = klass();
     bool tinst_xk = tinst->klass_is_exact();
-    bool this_xk  = this->klass_is_exact();
-    if (!tinst_klass->is_loaded() || !this_klass->is_loaded() ) {
+    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);
+    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);
 #ifndef PRODUCT
-      if( PrintOpto && Verbose ) {
-        tty->print("meet of unloaded classes resulted in: "); unloaded_meet->dump(); tty->cr();
-        tty->print("  this == "); this->dump(); tty->cr();
-        tty->print(" tinst == "); tinst->dump(); tty->cr();
+      if (PrintOpto && Verbose) {
+        tty->print("meet of unloaded classes resulted in: ");
+        unloaded_meet->dump();
+        tty->cr();
+        tty->print("  this == ");
+        dump();
+        tty->cr();
+        tty->print(" tinst == ");
+        tinst->dump();
+        tty->cr();
       }
 #endif
-      return unloaded_meet;
-    }
-
-    // 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.
-      ciKlass *k;
-      bool xk;
-      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.
-        k  = below_centerline(ptr) ? tinst_klass : this_klass;
-        // If we are keeping this_klass, keep its exactness too.
-        xk = below_centerline(ptr) ? tinst_xk    : this_xk;
-      } 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)
-        k = above_centerline(ptr) ? tinst_klass : ciEnv::current()->Object_klass();
-        xk = above_centerline(ptr) ? tinst_xk : false;
-        // Watch out for Constant vs. AnyNull interface.
-        if (ptr == Constant) {
-          ptr = NotNull;  // forget it was a constant
-        }
-        if (instance_id > 0) {
-          instance_id = InstanceBot;
-        }
+      res = unloaded_meet;
+    } else {
+      if (kind == NOT_SUBTYPE && instance_id > 0) {
+        instance_id = InstanceBot;
+      } else if (kind == LCA) {
+        instance_id = InstanceBot;
       }
-      ciObject* o = NULL;  // the Constant value, if any
-      if (ptr == Constant) {
-        // Find out which constant.
-        o = (this_klass == klass()) ? const_oop() : tinst->const_oop();
-      }
-      return make(ptr, k, xk, o, off, instance_id, speculative, depth);
-    }
-
-    // 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".
-    // If both are up and they subtype, take the subtype class.
-    // If both are up and they do NOT subtype, "fall hard".
-    // If both are down and they subtype, take the supertype class.
-    // If both are down and they do NOT subtype, "fall hard".
-    // Constants treated as down.
-
-    // Now, reorder the above list; observe that both-down+subtype is also
-    // "fall hard"; "fall hard" becomes the default case:
-    // If we split one up & one down AND they subtype, take the down man.
-    // If both are up and they subtype, take the subtype class.
-
-    // If both are down and they subtype, "fall hard".
-    // If both are down and they do NOT subtype, "fall hard".
-    // If both are up and they do NOT subtype, "fall hard".
-    // If we split one up & one down AND they do NOT subtype, "fall hard".
-
-    // If a proper subtype is exact, and we return it, we return it exactly.
-    // If a proper supertype is exact, there can be no subtyping relationship!
-    // If both types are equal to the subtype, exactness is and-ed below the
-    // centerline and or-ed above it.  (N.B. Constants are always exact.)
-
-    // Check for subtyping:
-    ciKlass *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
-      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;
-    }
-
-    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;
-      } 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 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).
       ciObject* o = NULL;             // Assume not constant when done
-      ciObject* this_oop  = const_oop();
+      ciObject* this_oop = const_oop();
       ciObject* tinst_oop = tinst->const_oop();
-      if( ptr == Constant ) {
+      if (ptr == Constant) {
         if (this_oop != NULL && tinst_oop != NULL &&
-            this_oop->equals(tinst_oop) )
+            this_oop->equals(tinst_oop))
           o = this_oop;
-        else if (above_centerline(this ->_ptr))
+        else if (above_centerline(_ptr)) {
+          assert(!tinst_klass->is_interface(), "");
           o = tinst_oop;
-        else if (above_centerline(tinst ->_ptr))
+        } else if (above_centerline(tinst->_ptr)) {
+          assert(!this_klass->is_interface(), "");
           o = this_oop;
-        else
+        } else
           ptr = NotNull;
       }
-      return make(ptr, this_klass, this_xk, o, off, instance_id, speculative, depth);
-    } // Else classes are not equal
-
-    // Since klasses are different, we require a LCA in the Java
-    // class hierarchy - which means we have to fall to at least NotNull.
-    if (ptr == TopPTR || ptr == AnyNull || ptr == Constant) {
-      ptr = NotNull;
+      res = make(ptr, res_klass, res_xk, o, off, instance_id, speculative, depth);
     }
-    instance_id = InstanceBot;
 
-    // Now we find the LCA of Java classes
-    ciKlass* k = this_klass->least_common_ancestor(tinst_klass);
-    return make(ptr, k, false, NULL, off, instance_id, speculative, depth);
+    return res;
+
   } // End of case InstPtr
 
   } // End of switch
   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) {
+
+  // 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) {
+    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()) {
+    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".
+  // If both are up and they subtype, take the subtype class.
+  // If both are up and they do NOT subtype, "fall hard".
+  // If both are down and they subtype, take the supertype class.
+  // If both are down and they do NOT subtype, "fall hard".
+  // Constants treated as down.
+
+  // Now, reorder the above list; observe that both-down+subtype is also
+  // "fall hard"; "fall hard" becomes the default case:
+  // If we split one up & one down AND they subtype, take the down man.
+  // If both are up and they subtype, take the subtype class.
+
+  // If both are down and they subtype, "fall hard".
+  // If both are down and they do NOT subtype, "fall hard".
+  // If both are up and they do NOT subtype, "fall hard".
+  // If we split one up & one down AND they do NOT subtype, "fall hard".
+
+  // If a proper subtype is exact, and we return it, we return it exactly.
+  // If a proper supertype is exact, there can be no subtyping relationship!
+  // If both types are equal to the subtype, exactness is and-ed below the
+  // centerline and or-ed above it.  (N.B. Constants are always exact.)
+
+  // Check for subtyping:
+  ciKlass *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
+    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;
+  }
+
+  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;
+    } 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 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_xk = this_xk;
+    return SUBTYPE;
+  } // Else classes are not equal
+
+  // Since klasses are different, we require a LCA in the Java
+  // class hierarchy - which means we have to fall to at least NotNull.
+  if (ptr == TopPTR || ptr == AnyNull || ptr == Constant) {
+    ptr = NotNull;
+  }
+
+  // Now we find the LCA of Java classes
+  ciKlass* k = this_klass->least_common_ancestor(tinst_klass);
+
+  res_klass = k;
+  res_xk = false;
+
+  return LCA;
+}
+
 
 //------------------------java_mirror_type--------------------------------------
 ciType* TypeInstPtr::java_mirror_type() const {
@@ -4136,6 +4181,18 @@ const TypePtr *TypeInstPtr::with_instance_id(int instance_id) const {
   return make(_ptr, klass(), 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;
+  }
+  return TypeInstKlassPtr::make(xk ? TypePtr::Constant : TypePtr::NotNull, klass(), 0);
+}
+
 //=============================================================================
 // Convenience common pre-built types.
 const TypeAryPtr *TypeAryPtr::RANGE;
@@ -4172,7 +4229,7 @@ const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciK
 }
 
 //------------------------------cast_to_ptr_type-------------------------------
-const Type *TypeAryPtr::cast_to_ptr_type(PTR ptr) const {
+const TypeAryPtr* TypeAryPtr::cast_to_ptr_type(PTR ptr) const {
   if( ptr == _ptr ) return this;
   return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth);
 }
@@ -4379,6 +4436,8 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
 
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
   case RawPtr: return TypePtr::BOTTOM;
 
   case AryPtr: {                // Meeting 2 references?
@@ -4389,81 +4448,30 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
     int instance_id = meet_instance_id(tap->instance_id());
     const TypePtr* speculative = xmeet_speculative(tap);
     int depth = meet_inline_depth(tap->inline_depth());
-    ciKlass* lazy_klass = NULL;
-    if (tary->_elem->isa_int()) {
-      // Integral array element types have irrelevant lattice relations.
-      // It is the klass that determines array layout, not the element type.
-      if (_klass == NULL)
-        lazy_klass = tap->_klass;
-      else if (tap->_klass == NULL || tap->_klass == _klass) {
-        lazy_klass = _klass;
-      } else {
-        // Something like byte[int+] meets char[int+].
-        // This must fall to bottom, not (int[-128..65535])[int+].
-        instance_id = InstanceBot;
-        tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
-      }
-    } 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) && klass() != tap->klass() &&
-          // meet with top[] and bottom[] are processed further down:
-          tap->_klass != NULL  && this->_klass != NULL   &&
-          // both are exact and not equal:
-          ((tap->_klass_is_exact && this->_klass_is_exact) ||
-           // 'tap'  is exact and super or unrelated:
-           (tap->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) ||
-           // 'this' is exact and super or unrelated:
-           (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) {
-      if (above_centerline(ptr) || (tary->_elem->make_ptr() && above_centerline(tary->_elem->make_ptr()->_ptr))) {
-        tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
-      }
-      return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot, speculative, depth);
+
+    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) {
+      instance_id = InstanceBot;
     }
 
-    bool xk = false;
-    switch (tap->ptr()) {
-    case AnyNull:
-    case TopPTR:
-      // Compute new klass on demand, do not use tap->_klass
-      if (below_centerline(this->_ptr)) {
-        xk = this->_klass_is_exact;
+    ciObject* o = NULL;             // Assume not constant when done
+    ciObject* this_oop = const_oop();
+    ciObject* tap_oop = tap->const_oop();
+    if (ptr == Constant) {
+      if (this_oop != NULL && tap_oop != NULL &&
+          this_oop->equals(tap_oop)) {
+        o = tap_oop;
+      } else if (above_centerline(_ptr)) {
+        o = tap_oop;
+      } else if (above_centerline(tap->_ptr)) {
+        o = this_oop;
       } else {
-        xk = (tap->_klass_is_exact || this->_klass_is_exact);
+        ptr = NotNull;
       }
-      return make(ptr, const_oop(), tary, lazy_klass, xk, off, instance_id, speculative, depth);
-    case Constant: {
-      ciObject* o = const_oop();
-      if( _ptr == Constant ) {
-        if( tap->const_oop() != NULL && !o->equals(tap->const_oop()) ) {
-          xk = (klass() == tap->klass());
-          ptr = NotNull;
-          o = NULL;
-          instance_id = InstanceBot;
-        } else {
-          xk = true;
-        }
-      } else if(above_centerline(_ptr)) {
-        o = tap->const_oop();
-        xk = true;
-      } else {
-        // Only precise for identical arrays
-        xk = this->_klass_is_exact && (klass() == tap->klass());
-      }
-      return make(ptr, o, tary, lazy_klass, xk, off, instance_id, speculative, depth);
-    }
-    case NotNull:
-    case BotPTR:
-      // Compute new klass on demand, do not use tap->_klass
-      if (above_centerline(this->_ptr)) {
-        xk = tap->_klass_is_exact;
-      } else {
-        xk = (tap->_klass_is_exact & this->_klass_is_exact) &&
-             (klass() == tap->klass()); // Only precise for identical arrays
-      }
-      return make(ptr, NULL, tary, lazy_klass, xk, off, instance_id, speculative, depth);
-    default: ShouldNotReachHere();
     }
+    return make(ptr, o, TypeAry::make(elem, tary->_size, tary->_stable), res_klass, res_xk, off, instance_id, speculative, depth);
   }
 
   // All arrays inherit from Object class
@@ -4520,6 +4528,85 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
   return this;                  // Lint noise
 }
 
+
+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) {
+  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 = this_klass;
+    } else {
+      // Something like byte[int+] meets char[int+].
+      // This must fall to bottom, not (int[-128..65535])[int+].
+      // instance_id = InstanceBot;
+      elem = Type::BOTTOM;
+      result = NOT_SUBTYPE;
+    }
+  } 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 &&
+        // meet with top[] and bottom[] are processed further down:
+        tap_klass != NULL  && this_klass != NULL   &&
+        // both are exact and not equal:
+        ((tap_xk && this_xk) ||
+         // 'tap'  is exact and super or unrelated:
+         (tap_xk && !tap_klass->is_subtype_of(this_klass)) ||
+         // 'this' is exact and super or unrelated:
+         (this_xk && !this_klass->is_subtype_of(tap_klass)))) {
+      if (above_centerline(ptr) || (elem->make_ptr() && above_centerline(elem->make_ptr()->_ptr))) {
+        elem = Type::BOTTOM;
+      }
+      ptr = NotNull;
+      res_xk = false;
+      return NOT_SUBTYPE;
+    }
+
+  res_xk = false;
+  switch (tap_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);
+      }
+      return result;
+    case Constant: {
+      if (this_ptr == Constant) {
+          res_xk = true;
+      } else if(above_centerline(this_ptr)) {
+        res_xk = true;
+      } else {
+        // Only precise for identical arrays
+        res_xk = this_xk && (this_klass == tap_klass);
+      }
+      return result;
+    }
+    case NotNull:
+    case BotPTR:
+      // Compute new klass on demand, do not use tap->_klass
+      if (above_centerline(this_ptr)) {
+        res_xk = tap_xk;
+      } else {
+        res_xk = (tap_xk && this_xk) &&
+          (this_klass == tap_klass); // Only precise for identical arrays
+      }
+      return result;
+    default:  {
+      ShouldNotReachHere();
+      return result;
+    }
+  }
+  return result;
+}
+
+
 //------------------------------xdual------------------------------------------
 // Dual: compute field-by-field dual
 const Type *TypeAryPtr::xdual() const {
@@ -4701,6 +4788,8 @@ const Type *TypeNarrowPtr::xmeet( const Type *t ) const {
   case AryPtr:
   case MetadataPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
   case NarrowOop:
   case NarrowKlass:
 
@@ -4825,7 +4914,7 @@ intptr_t TypeMetadataPtr::get_con() const {
 }
 
 //------------------------------cast_to_ptr_type-------------------------------
-const Type *TypeMetadataPtr::cast_to_ptr_type(PTR ptr) const {
+const TypeMetadataPtr* TypeMetadataPtr::cast_to_ptr_type(PTR ptr) const {
   if( ptr == _ptr ) return this;
   return make(ptr, metadata(), _offset);
 }
@@ -4879,6 +4968,8 @@ const Type *TypeMetadataPtr::xmeet( const Type *t ) const {
 
   case RawPtr:
   case KlassPtr:
+  case InstKlassPtr:
+  case AryKlassPtr:
   case OopPtr:
   case InstPtr:
   case AryPtr:
@@ -4952,42 +5043,50 @@ const TypeMetadataPtr *TypeMetadataPtr::make(PTR ptr, ciMetadata* m, int offset)
 }
 
 
-//=============================================================================
-// Convenience common pre-built types.
-
-// Not-null object klass or below
-const TypeKlassPtr *TypeKlassPtr::OBJECT;
-const TypeKlassPtr *TypeKlassPtr::OBJECT_OR_NULL;
-
-//------------------------------TypeKlassPtr-----------------------------------
-TypeKlassPtr::TypeKlassPtr( PTR ptr, ciKlass* klass, int offset )
-  : TypePtr(KlassPtr, ptr, offset), _klass(klass), _klass_is_exact(ptr == Constant) {
+const TypeKlassPtr* TypeAryPtr::as_klass_type(bool try_for_exact) const {
+  const Type* elem = _ary->_elem;
+  bool xk = klass_is_exact();
+  if (elem->make_oopptr() != NULL) {
+    elem = elem->make_oopptr()->as_klass_type(try_for_exact);
+    if (elem->is_klassptr()->klass_is_exact()) {
+      xk = true;
+    }
+  }
+  return TypeAryKlassPtr::make(xk ? TypePtr::Constant : TypePtr::NotNull, elem, klass(), 0);
 }
 
-//------------------------------make-------------------------------------------
-// ptr to klass 'k', if Constant, or possibly to a sub-klass if not a Constant
-const TypeKlassPtr *TypeKlassPtr::make( PTR ptr, ciKlass* k, int offset ) {
-  assert( k != NULL, "Expect a non-NULL klass");
-  assert(k->is_instance_klass() || k->is_array_klass(), "Incorrect type of klass oop");
-  TypeKlassPtr *r =
-    (TypeKlassPtr*)(new TypeKlassPtr(ptr, k, offset))->hashcons();
+const TypeKlassPtr* TypeKlassPtr::make(ciKlass *klass) {
+  if (klass->is_instance_klass()) {
+    return TypeInstKlassPtr::make(klass);
+  }
+  return TypeAryKlassPtr::make(klass);
+}
 
-  return r;
+const TypeKlassPtr* TypeKlassPtr::make(PTR ptr, ciKlass* klass, int offset) {
+  if (klass->is_instance_klass()) {
+    return TypeInstKlassPtr::make(ptr, klass, offset);
+  }
+  return TypeAryKlassPtr::make(ptr, klass, offset);
+}
+
+
+//------------------------------TypeKlassPtr-----------------------------------
+TypeKlassPtr::TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, int offset)
+  : TypePtr(t, ptr, offset), _klass(klass) {
 }
 
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
-bool TypeKlassPtr::eq( const Type *t ) const {
+bool TypeKlassPtr::eq(const Type *t) const {
   const TypeKlassPtr *p = t->is_klassptr();
   return
-    klass()->equals(p->klass()) &&
     TypePtr::eq(p);
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeKlassPtr::hash(void) const {
-  return java_add((jint)klass()->hash(), (jint)TypePtr::hash());
+  return TypePtr::hash();
 }
 
 //------------------------------singleton--------------------------------------
@@ -5004,8 +5103,8 @@ const Type *TypeKlassPtr::filter_helper(const Type *kills, bool include_speculat
   // logic here mirrors the one from TypeOopPtr::filter. See comments
   // there.
   const Type* ft = join_helper(kills, include_speculative);
-  const TypeKlassPtr* ftkp = ft->isa_klassptr();
-  const TypeKlassPtr* ktkp = kills->isa_klassptr();
+  const TypeKlassPtr* ftkp = ft->isa_instklassptr();
+  const TypeKlassPtr* ktkp = kills->isa_instklassptr();
 
   if (ft->empty()) {
     if (!empty() && ktkp != NULL && ktkp->klass()->is_loaded() && ktkp->klass()->is_interface())
@@ -5026,6 +5125,318 @@ const Type *TypeKlassPtr::filter_helper(const Type *kills, bool include_speculat
   return ft;
 }
 
+//------------------------------get_con----------------------------------------
+intptr_t TypeKlassPtr::get_con() const {
+  assert( _ptr == Null || _ptr == Constant, "" );
+  assert( _offset >= 0, "" );
+
+  if (_offset != 0) {
+    // After being ported to the compiler interface, the compiler no longer
+    // directly manipulates the addresses of oops.  Rather, it only has a pointer
+    // to a handle at compile time.  This handle is embedded in the generated
+    // code and dereferenced at the time the nmethod is made.  Until that time,
+    // it is not reasonable to do arithmetic with the addresses of oops (we don't
+    // have access to the addresses!).  This does not seem to currently happen,
+    // but this assertion here is to help prevent its occurence.
+    tty->print_cr("Found oop constant with non-zero offset");
+    ShouldNotReachHere();
+  }
+
+  return (intptr_t)klass()->constant_encoding();
+}
+
+//------------------------------dump2------------------------------------------
+// Dump Klass Type
+#ifndef PRODUCT
+void TypeKlassPtr::dump2(Dict & d, uint depth, outputStream *st) const {
+  switch(_ptr) {
+  case Constant:
+    st->print("precise ");
+  case NotNull:
+    {
+      const char *name = klass()->name()->as_utf8();
+      if (name) {
+        st->print("%s: " INTPTR_FORMAT, name, p2i(klass()));
+      } else {
+        ShouldNotReachHere();
+      }
+    }
+  case BotPTR:
+    if (!WizardMode && !Verbose && _ptr != Constant) break;
+  case TopPTR:
+  case AnyNull:
+    st->print(":%s", ptr_msg[_ptr]);
+    if (_ptr == Constant) st->print(":exact");
+    break;
+  default:
+    break;
+  }
+
+  if (_offset) {               // Dump offset, if any
+    if (_offset == OffsetBot)      { st->print("+any"); }
+    else if (_offset == OffsetTop) { st->print("+unknown"); }
+    else                            { st->print("+%d", _offset); }
+  }
+
+  st->print(" *");
+}
+#endif
+
+//=============================================================================
+// Convenience common pre-built types.
+
+// Not-null object klass or below
+const TypeInstKlassPtr *TypeInstKlassPtr::OBJECT;
+const TypeInstKlassPtr *TypeInstKlassPtr::OBJECT_OR_NULL;
+
+bool TypeInstKlassPtr::eq(const Type *t) const {
+  const TypeKlassPtr *p = t->is_klassptr();
+  return
+    klass()->equals(p->klass()) &&
+    TypeKlassPtr::eq(p);
+}
+
+int TypeInstKlassPtr::hash(void) const {
+  return java_add((jint)klass()->hash(), TypeKlassPtr::hash());
+}
+
+const TypeInstKlassPtr *TypeInstKlassPtr::make(PTR ptr, ciKlass* k, int offset) {
+  TypeInstKlassPtr *r =
+    (TypeInstKlassPtr*)(new TypeInstKlassPtr(ptr, k, 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 TypeKlassPtr *TypeInstKlassPtr::with_offset(intptr_t offset) const {
+  return make(_ptr, klass(), offset);
+}
+
+//------------------------------cast_to_ptr_type-------------------------------
+const TypePtr* 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);
+}
+
+
+bool TypeInstKlassPtr::must_be_exact() const {
+  if (!_klass->is_loaded())  return false;
+  ciInstanceKlass* ik = _klass->as_instance_klass();
+  if (ik->is_final())  return true;  // cannot clear xk
+  return false;
+}
+
+//-----------------------------cast_to_exactness-------------------------------
+const TypeKlassPtr* TypeInstKlassPtr::cast_to_exactness(bool klass_is_exact) const {
+  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);
+}
+
+
+//-----------------------------as_instance_type--------------------------------
+// Corresponding type for an instance of the given class.
+// It will be NotNull, and exact if and only if the klass type is exact.
+const TypeOopPtr* TypeInstKlassPtr::as_instance_type() const {
+  ciKlass* k = klass();
+  bool    xk = klass_is_exact();
+  return TypeInstPtr::make(TypePtr::BotPTR, k, xk, NULL, 0);
+}
+
+//------------------------------xmeet------------------------------------------
+// Compute the MEET of two types, return a new Type object.
+const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {
+  // Perform a fast test for common case; meeting the same types together.
+  if( this == t ) return this;  // Meeting same type-rep?
+
+  // Current "this->_base" is Pointer
+  switch (t->base()) {          // switch on original type
+
+  case Int:                     // Mixing ints & oops happens when javac
+  case Long:                    // reuses local variables
+  case FloatTop:
+  case FloatCon:
+  case FloatBot:
+  case DoubleTop:
+  case DoubleCon:
+  case DoubleBot:
+  case NarrowOop:
+  case NarrowKlass:
+  case Bottom:                  // Ye Olde Default
+    return Type::BOTTOM;
+  case Top:
+    return this;
+
+  default:                      // All else is a mistake
+    typerr(t);
+
+  case AnyPtr: {                // Meeting to AnyPtrs
+    // Found an AnyPtr type vs self-KlassPtr type
+    const TypePtr *tp = t->is_ptr();
+    int offset = meet_offset(tp->offset());
+    PTR ptr = meet_ptr(tp->ptr());
+    switch (tp->ptr()) {
+    case TopPTR:
+      return this;
+    case Null:
+      if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
+    case AnyNull:
+      return make( ptr, klass(), offset );
+    case BotPTR:
+    case NotNull:
+      return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
+    default: typerr(t);
+    }
+  }
+
+  case RawPtr:
+  case MetadataPtr:
+  case OopPtr:
+  case AryPtr:                  // Meet with AryPtr
+  case InstPtr:                 // Meet with InstPtr
+    return TypePtr::BOTTOM;
+
+  //
+  //             A-top         }
+  //           /   |   \       }  Tops
+  //       B-top A-any C-top   }
+  //          | /  |  \ |      }  Any-nulls
+  //       B-any   |   C-any   }
+  //          |    |    |
+  //       B-con A-con C-con   } constants; not comparable across classes
+  //          |    |    |
+  //       B-not   |   C-not   }
+  //          | \  |  / |      }  not-nulls
+  //       B-bot A-not C-bot   }
+  //           \   |   /       }  Bottoms
+  //             A-bot         }
+  //
+
+  case InstKlassPtr: {  // Meet two KlassPtr types
+    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();
+
+    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)) {
+      case UNLOADED:
+        ShouldNotReachHere();
+      case SUBTYPE:
+      case NOT_SUBTYPE:
+      case LCA:
+      case QUICK: {
+        assert(res_xk == (ptr == Constant), "");
+        const Type* res1 = make(ptr, res_klass, off);
+        return res1;
+      }
+      default:
+        ShouldNotReachHere();
+    }
+  } // End of case KlassPtr
+  case AryKlassPtr: {                // All arrays inherit from Object class
+    const TypeAryKlassPtr *tp = t->is_aryklassptr();
+    int offset = meet_offset(tp->offset());
+    PTR ptr = meet_ptr(tp->ptr());
+
+    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 (klass()->equals(ciEnv::current()->Object_klass()) && !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);
+      }
+    case Constant:
+    case NotNull:
+    case BotPTR:                // Fall down to object klass
+      // LCA is object_klass, but if we subclass from the top we can do better
+      if( above_centerline(_ptr) ) { // if( _ptr == TopPTR || _ptr == AnyNull )
+        // If 'this' (InstPtr) is above the centerline and it is Object class
+        // then we can subclass in the Java class hierarchy.
+        // 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())) {
+          // that is, tp's array type is a subtype of my klass
+          return TypeAryKlassPtr::make(ptr,
+                                       tp->elem(), tp->klass(), offset);
+        }
+      }
+      // The other case cannot happen, since I cannot be a subtype of an array.
+      // The meet falls down to Object class below centerline.
+      if( ptr == Constant )
+         ptr = NotNull;
+      return make(ptr, ciEnv::current()->Object_klass(), offset);
+    default: typerr(t);
+    }
+  }
+
+  } // End of switch
+  return this;                  // Return the double constant
+}
+
+//------------------------------xdual------------------------------------------
+// Dual: compute field-by-field dual
+const Type    *TypeInstKlassPtr::xdual() const {
+  return new TypeInstKlassPtr(dual_ptr(), klass(), dual_offset());
+}
+
+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()) {
+    // 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);
+    return TypeAryKlassPtr::make(ptr, etype, NULL, offset);
+  } else if (klass->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);
+  } else {
+    ShouldNotReachHere();
+    return NULL;
+  }
+}
+
+const TypeAryKlassPtr* TypeAryKlassPtr::make(ciKlass* klass) {
+  return TypeAryKlassPtr::make(Constant, klass, 0);
+}
+
+//------------------------------eq---------------------------------------------
+// Structural equality check for Type representations
+bool TypeAryKlassPtr::eq(const Type *t) const {
+  const TypeAryKlassPtr *p = t->is_aryklassptr();
+  return
+    _elem == p->_elem &&  // Check array
+    TypeKlassPtr::eq(p);  // Check sub-parts
+}
+
+//------------------------------hash-------------------------------------------
+// Type-specific hashing function.
+int TypeAryKlassPtr::hash(void) const {
+  return (intptr_t)_elem + TypeKlassPtr::hash();
+}
+
 //----------------------compute_klass------------------------------------------
 // Compute the defining klass for this class
 ciKlass* TypeAryPtr::compute_klass(DEBUG_ONLY(bool verify)) const {
@@ -5116,42 +5527,56 @@ ciKlass* TypeAryPtr::klass() const {
 
 //------------------------------add_offset-------------------------------------
 // Access internals of klass object
-const TypePtr *TypeKlassPtr::add_offset( intptr_t offset ) const {
-  return make( _ptr, klass(), xadd_offset(offset) );
+const TypePtr *TypeAryKlassPtr::add_offset(intptr_t offset) const {
+  return make(_ptr, elem(), klass(), xadd_offset(offset));
+}
+
+const TypeKlassPtr *TypeAryKlassPtr::with_offset(intptr_t offset) const {
+  return make(_ptr, elem(), klass(), offset);
 }
 
 //------------------------------cast_to_ptr_type-------------------------------
-const Type *TypeKlassPtr::cast_to_ptr_type(PTR ptr) const {
-  assert(_base == KlassPtr, "subclass must override cast_to_ptr_type");
-  if( ptr == _ptr ) return this;
-  return make(ptr, _klass, _offset);
+const TypePtr* TypeAryKlassPtr::cast_to_ptr_type(PTR ptr) const {
+  assert(_base == AryKlassPtr, "subclass must override cast_to_ptr_type");
+  if (ptr == _ptr) return this;
+  return make(ptr, elem(), _klass, _offset);
+}
+
+bool TypeAryKlassPtr::must_be_exact() const {
+  if (_elem == Type::BOTTOM) return false;
+  if (_elem == Type::TOP   ) return false;
+  const TypeKlassPtr*  tk = _elem->isa_klassptr();
+  if (!tk)             return true;   // a primitive type, like int
+  return tk->must_be_exact();
 }
 
 
 //-----------------------------cast_to_exactness-------------------------------
-const Type *TypeKlassPtr::cast_to_exactness(bool klass_is_exact) const {
-  if( klass_is_exact == _klass_is_exact ) return this;
-  return make(klass_is_exact ? Constant : NotNull, _klass, _offset);
+const TypeKlassPtr *TypeAryKlassPtr::cast_to_exactness(bool klass_is_exact) const {
+  if (must_be_exact()) return this;  // cannot clear xk
+  ciKlass* k = _klass;
+  const Type* elem = this->elem();
+  if (elem->isa_klassptr() && !klass_is_exact) {
+    elem = elem->is_klassptr()->cast_to_exactness(klass_is_exact);
+  }
+  return make(klass_is_exact ? Constant : NotNull, elem, k, _offset);
 }
 
 
 //-----------------------------as_instance_type--------------------------------
 // Corresponding type for an instance of the given class.
-// It will be NotNull, and exact if and only if the klass type is exact.
-const TypeOopPtr* TypeKlassPtr::as_instance_type() const {
+// It will be exact if and only if the klass type is exact.
+const TypeOopPtr* TypeAryKlassPtr::as_instance_type() const {
   ciKlass* k = klass();
   bool    xk = klass_is_exact();
-  //return TypeInstPtr::make(TypePtr::NotNull, k, xk, NULL, 0);
-  const TypeOopPtr* toop = TypeOopPtr::make_from_klass_raw(k);
-  guarantee(toop != NULL, "need type for given klass");
-  toop = toop->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr();
-  return toop->cast_to_exactness(xk)->is_oopptr();
+  const Type* el = elem()->isa_klassptr() ? elem()->is_klassptr()->as_instance_type()->is_oopptr()->cast_to_exactness(false) : elem();
+  return TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(el, TypeInt::POS), k, xk, 0);
 }
 
 
 //------------------------------xmeet------------------------------------------
 // Compute the MEET of two types, return a new Type object.
-const Type    *TypeKlassPtr::xmeet( const Type *t ) const {
+const Type    *TypeAryKlassPtr::xmeet( const Type *t ) const {
   // Perform a fast test for common case; meeting the same types together.
   if( this == t ) return this;  // Meeting same type-rep?
 
@@ -5187,7 +5612,7 @@ const Type    *TypeKlassPtr::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, _elem, klass(), offset );
     case BotPTR:
     case NotNull:
       return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
@@ -5218,62 +5643,59 @@ const Type    *TypeKlassPtr::xmeet( const Type *t ) const {
   //             A-bot         }
   //
 
-  case KlassPtr: {  // Meet two KlassPtr types
-    const TypeKlassPtr *tkls = t->is_klassptr();
-    int  off     = meet_offset(tkls->offset());
-    PTR  ptr     = meet_ptr(tkls->ptr());
+  case AryKlassPtr: {  // Meet two KlassPtr types
+    const TypeAryKlassPtr *tap = t->is_aryklassptr();
+    int off = meet_offset(tap->offset());
+    const Type* elem = _elem->meet(tap->_elem);
 
-    // 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
-    // not-loaded classes
-    if( ptr != Constant && tkls->klass()->equals(klass()) ) {
-      return make( ptr, klass(), off );
-    }
-
-    // Classes require inspection in the Java klass hierarchy.  Must be loaded.
-    ciKlass* tkls_klass = tkls->klass();
-    ciKlass* this_klass = this->klass();
-    assert( tkls_klass->is_loaded(), "This class should have been loaded.");
-    assert( this_klass->is_loaded(), "This class should have been loaded.");
-
-    // If 'this' type is above the centerline and is a superclass of the
-    // other, we can treat 'this' as having the same type as the other.
-    if ((above_centerline(this->ptr())) &&
-        tkls_klass->is_subtype_of(this_klass)) {
-      this_klass = tkls_klass;
-    }
-    // If 'tinst' type is above the centerline and is a superclass of the
-    // other, we can treat 'tinst' as having the same type as the other.
-    if ((above_centerline(tkls->ptr())) &&
-        this_klass->is_subtype_of(tkls_klass)) {
-      tkls_klass = this_klass;
-    }
-
-    // Check for classes now being equal
-    if (tkls_klass->equals(this_klass)) {
-      // 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).
-      if( ptr == Constant ) {
-        if (this->_ptr == Constant && tkls->_ptr == Constant &&
-            this->klass()->equals(tkls->klass()));
-        else if (above_centerline(this->ptr()));
-        else if (above_centerline(tkls->ptr()));
-        else
-          ptr = NotNull;
-      }
-      return make( ptr, this_klass, off );
-    } // Else classes are not equal
-
-    // Since klasses are different, we require the LCA in the Java
-    // class hierarchy - which means we have to fall to at least NotNull.
-    if( ptr == TopPTR || ptr == AnyNull || ptr == Constant )
-      ptr = NotNull;
-    // Now we find the LCA of Java classes
-    ciKlass* k = this_klass->least_common_ancestor(tkls_klass);
-    return   make( ptr, k, off );
+    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);
+    assert(res_xk == (ptr == Constant), "");
+    return make(ptr, elem, res_klass, off);
   } // End of case KlassPtr
+  case InstKlassPtr: {
+    const TypeInstKlassPtr *tp = t->is_instklassptr();
+    int offset = meet_offset(tp->offset());
+    PTR ptr = meet_ptr(tp->ptr());
+
+    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 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);
+      }
+    case Constant:
+    case NotNull:
+    case BotPTR:                // Fall down to object klass
+      // LCA is object_klass, but if we subclass from the top we can do better
+      if (above_centerline(tp->ptr())) {
+        // If 'tp'  is above the centerline and it is Object class
+        // then we can subclass in the Java class hierarchy.
+        // 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()) {
+          // that is, my array type is a subtype of 'tp' klass
+          return make(ptr, _elem, _klass, offset);
+        }
+      }
+      // The other case cannot happen, since t cannot be a subtype of an array.
+      // The meet falls down to Object class below centerline.
+      if (ptr == Constant)
+         ptr = NotNull;
+      return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), offset);
+    default: typerr(t);
+    }
+  }
 
   } // End of switch
   return this;                  // Return the double constant
@@ -5281,51 +5703,49 @@ const Type    *TypeKlassPtr::xmeet( const Type *t ) const {
 
 //------------------------------xdual------------------------------------------
 // Dual: compute field-by-field dual
-const Type    *TypeKlassPtr::xdual() const {
-  return new TypeKlassPtr( dual_ptr(), klass(), dual_offset() );
+const Type    *TypeAryKlassPtr::xdual() const {
+  return new TypeAryKlassPtr(dual_ptr(), elem()->dual(), klass(), dual_offset());
 }
 
 //------------------------------get_con----------------------------------------
-intptr_t TypeKlassPtr::get_con() const {
-  assert( _ptr == Null || _ptr == Constant, "" );
-  assert( _offset >= 0, "" );
-
-  if (_offset != 0) {
-    // After being ported to the compiler interface, the compiler no longer
-    // directly manipulates the addresses of oops.  Rather, it only has a pointer
-    // to a handle at compile time.  This handle is embedded in the generated
-    // code and dereferenced at the time the nmethod is made.  Until that time,
-    // it is not reasonable to do arithmetic with the addresses of oops (we don't
-    // have access to the addresses!).  This does not seem to currently happen,
-    // but this assertion here is to help prevent its occurence.
-    tty->print_cr("Found oop constant with non-zero offset");
-    ShouldNotReachHere();
+ciKlass* TypeAryKlassPtr::klass() const {
+  if (_klass != NULL) {
+    return _klass;
   }
-
-  return (intptr_t)klass()->constant_encoding();
+  ciKlass* k = NULL;
+  if (elem()->isa_klassptr()) {
+    k = elem()->is_klassptr()->klass();
+    if (k != NULL) {
+      k = ciObjArrayKlass::make(k);
+      ((TypeAryKlassPtr*)this)->_klass = k;
+    }
+  } else if ((elem()->base() == Type::Top) ||
+             (elem()->base() == Type::Bottom)) {
+  } else {
+    k = ciTypeArrayKlass::make(elem()->basic_type());
+  }
+  return k;
 }
+
 //------------------------------dump2------------------------------------------
 // Dump Klass Type
 #ifndef PRODUCT
-void TypeKlassPtr::dump2( Dict & d, uint depth, outputStream *st ) const {
+void TypeAryKlassPtr::dump2( Dict & d, uint depth, outputStream *st ) const {
   switch( _ptr ) {
   case Constant:
     st->print("precise ");
   case NotNull:
     {
-      const char *name = klass()->name()->as_utf8();
-      if( name ) {
-        st->print("klass %s: " INTPTR_FORMAT, name, p2i(klass()));
-      } else {
-        ShouldNotReachHere();
-      }
+      st->print("[");
+      _elem->dump2(d, depth, st);
+      st->print(": ");
     }
   case BotPTR:
-    if( !WizardMode && !Verbose && !_klass_is_exact ) break;
+    if( !WizardMode && !Verbose && _ptr != Constant ) break;
   case TopPTR:
   case AnyNull:
     st->print(":%s", ptr_msg[_ptr]);
-    if( _klass_is_exact ) st->print(":exact");
+    if( _ptr == Constant ) st->print(":exact");
     break;
   default:
     break;
@@ -5341,7 +5761,15 @@ void TypeKlassPtr::dump2( Dict & d, uint depth, outputStream *st ) const {
 }
 #endif
 
-
+const Type* TypeAryKlassPtr::base_element_type(int& dims) const {
+  const Type* elem = this->elem();
+  dims = 1;
+  while (elem->isa_aryklassptr()) {
+    elem = elem->is_aryklassptr()->elem();
+    dims++;
+  }
+  return elem;
+}
 
 //=============================================================================
 // Convenience common pre-built types.
diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp
index 21612afbedc..dc9a5d8156b 100644
--- a/src/hotspot/share/opto/type.hpp
+++ b/src/hotspot/share/opto/type.hpp
@@ -67,6 +67,8 @@ class     TypeOopPtr;
 class       TypeInstPtr;
 class       TypeAryPtr;
 class     TypeKlassPtr;
+class       TypeInstKlassPtr;
+class       TypeAryKlassPtr;
 class     TypeMetadataPtr;
 
 //------------------------------Type-------------------------------------------
@@ -108,6 +110,8 @@ public:
 
     MetadataPtr,                // Generic metadata
     KlassPtr,                   // Klass pointers
+    InstKlassPtr,
+    AryKlassPtr,
 
     Function,                   // Function signature
     Abio,                       // Abstract I/O
@@ -321,6 +325,10 @@ public:
   const TypeMetadataPtr   *is_metadataptr() const;    // Java-style GC'd pointer
   const TypeKlassPtr      *isa_klassptr() const;      // Returns NULL if not KlassPtr
   const TypeKlassPtr      *is_klassptr() const;       // assert if not KlassPtr
+  const TypeInstKlassPtr  *isa_instklassptr() const;  // Returns NULL if not IntKlassPtr
+  const TypeInstKlassPtr  *is_instklassptr() const;   // assert if not IntKlassPtr
+  const TypeAryKlassPtr   *isa_aryklassptr() const;   // Returns NULL if not AryKlassPtr
+  const TypeAryKlassPtr   *is_aryklassptr() const;    // assert if not AryKlassPtr
 
   virtual bool      is_finite() const;           // Has a finite value
   virtual bool      is_nan()    const;           // Is not a number (NaN)
@@ -916,6 +924,24 @@ protected:
   void dump_inline_depth(outputStream *st) const;
 #endif
 
+  // TypeInstPtr (TypeAryPtr resp.) and TypeInstKlassPtr (TypeAryKlassPtr resp.) implement very similar meet logic.
+  // The logic for meeting 2 instances (2 arrays resp.) is shared in the 2 utility methods below. However the logic for
+  // the oop and klass versions can be slightly different and extra logic may have to be executed depending on what
+  // exact case the meet falls into. The MeetResult struct is used by the utility methods to communicate what case was
+  // encountered so the right logic specific to klasses or oops can be executed.,
+  enum MeetResult {
+    QUICK,
+    UNLOADED,
+    SUBTYPE,
+    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);
+
 public:
   const int _offset;            // Offset into oop, with TOP & BOT
   const PTR _ptr;               // Pointer equivalence class
@@ -998,7 +1024,7 @@ public:
   static const TypeRawPtr *make( address bits );
 
   // Return a 'ptr' version of this type
-  virtual const Type *cast_to_ptr_type(PTR ptr) const;
+  virtual const TypeRawPtr* cast_to_ptr_type(PTR ptr) const;
 
   virtual intptr_t get_con() const;
 
@@ -1097,14 +1123,14 @@ public:
 
   virtual intptr_t get_con() const;
 
-  virtual const Type *cast_to_ptr_type(PTR ptr) const;
+  virtual const TypeOopPtr* cast_to_ptr_type(PTR ptr) const;
 
   virtual const Type *cast_to_exactness(bool klass_is_exact) const;
 
   virtual const TypeOopPtr *cast_to_instance_id(int instance_id) const;
 
   // corresponding pointer to klass, for a given instance
-  const TypeKlassPtr* as_klass_type() const;
+  virtual const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const;
 
   virtual const TypePtr *add_offset( intptr_t offset ) const;
 
@@ -1181,7 +1207,7 @@ class TypeInstPtr : public TypeOopPtr {
   // be a TypeInstPtr, but may also be a TypeInt::INT for int.class, etc.
   ciType* java_mirror_type() const;
 
-  virtual const Type *cast_to_ptr_type(PTR ptr) const;
+  virtual const TypeInstPtr* cast_to_ptr_type(PTR ptr) const;
 
   virtual const Type *cast_to_exactness(bool klass_is_exact) const;
 
@@ -1199,6 +1225,8 @@ class TypeInstPtr : public TypeOopPtr {
   virtual const TypeInstPtr *xmeet_unloaded( const TypeInstPtr *t ) const;
   virtual const Type *xdual() const;    // Compute dual right now.
 
+  const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const;
+
   // Convenience common pre-built types.
   static const TypeInstPtr *NOTNULL;
   static const TypeInstPtr *BOTTOM;
@@ -1265,7 +1293,7 @@ public:
                                 int inline_depth = InlineDepthBottom, bool is_autobox_cache = false);
 
   // Return a 'ptr' version of this type
-  virtual const Type *cast_to_ptr_type(PTR ptr) const;
+  virtual const TypeAryPtr* cast_to_ptr_type(PTR ptr) const;
 
   virtual const Type *cast_to_exactness(bool klass_is_exact) const;
 
@@ -1292,6 +1320,7 @@ public:
   const TypeAryPtr* cast_to_autobox_cache() const;
 
   static jint max_array_length(BasicType etype) ;
+  virtual const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const;
 
   // Convenience common pre-built types.
   static const TypeAryPtr *RANGE;
@@ -1343,7 +1372,7 @@ public:
 
   ciMetadata* metadata() const { return _metadata; }
 
-  virtual const Type *cast_to_ptr_type(PTR ptr) const;
+  virtual const TypeMetadataPtr* cast_to_ptr_type(PTR ptr) const;
 
   virtual const TypePtr *add_offset( intptr_t offset ) const;
 
@@ -1363,74 +1392,130 @@ public:
 //------------------------------TypeKlassPtr-----------------------------------
 // Class of Java Klass pointers
 class TypeKlassPtr : public TypePtr {
-  TypeKlassPtr( PTR ptr, ciKlass* klass, int offset );
+protected:
+  TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, int offset);
+
+  virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
+
+public:
+  virtual bool eq( const Type *t ) const;
+  virtual int hash() const;
+  virtual bool singleton(void) const;    // TRUE if type is a singleton
+  virtual bool must_be_exact() const { ShouldNotReachHere(); return false; }
 
 protected:
-  virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
- public:
-  virtual bool eq( const Type *t ) const;
-  virtual int hash() const;             // Type specific hashing
-  virtual bool singleton(void) const;    // TRUE if type is a singleton
- private:
-
-  static const TypeKlassPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact);
 
   ciKlass* _klass;
 
-  // Does the type exclude subclasses of the klass?  (Inexact == polymorphic.)
-  bool          _klass_is_exact;
-
 public:
-  ciSymbol* name()  const { return klass()->name(); }
-
-  ciKlass* klass() const { return  _klass; }
-  bool klass_is_exact()    const { return _klass_is_exact; }
 
+  virtual ciKlass* klass() const { return  _klass; }
+  bool klass_is_exact()    const { return _ptr == Constant; }
   bool  is_loaded() const { return klass()->is_loaded(); }
 
-  // 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 TypeKlassPtr* make_from_klass(ciKlass* klass) {
-    return make_from_klass_common(klass, true, false);
-  }
-  // 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 TypeKlassPtr* make_from_klass_unique(ciKlass* klass) {
-    return make_from_klass_common(klass, true, true);
-  }
-  // Same as before, but does not respects UseUniqueSubclasses.
-  // Use this only for creating array element types.
-  static const TypeKlassPtr* make_from_klass_raw(ciKlass* klass) {
-    return make_from_klass_common(klass, false, false);
-  }
+  static const TypeKlassPtr* make(ciKlass* klass);
+  static const TypeKlassPtr *make(PTR ptr, ciKlass* klass, int offset);
 
-  // Make a generic (unclassed) pointer to metadata.
-  static const TypeKlassPtr* make(PTR ptr, int offset);
 
-  // ptr to klass 'k'
-  static const TypeKlassPtr *make( ciKlass* k ) { return make( TypePtr::Constant, k, 0); }
-  // ptr to klass 'k' with offset
-  static const TypeKlassPtr *make( ciKlass* k, int offset ) { return make( TypePtr::Constant, k, offset); }
-  // ptr to klass 'k' or sub-klass
-  static const TypeKlassPtr *make( PTR ptr, ciKlass* k, int offset);
+  virtual const TypePtr* cast_to_ptr_type(PTR ptr) const { ShouldNotReachHere(); return NULL; }
 
-  virtual const Type *cast_to_ptr_type(PTR ptr) const;
-
-  virtual const Type *cast_to_exactness(bool klass_is_exact) const;
+  virtual const TypeKlassPtr *cast_to_exactness(bool klass_is_exact) const { ShouldNotReachHere(); return NULL; }
 
   // corresponding pointer to instance, for a given class
-  const TypeOopPtr* as_instance_type() const;
+  virtual const TypeOopPtr* as_instance_type() const { ShouldNotReachHere(); return NULL; }
+
+  virtual const TypePtr *add_offset( intptr_t offset ) const { ShouldNotReachHere(); return NULL; }
+  virtual const Type    *xmeet( const Type *t ) const { ShouldNotReachHere(); return NULL; }
+  virtual const Type    *xdual() const { ShouldNotReachHere(); return NULL; }
+
+  virtual intptr_t get_con() const;
+
+  virtual const TypeKlassPtr* with_offset(intptr_t offset) const { ShouldNotReachHere(); return NULL; }
+
+#ifndef PRODUCT
+  virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
+#endif
+};
+
+// Instance klass pointer, mirrors TypeInstPtr
+class TypeInstKlassPtr : public TypeKlassPtr {
+
+  TypeInstKlassPtr(PTR ptr, ciKlass* klass, int offset)
+    : TypeKlassPtr(InstKlassPtr, ptr, klass, offset) {
+  }
+
+  virtual bool must_be_exact() const;
+
+public:
+  // Instance klass ignoring any interface
+  ciInstanceKlass* instance_klass() const { return klass()->as_instance_klass();     }
+
+  static const TypeInstKlassPtr *make(ciKlass* k) {
+    return make(TypePtr::Constant, k, 0);
+  }
+  static const TypeInstKlassPtr *make(PTR ptr, ciKlass* k, int offset);
+
+  virtual const TypePtr* cast_to_ptr_type(PTR ptr) const;
+
+  virtual const TypeKlassPtr *cast_to_exactness(bool klass_is_exact) const;
+
+  // corresponding pointer to instance, for a given class
+  virtual const TypeOopPtr* as_instance_type() const;
+  virtual int hash() const;
+  virtual bool eq(const Type *t) const;
+
+  virtual const TypePtr *add_offset( intptr_t offset ) const;
+  virtual const Type    *xmeet( const Type *t ) const;
+  virtual const Type    *xdual() const;
+  virtual const TypeKlassPtr* with_offset(intptr_t offset) 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
+};
+
+// Array klass pointer, mirrors TypeAryPtr
+class TypeAryKlassPtr : public TypeKlassPtr {
+  const Type *_elem;
+
+  TypeAryKlassPtr(PTR ptr, const Type *elem, ciKlass* klass, int offset)
+    : TypeKlassPtr(AryKlassPtr, ptr, klass, offset), _elem(elem) {
+  }
+
+  virtual bool must_be_exact() const;
+
+public:
+  virtual ciKlass* klass() const;
+
+  // 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, const Type *elem, ciKlass* k, int offset);
+  static const TypeAryKlassPtr* make(ciKlass* klass);
+
+  const Type *elem() const { return _elem; }
+
+  virtual bool eq(const Type *t) const;
+  virtual int hash() const;             // Type specific hashing
+
+  virtual const TypePtr* cast_to_ptr_type(PTR ptr) const;
+
+  virtual const TypeKlassPtr *cast_to_exactness(bool klass_is_exact) const;
+
+  // corresponding pointer to instance, for a given class
+  virtual const TypeOopPtr* as_instance_type() const;
 
   virtual const TypePtr *add_offset( intptr_t offset ) const;
   virtual const Type    *xmeet( const Type *t ) const;
   virtual const Type    *xdual() const;      // Compute dual right now.
 
-  virtual intptr_t get_con() const;
+  virtual const TypeKlassPtr* with_offset(intptr_t offset) const;
+
+  virtual bool empty(void) const {
+    return TypeKlassPtr::empty() || _elem->empty();
+  }
 
-  // Convenience common pre-built types.
-  static const TypeKlassPtr* OBJECT; // Not-null object klass or below
-  static const TypeKlassPtr* OBJECT_OR_NULL; // Maybe-null version of same
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
 #endif
@@ -1721,13 +1806,13 @@ inline const TypeVect *Type::isa_vect() const {
 
 inline const TypePtr *Type::is_ptr() const {
   // AnyPtr is the first Ptr and KlassPtr the last, with no non-ptrs between.
-  assert(_base >= AnyPtr && _base <= KlassPtr, "Not a pointer");
+  assert(_base >= AnyPtr && _base <= AryKlassPtr, "Not a pointer");
   return (TypePtr*)this;
 }
 
 inline const TypePtr *Type::isa_ptr() const {
   // AnyPtr is the first Ptr and KlassPtr the last, with no non-ptrs between.
-  return (_base >= AnyPtr && _base <= KlassPtr) ? (TypePtr*)this : NULL;
+  return (_base >= AnyPtr && _base <= AryKlassPtr) ? (TypePtr*)this : NULL;
 }
 
 inline const TypeOopPtr *Type::is_oopptr() const {
@@ -1799,14 +1884,32 @@ inline const TypeMetadataPtr *Type::isa_metadataptr() const {
 }
 
 inline const TypeKlassPtr *Type::isa_klassptr() const {
-  return (_base == KlassPtr) ? (TypeKlassPtr*)this : NULL;
+  return (_base >= KlassPtr && _base <= AryKlassPtr ) ? (TypeKlassPtr*)this : NULL;
 }
 
 inline const TypeKlassPtr *Type::is_klassptr() const {
-  assert( _base == KlassPtr, "Not a klass pointer" );
+  assert(_base >= KlassPtr && _base <= AryKlassPtr, "Not a klass pointer");
   return (TypeKlassPtr*)this;
 }
 
+inline const TypeInstKlassPtr *Type::isa_instklassptr() const {
+  return (_base == InstKlassPtr) ? (TypeInstKlassPtr*)this : NULL;
+}
+
+inline const TypeInstKlassPtr *Type::is_instklassptr() const {
+  assert(_base == InstKlassPtr, "Not a klass pointer");
+  return (TypeInstKlassPtr*)this;
+}
+
+inline const TypeAryKlassPtr *Type::isa_aryklassptr() const {
+  return (_base == AryKlassPtr) ? (TypeAryKlassPtr*)this : NULL;
+}
+
+inline const TypeAryKlassPtr *Type::is_aryklassptr() const {
+  assert(_base == AryKlassPtr, "Not a klass pointer");
+  return (TypeAryKlassPtr*)this;
+}
+
 inline const TypePtr* Type::make_ptr() const {
   return (_base == NarrowOop) ? is_narrowoop()->get_ptrtype() :
                               ((_base == NarrowKlass) ? is_narrowklass()->get_ptrtype() :
diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp
index b75283843eb..8ab6f6f4af6 100644
--- a/src/hotspot/share/utilities/growableArray.hpp
+++ b/src/hotspot/share/utilities/growableArray.hpp
@@ -447,7 +447,7 @@ public:
 
   // Binary search and insertion utility.  Search array for element
   // matching key according to the static compare function.  Insert
-  // that element is not already in the list.  Assumes the list is
+  // that element if not already in the list.  Assumes the list is
   // already sorted according to compare function.
   template <int compare(const E&, const E&)> E insert_sorted(const E& key) {
     bool found;
diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
index febceba266c..d99e51462ba 100644
--- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
+++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
@@ -53,13 +53,13 @@ public class IRNode {
     private static final String STORE_OF_CLASS_POSTFIX = "(:|\\+)\\S* \\*" + END;
     private static final String LOAD_OF_CLASS_POSTFIX = "(:|\\+)\\S* \\*" + END;
 
-    public static final String ALLOC = "(.*precise klass .*\\R((.*(?i:mov|xorl|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_instance_Java" + END;
-    public static final String ALLOC_OF = COMPOSITE_PREFIX + "(.*precise klass .*" + IS_REPLACED + ":.*\\R((.*(?i:mov|xorl|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_instance_Java" + END;
-    public static final String ALLOC_ARRAY = "(.*precise klass \\[L.*\\R((.*(?i:mov|xor|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_array_Java" + END;
-    public static final String ALLOC_ARRAY_OF = COMPOSITE_PREFIX + "(.*precise klass \\[L.*" + IS_REPLACED + ";:.*\\R((.*(?i:mov|xorl|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_array_Java" + END;
+    public static final String ALLOC = "(.*precise .*\\R((.*(?i:mov|xorl|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_instance_Java" + END;
+    public static final String ALLOC_OF = COMPOSITE_PREFIX + "(.*precise .*" + IS_REPLACED + ":.*\\R((.*(?i:mov|xorl|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_instance_Java" + END;
+    public static final String ALLOC_ARRAY = "(.*precise \\[.*\\R((.*(?i:mov|xor|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_array_Java" + END;
+    public static final String ALLOC_ARRAY_OF = COMPOSITE_PREFIX + "(.*precise \\[.*" + IS_REPLACED + ":.*\\R((.*(?i:mov|xorl|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_array_Java" + END;
 
-    public static final String CHECKCAST_ARRAY = "(((?i:cmp|CLFI|CLR).*precise klass \\[.*;:|.*(?i:mov|or).*precise klass \\[.*;:.*\\R.*(cmp|CMP|CLR))" + END;
-    public static final String CHECKCAST_ARRAY_OF = COMPOSITE_PREFIX + "(((?i:cmp|CLFI|CLR).*precise klass \\[.*" + IS_REPLACED + ";:|.*(?i:mov|or).*precise klass \\[.*" + IS_REPLACED + ";:.*\\R.*(cmp|CMP|CLR))" + END;
+    public static final String CHECKCAST_ARRAY = "(((?i:cmp|CLFI|CLR).*precise \\[.*:|.*(?i:mov|or).*precise \\[.*:.*\\R.*(cmp|CMP|CLR))" + END;
+    public static final String CHECKCAST_ARRAY_OF = COMPOSITE_PREFIX + "(((?i:cmp|CLFI|CLR).*precise \\[.*" + IS_REPLACED + ":|.*(?i:mov|or).*precise klass \\[.*" + IS_REPLACED + ";:.*\\R.*(cmp|CMP|CLR))" + END;
     // Does not work on s390 (a rule containing this regex will be skipped on s390).
     public static final String CHECKCAST_ARRAYCOPY = "(.*((?i:call_leaf_nofp,runtime)|CALL,\\s?runtime leaf nofp|BCTRL.*.leaf call).*checkcast_arraycopy.*" + END;
 
diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java
index 8b6333d1e23..08fac4c871a 100644
--- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java
+++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java
@@ -207,9 +207,9 @@ public class TestIRMatching {
         } else {
             cmp = "cmp";
         }
-        runCheck(BadFailOnConstraint.create(CheckCastArray.class, "array()", 1, cmp, "precise klass"),
-                 BadFailOnConstraint.create(CheckCastArray.class, "array()", 2, 1,cmp, "precise klass", "MyClass"),
-                 BadFailOnConstraint.create(CheckCastArray.class, "array()", 2, 2,cmp, "precise klass", "ir_framework/tests/MyClass"),
+        runCheck(BadFailOnConstraint.create(CheckCastArray.class, "array()", 1, cmp, "precise"),
+                 BadFailOnConstraint.create(CheckCastArray.class, "array()", 2, 1,cmp, "precise", "MyClass"),
+                 BadFailOnConstraint.create(CheckCastArray.class, "array()", 2, 2,cmp, "precise", "ir_framework/tests/MyClass"),
                  GoodFailOnConstraint.create(CheckCastArray.class, "array()", 3),
                  Platform.isS390x() ? // There is no checkcast_arraycopy stub for C2 on s390
                      GoodFailOnConstraint.create(CheckCastArray.class, "arrayCopy(java.lang.Object[],java.lang.Class)", 1)