Refactoring type verification in Art.

Each type now has its own class instead of one class with enums.

Improved test cases for reg_type. Added test cases for testing precision, Merge,
Dump messages, etc.

Fixed bugs for:
        1- Creating precise references in cache was ignoring the passed parameter
        for reference types and only creating precise for final classes. Now creating
        for final classes or if boolean set to true.
        2- Precise constants were created if precise boolean passed as false ( and vice
           versa ). Fixed.

Change-Id: Ia5450d6c732f848e6b94298e43e8cfb819897fc6
diff --git a/src/runtime.cc b/src/runtime.cc
index f6fdef4..3e9cd8e 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -136,18 +136,16 @@
   // Make sure all other non-daemon threads have terminated, and all daemon threads are suspended.
   delete thread_list_;
   delete monitor_list_;
-
   delete class_linker_;
   delete heap_;
-  verifier::MethodVerifier::Shutdown();
   delete intern_table_;
   delete java_vm_;
   Thread::Shutdown();
   QuasiAtomic::Shutdown();
-
   // TODO: acquire a static mutex on Runtime to avoid racing.
   CHECK(instance_ == NULL || instance_ == this);
   instance_ = NULL;
+  verifier::MethodVerifier::Shutdown();
 }
 
 struct AbortState {
@@ -810,7 +808,6 @@
   thread_list_ = new ThreadList;
   intern_table_ = new InternTable;
 
-  verifier::MethodVerifier::Init();
 
   heap_ = new Heap(options->heap_initial_size_,
                    options->heap_growth_limit_,
@@ -850,6 +847,7 @@
     class_linker_ = ClassLinker::CreateFromCompiler(*options->boot_class_path_, intern_table_);
   }
   CHECK(class_linker_ != NULL);
+  verifier::MethodVerifier::Init();
 
   method_trace_ = options->method_trace_;
   method_trace_file_ = options->method_trace_file_;
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 6018bf8..01f5466 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -3325,6 +3325,7 @@
     MutexLock mu(self, *rejected_classes_lock_);
     rejected_classes_ = new MethodVerifier::RejectedClassesTable;
   }
+  art::verifier::RegTypeCache::Init();
 }
 
 void MethodVerifier::Shutdown() {
@@ -3345,6 +3346,7 @@
   }
   delete rejected_classes_lock_;
   rejected_classes_lock_ = NULL;
+  verifier::RegTypeCache::ShutDown();
 }
 
 void MethodVerifier::AddRejectedClass(CompilerDriver::ClassReference ref) {
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index 49bc808..ae43162 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -29,7 +29,7 @@
 #include "instruction_flags.h"
 #include "mirror/object.h"
 #include "reg_type.h"
-#include "reg_type_cache.h"
+#include "reg_type_cache-inl.h"
 #include "register_line.h"
 #include "safe_map.h"
 #include "UniquePtr.h"
@@ -192,7 +192,7 @@
                                std::vector<uint32_t>& monitor_enter_dex_pcs)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static void Init();
+  static void Init() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void Shutdown();
 
   static bool IsClassRejected(CompilerDriver::ClassReference ref)
diff --git a/src/verifier/reg_type.cc b/src/verifier/reg_type.cc
index 0cca343..774c2b2 100644
--- a/src/verifier/reg_type.cc
+++ b/src/verifier/reg_type.cc
@@ -16,157 +16,592 @@
 
 #include "reg_type.h"
 
+
+#include "base/casts.h"
 #include "dex_file-inl.h"
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "object_utils.h"
-#include "reg_type_cache.h"
+#include "reg_type_cache-inl.h"
 
 #include <limits>
+#include <sstream>
 
 namespace art {
 namespace verifier {
 
-static const char* type_strings[] = {
-    "Undefined",
-    "Conflict",
-    "boolean",
-    "byte",
-    "short",
-    "char",
-    "int",
-    "float",
-    "long (Low Half)",
-    "long (High Half)",
-    "double (Low Half)",
-    "double (High Half)",
-    "Precise 32-bit Constant",
-    "Imprecise 32-bit Constant",
-    "Precise 64-bit Constant (Low Half)",
-    "Precise 64-bit Constant (High Half)",
-    "Imprecise 64-bit Constant (Low Half)",
-    "Imprecise 64-bit Constant (High Half)",
-    "Unresolved Reference",
-    "Uninitialized Reference",
-    "Uninitialized This Reference",
-    "Unresolved And Uninitialized Reference",
-    "Unresolved And Uninitialized This Reference",
-    "Unresolved Merged References",
-    "Unresolved Super Class",
-    "Reference",
-    "Precise Reference",
-};
+static const bool kIsDebugBuild = false;
+UndefinedType* UndefinedType::instance_ = NULL;
+ConflictType* ConflictType::instance_ = NULL;
+BooleanType* BooleanType::instance = NULL;
+ByteType* ByteType::instance_ = NULL;
+ShortType* ShortType::instance_ = NULL;
+CharType* CharType::instance_ = NULL;
+FloatType* FloatType::instance_ = NULL;
+LongLoType* LongLoType::instance_ = NULL;
+LongHiType* LongHiType::instance_ = NULL;
+DoubleLoType* DoubleLoType::instance_ = NULL;
+DoubleHiType* DoubleHiType::instance_ = NULL;
+IntegerType* IntegerType::instance_ = NULL;
 
-std::string RegType::Dump(const RegTypeCache* reg_types) const {
-  DCHECK(type_ >=  kRegTypeUndefined && type_ <= kRegTypePreciseReference);
-  DCHECK(arraysize(type_strings) == (kRegTypePreciseReference + 1));
-  std::string result;
-  if (IsUnresolvedMergedReference()) {
-    if (reg_types == NULL) {
-      std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes();
-      result += StringPrintf("UnresolvedMergedReferences(%d, %d)", refs.first, refs.second);
-    } else {
-      std::set<uint16_t> types = GetMergedTypes(reg_types);
-      result += "UnresolvedMergedReferences(";
-      typedef std::set<uint16_t>::const_iterator It;  // TODO: C++0x auto
-      It it = types.begin();
-      result += reg_types->GetFromId(*it).Dump(reg_types);
-      for(++it; it != types.end(); ++it) {
-        result += ", ";
-        result += reg_types->GetFromId(*it).Dump(reg_types);
-      }
-      result += ")";
-    }
-  } else if (IsUnresolvedSuperClass()) {
-    uint16_t super_type_id = GetUnresolvedSuperClassChildId();
-    if (reg_types == NULL) {
-      result += StringPrintf("UnresolvedSuperClass(%d)", super_type_id);
-    } else {
-      result += "UnresolvedSuperClass(";
-      result += reg_types->GetFromId(super_type_id).Dump(reg_types);
-      result += ")";
-    }
-  } else if (IsConstant()) {
-    uint32_t val = ConstantValue();
-    if (val == 0) {
-      CHECK(IsPreciseConstant());
-      result = "Zero/null";
-    } else {
-      result = IsPreciseConstant() ? "Precise " : "Imprecise ";
-      if (IsConstantShort()) {
-        result += StringPrintf("Constant: %d", val);
-      } else {
-        result += StringPrintf("Constant: 0x%x", val);
-      }
-    }
-  } else if (IsConstantLo()) {
-    int32_t val = ConstantValueLo();
-    result = IsPreciseConstantLo() ? "Precise " : "Imprecise ";
-    if (val >= std::numeric_limits<jshort>::min() &&
-        val <= std::numeric_limits<jshort>::max()) {
-      result += StringPrintf("Low-half Constant: %d", val);
-    } else {
-      result += StringPrintf("Low-half Constant: 0x%x", val);
-    }
-  } else if (IsConstantHi()) {
-    int32_t val = ConstantValueHi();
-    result = IsPreciseConstantHi() ? "Precise " : "Imprecise ";
-    if (val >= std::numeric_limits<jshort>::min() &&
-        val <= std::numeric_limits<jshort>::max()) {
-      result += StringPrintf("High-half Constant: %d", val);
-    } else {
-      result += StringPrintf("High-half Constant: 0x%x", val);
-    }
+std::string PreciseConstType::Dump() const {
+  std::stringstream result;
+  uint32_t val = ConstantValue();
+  if (val == 0) {
+    CHECK(IsPreciseConstant());
+    result << "Zero/null";
   } else {
-    result = type_strings[type_];
-    if (IsReferenceTypes()) {
-      result += ": ";
-      if (IsUnresolvedTypes()) {
-        result += PrettyDescriptor(GetDescriptor());
-      } else {
-        result += PrettyDescriptor(GetClass());
-      }
+    result << "Precise ";
+    if (IsConstantShort()) {
+      result << StringPrintf("Constant: %d", val);
+    } else {
+      result << StringPrintf("Constant: 0x%x", val);
     }
   }
-  return result;
+  return result.str();
+}
+
+std::string BooleanType::Dump() const {
+  return "boolean";
+}
+
+std::string ConflictType::Dump() const {
+    return "Conflict";
+}
+std::string ByteType::Dump() const {
+  return "Byte";
+}
+std::string ShortType::Dump() const {
+  return "short";
+}
+std::string CharType::Dump() const {
+  return "Char";
+}
+std::string FloatType::Dump() const {
+  return "float";
+}
+std::string LongLoType::Dump() const {
+  return "long (Low Half)";
+}
+std::string LongHiType::Dump() const {
+  return "long (High Half)";
+}
+std::string DoubleLoType::Dump() const {
+  return "Double (Low Half)";
+}
+std::string DoubleHiType::Dump() const {
+  return "Double (High Half)";
+}
+std::string IntegerType::Dump() const {
+    return "Integer";
+}
+
+
+DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                           uint16_t cache_id) {
+  if (instance_ == NULL) {
+    instance_ = new DoubleHiType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+
+DoubleHiType* DoubleHiType::GetInstance() {
+  CHECK(instance_ != NULL);
+  return instance_;
+}
+
+void DoubleHiType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+
+DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                           uint16_t cache_id) {
+  if (instance_ == NULL) {
+    instance_ = new DoubleLoType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+
+DoubleLoType* DoubleLoType::GetInstance() {
+  CHECK(instance_ != NULL);
+  return instance_;
+}
+
+void DoubleLoType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+
+LongLoType* LongLoType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                       uint16_t cache_id) {
+  if (instance_ == NULL) {
+    instance_ = new LongLoType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+
+LongHiType* LongHiType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                       uint16_t cache_id) {
+  if (instance_ == NULL) {
+    instance_ = new LongHiType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+
+LongHiType* LongHiType::GetInstance() {
+  CHECK(instance_ != NULL);
+  return instance_;
+}
+
+void LongHiType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+
+LongLoType* LongLoType::GetInstance() {
+  CHECK (instance_ != NULL);
+  return instance_;
+}
+
+void LongLoType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+
+FloatType* FloatType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                     uint16_t cache_id)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (instance_ == NULL) {
+    instance_ = new FloatType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+FloatType* FloatType::GetInstance() {
+  CHECK(instance_ != NULL);
+  return instance_;
+}
+
+void FloatType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+
+CharType* CharType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                   uint16_t cache_id) {
+  if (instance_ == NULL) {
+    instance_ = new CharType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+CharType* CharType::GetInstance() {
+  CHECK(instance_ != NULL);
+  return instance_;
+}
+void CharType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+
+ShortType* ShortType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                     uint16_t cache_id) {
+  if (instance_ == NULL) {
+    instance_ = new ShortType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+ShortType* ShortType::GetInstance() {
+  CHECK(instance_ != NULL);
+  return instance_;
+}
+void ShortType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+ByteType* ByteType::CreateInstance(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (instance_ == NULL) {
+    instance_ = new ByteType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+ByteType* ByteType::GetInstance() {
+  CHECK(instance_ != NULL);
+  return instance_;
+}
+void ByteType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+IntegerType* IntegerType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                         uint16_t cache_id) {
+  if (instance_ == NULL) {
+    instance_ = new IntegerType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+IntegerType* IntegerType::GetInstance() {
+  CHECK(instance_ != NULL);
+  return instance_;
+}
+void IntegerType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+ConflictType* ConflictType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                           uint16_t cache_id) {
+  if (instance_ == NULL) {
+    instance_ = new ConflictType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+ConflictType* ConflictType::GetInstance() {
+  CHECK(instance_ != NULL);
+  return instance_;
+}
+void ConflictType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+BooleanType* BooleanType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                         uint16_t cache_id) {
+  if (BooleanType::instance == NULL) {
+    instance = new BooleanType(klass, descriptor, cache_id);
+  }
+  return BooleanType::instance;
+}
+BooleanType* BooleanType::GetInstance() {
+  CHECK(BooleanType::instance != NULL);
+  return BooleanType::instance;
+}
+
+void BooleanType::Destroy() {
+  if(BooleanType::instance != NULL) {
+    delete instance;
+    instance = NULL;
+  }
+}
+
+std::string UndefinedType::Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return "Undefined";
+}
+UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                             uint16_t cache_id) {
+  if (instance_ == NULL) {
+    instance_ = new UndefinedType(klass, descriptor, cache_id);
+  }
+  return instance_;
+}
+UndefinedType* UndefinedType::GetInstance() {
+  CHECK(instance_ != NULL);
+  return instance_;
+}
+void UndefinedType::Destroy() {
+  if (instance_ != NULL) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+std::string UnresolvedMergedType::Dump() const {
+  std::stringstream result;
+  std::set<uint16_t> types = GetMergedTypes();
+  result << "UnresolvedMergedReferences(";
+  typedef std::set<uint16_t>::const_iterator It;  // TODO: C++0x auto
+  It it = types.begin();
+  result << reg_type_cache_->GetFromId(*it).Dump();
+  for (++it; it != types.end(); ++it) {
+    result << ", ";
+    result << reg_type_cache_->GetFromId(*it).Dump();
+  }
+  result << ")";
+  return result.str();
+}
+std::string UnresolvedSuperClass::Dump() const {
+  std::stringstream result;
+  uint16_t super_type_id = GetUnresolvedSuperClassChildId();
+  result << "UnresolvedSuperClass(" << reg_type_cache_->GetFromId(super_type_id).Dump() << ")";
+  return result.str();
+}
+
+std::string UnresolvedReferenceType::Dump() const {
+  std::stringstream result;
+  result << "Unresolved Reference" << ": " << PrettyDescriptor(GetDescriptor());
+  return result.str();
+}
+
+std::string UnresolvedUninitializedRefType::Dump() const {
+  std::stringstream result;
+  result << "Unresolved And Uninitialized Reference" << ": " << PrettyDescriptor(GetDescriptor());
+  result << " Allocation PC: " << GetAllocationPc();
+  return result.str();
+}
+
+std::string UnresolvedUninitialisedThisRefType::Dump() const {
+  std::stringstream result;
+  result << "Unresolved And Uninitialized This Reference" << PrettyDescriptor(GetDescriptor());
+  return result.str();
+}
+
+std::string ReferenceType::Dump() const {
+  std::stringstream result;
+  result << "Reference" << ": " << PrettyDescriptor(GetClass());
+  return result.str();
+}
+
+std::string PreciseReferenceType::Dump() const {
+  std::stringstream result;
+  result << "Precise Reference" << ": "<< PrettyDescriptor(GetClass());
+  return result.str();
+}
+
+std::string UninitialisedReferenceType::Dump() const {
+  std::stringstream result;
+  result << "Uninitialized Reference" << ": " << PrettyDescriptor(GetClass());
+  result << " Allocation PC: " << GetAllocationPc();
+  return result.str();
+}
+std::string UninitialisedThisReferenceType::Dump() const {
+  std::stringstream result;
+  result << "Uninitialized This Reference" << ": " << PrettyDescriptor(GetClass());
+  result << "Allocation PC: " << GetAllocationPc();
+  return result.str();
+}
+
+std::string ImpreciseConstType::Dump() const {
+  std::stringstream result;
+  uint32_t val = ConstantValue();
+  if (val == 0) {
+    CHECK(IsPreciseConstant());
+    result << "Zero/null";
+  } else {
+    result << "Imprecise ";
+    if (IsConstantShort()) {
+      result << StringPrintf("Constant: %d", val);
+    } else {
+      result << StringPrintf("Constant: 0x%x", val);
+    }
+  }
+  return result.str();
+}
+std::string PreciseConstLoType::Dump() const {
+  std::stringstream result;
+
+  int32_t val = ConstantValueLo();
+  result << "Precise ";
+  if (val >= std::numeric_limits<jshort>::min() &&
+      val <= std::numeric_limits<jshort>::max()) {
+    result << StringPrintf("Low-half Constant: %d", val);
+  } else {
+    result << StringPrintf("Low-half Constant: 0x%x", val);
+  }
+  return result.str();
+}
+
+std::string ImpreciseConstLoType::Dump() const {
+  std::stringstream result;
+
+  int32_t val = ConstantValueLo();
+  result << "Imprecise ";
+  if (val >= std::numeric_limits<jshort>::min() &&
+      val <= std::numeric_limits<jshort>::max()) {
+    result << StringPrintf("Low-half Constant: %d", val);
+  } else {
+    result << StringPrintf("Low-half Constant: 0x%x", val);
+  }
+  return result.str();
+}
+
+std::string PreciseConstHiType::Dump() const {
+  std::stringstream result;
+  int32_t val = ConstantValueHi();
+  result << "Precise ";
+  if (val >= std::numeric_limits<jshort>::min() &&
+      val <= std::numeric_limits<jshort>::max()) {
+    result << StringPrintf("High-half Constant: %d", val);
+  } else {
+    result << StringPrintf("High-half Constant: 0x%x", val);
+  }
+  return result.str();
+}
+
+std::string ImpreciseConstHiType::Dump() const {
+  std::stringstream result;
+  int32_t val = ConstantValueHi();
+  result << "Imprecise ";
+  if (val >= std::numeric_limits<jshort>::min() &&
+      val <= std::numeric_limits<jshort>::max()) {
+    result << StringPrintf("High-half Constant: %d", val);
+  } else {
+    result << StringPrintf("High-half Constant: 0x%x", val);
+  }
+  return result.str();
+}
+
+BooleanType::BooleanType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      : RegType(klass, descriptor, cache_id) {
+}
+
+ConflictType::ConflictType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+ByteType::ByteType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+ShortType::ShortType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+CharType::CharType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+IntegerType::IntegerType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+ConstantType::ConstantType(uint32_t constat, uint16_t cache_id)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_): RegType(NULL, "", cache_id), constant_(constat) {
+}
+
+ReferenceType::ReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, std::string& descriptor,
+                                           uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+UnresolvedUninitialisedThisRefType::UnresolvedUninitialisedThisRefType(std::string& descriptor,
+                                                                       uint16_t cache_id)
+    : UninitializedType(NULL, descriptor, 0, cache_id) {
+}
+
+UnresolvedUninitializedRefType::UnresolvedUninitializedRefType( std::string& descriptor,
+                                                         uint32_t allocation_pc, uint16_t cache_id)
+    : UninitializedType(NULL, descriptor, allocation_pc, cache_id) {
+}
+
+UninitialisedReferenceType::UninitialisedReferenceType(mirror::Class* klass,
+                                std::string& descriptor, uint32_t allocation_pc, uint16_t cache_id)
+    : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
+}
+
+LongHiType::LongHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+FloatType::FloatType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+DoubleLoType::DoubleLoType(mirror::Class* klass,  std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+DoubleHiType::DoubleHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+LongLoType::LongLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+}
+
+const RegType& UndefinedType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (incoming_type.IsUndefined()) {
+    return *this;  // Undefined MERGE Undefined => Undefined
+  }
+  return reg_types->Conflict();
 }
 
 const RegType& RegType::HighHalf(RegTypeCache* cache) const {
   DCHECK(IsLowHalf());
-  if (type_ == kRegTypeLongLo) {
-    return cache->FromType(kRegTypeLongHi);
-  } else if (type_ == kRegTypeDoubleLo) {
-    return cache->FromType(kRegTypeDoubleHi);
+  if (IsLongLo()) {
+    return cache->LongHi();
+  } else if (IsDoubleLo()) {
+    return cache->DoubleHi();
   } else {
-    DCHECK_EQ(type_, kRegTypeImpreciseConstLo);
-    return cache->FromType(kRegTypeImpreciseConstHi);
+    DCHECK(IsImpreciseConstantLo());
+    return cache->FromCat2ConstHi(ConstantValue(), false);
   }
 }
 
-std::set<uint16_t> RegType::GetMergedTypes(const RegTypeCache* cache) const {
+Primitive::Type RegType::GetPrimitiveType() const {
+  if (IsNonZeroReferenceTypes()) {
+    return Primitive::kPrimNot;
+  } else if (IsBooleanTypes()) {
+    return Primitive::kPrimBoolean;
+  } else if (IsByteTypes()) {
+    return Primitive::kPrimByte;
+  } else if (IsShortTypes()) {
+    return Primitive::kPrimShort;
+  } else if (IsCharTypes()) {
+    return Primitive::kPrimChar;
+  } else if (IsFloat()) {
+    return Primitive::kPrimFloat;
+  } else if (IsIntegralTypes()) {
+    return Primitive::kPrimInt;
+  } else if (IsDoubleLo()) {
+    return Primitive::kPrimDouble;
+  } else {
+    DCHECK(IsLongTypes());
+    return Primitive::kPrimLong;
+  }
+}
+
+std::set<uint16_t> UnresolvedMergedType::GetMergedTypes() const {
   std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes();
-  const RegType& left = cache->GetFromId(refs.first);
-  const RegType& right = cache->GetFromId(refs.second);
+  const RegType& _left(reg_type_cache_->GetFromId(refs.first));
+  RegType& __left(const_cast<RegType&>(_left));
+  UnresolvedMergedType* left = down_cast<UnresolvedMergedType*>(&__left);
+
+  RegType& _right(
+      const_cast<RegType&>(reg_type_cache_->GetFromId(refs.second)));
+  UnresolvedMergedType* right = down_cast<UnresolvedMergedType*>(&_right);
+
   std::set<uint16_t> types;
-  if (left.IsUnresolvedMergedReference()) {
-    types = left.GetMergedTypes(cache);
+  if (left->IsUnresolvedMergedReference()) {
+    types = left->GetMergedTypes();
   } else {
     types.insert(refs.first);
   }
-  if (right.IsUnresolvedMergedReference()) {
-    std::set<uint16_t> right_types = right.GetMergedTypes(cache);
+  if (right->IsUnresolvedMergedReference()) {
+    std::set<uint16_t> right_types = right->GetMergedTypes();
     types.insert(right_types.begin(), right_types.end());
   } else {
     types.insert(refs.second);
   }
-#ifndef NDEBUG
-  typedef std::set<uint16_t>::const_iterator It;  // TODO: C++0x auto
-  for(It it = types.begin(); it != types.end(); ++it) {
-    CHECK(!cache->GetFromId(*it).IsUnresolvedMergedReference());
+  if (kIsDebugBuild) {
+    typedef std::set<uint16_t>::const_iterator It;  // TODO: C++0x auto
+    for (It it = types.begin(); it != types.end(); ++it) {
+      CHECK(!reg_type_cache_->GetFromId(*it).IsUnresolvedMergedReference());
+    }
   }
-#endif
   return types;
 }
 
@@ -200,13 +635,13 @@
     } else if (!other_unresolved) {
       return other.GetClass()->IsPublic();  // Be conservative, only allow if other is public.
     } else {
-      return false; // More complicated test not possible on unresolved types, be conservative.
+      return false;  // More complicated test not possible on unresolved types, be conservative.
     }
   }
 }
 
 bool RegType::CanAccessMember(mirror::Class* klass, uint32_t access_flags) const {
-  if (access_flags & kAccPublic) {
+  if ((access_flags & kAccPublic) != 0) {
     return true;
   }
   if (!IsUnresolvedTypes()) {
@@ -229,23 +664,6 @@
   }
 }
 
-bool RegType::IsConstantByte() const {
-  return IsConstant() &&
-      ConstantValue() >= std::numeric_limits<jbyte>::min() &&
-      ConstantValue() <= std::numeric_limits<jbyte>::max();
-}
-
-bool RegType::IsConstantShort() const {
-  return IsConstant() &&
-      ConstantValue() >= std::numeric_limits<jshort>::min() &&
-      ConstantValue() <= std::numeric_limits<jshort>::max();
-}
-
-bool RegType::IsConstantChar() const {
-  return IsConstant() && ConstantValue() >= 0 &&
-      ConstantValue() <= std::numeric_limits<jchar>::max();
-}
-
 bool RegType::IsJavaLangObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return IsReference() && GetClass()->IsObjectClass();
 }
@@ -272,30 +690,41 @@
   return IsUnresolvedTypes() || (IsNonZeroReferenceTypes() && GetClass()->IsInstantiable());
 }
 
+ImpreciseConstType::ImpreciseConstType(uint32_t constat, uint16_t cache_id)
+  : ConstantType(constat, cache_id) {
+}
+
 bool RegType::IsAssignableFrom(const RegType& src) const {
   if (Equals(src)) {
     return true;
   } else {
-    switch (GetType()) {
-      case RegType::kRegTypeBoolean:  return src.IsBooleanTypes();
-      case RegType::kRegTypeByte:     return src.IsByteTypes();
-      case RegType::kRegTypeShort:    return src.IsShortTypes();
-      case RegType::kRegTypeChar:     return src.IsCharTypes();
-      case RegType::kRegTypeInteger:  return src.IsIntegralTypes();
-      case RegType::kRegTypeFloat:    return src.IsFloatTypes();
-      case RegType::kRegTypeLongLo:   return src.IsLongTypes();
-      case RegType::kRegTypeDoubleLo: return src.IsDoubleTypes();
-      default:
-        if (!IsReferenceTypes()) {
-          LOG(FATAL) << "Unexpected register type in IsAssignableFrom: '" << src << "'";
-        }
-        if (src.IsZero()) {
-          return true;  // all reference types can be assigned null
-        } else if (!src.IsReferenceTypes()) {
-          return false;  // expect src to be a reference type
-        } else if (IsJavaLangObject()) {
-          return true;  // all reference types can be assigned to Object
-        } else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
+    if (IsBoolean()) {
+      return src.IsBooleanTypes();
+    } else if (IsByte()) {
+      return src.IsByteTypes();
+    } else if (IsShort()) {
+      return src.IsShortTypes();
+    } else if (IsChar()) {
+      return src.IsCharTypes();
+    } else if (IsInteger()) {
+      return src.IsIntegralTypes();
+    } else if (IsFloat()) {
+      return src.IsFloatTypes();
+    } else if (IsLongLo()) {
+      return src.IsLongTypes();
+    } else if (IsDoubleLo()) {
+      return src.IsDoubleTypes();
+    } else {
+      if (!IsReferenceTypes()) {
+        LOG(FATAL) << "Unexpected register type in 4bleFrom: '" << src << "'";
+      }
+      if (src.IsZero()) {
+        return true;  // all reference types can be assigned null
+      } else if (!src.IsReferenceTypes()) {
+        return false;  // expect src to be a reference type
+      } else if (IsJavaLangObject()) {
+        return true;  // all reference types can be assigned to Object
+      } else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
           return true;  // We allow assignment to any interface, see comment in ClassJoin
         } else if (IsJavaLangObjectArray()) {
           return src.IsObjectArrayTypes();  // All reference arrays may be assigned to Object[]
@@ -303,23 +732,39 @@
                    GetClass()->IsAssignableFrom(src.GetClass())) {
           // We're assignable from the Class point-of-view
           return true;
+        } else if (IsUnresolvedTypes()) {
+          // Unresolved types are only assignable for null, Object and equality.
+          return (src.IsZero() || src.IsJavaLangObject());
         } else {
-          // TODO: unresolved types are only assignable for null, Object and equality currently.
           return false;
         }
     }
   }
 }
 
+int32_t ConstantType::ConstantValue() const {
+  DCHECK(IsConstantTypes());
+  return constant_;
+}
+int32_t ConstantType::ConstantValueLo() const {
+  DCHECK(IsConstantLo());
+  return constant_;
+}
+int32_t ConstantType::ConstantValueHi() const {
+  if (IsConstantHi() || IsPreciseConstantHi() || IsImpreciseConstantHi()) {
+    return constant_;
+  } else {
+    DCHECK(false);
+    return 0;
+  }
+}
 static const RegType& SelectNonConstant(const RegType& a, const RegType& b) {
   return a.IsConstant() ? b : a;
 }
 
 const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const {
   DCHECK(!Equals(incoming_type));  // Trivial equality handled by caller
-  if (IsUndefined() && incoming_type.IsUndefined()) {
-    return *this;  // Undefined MERGE Undefined => Undefined
-  } else if (IsConflict()) {
+  if (IsConflict()) {
     return *this;  // Conflict MERGE * => Conflict
   } else if (incoming_type.IsConflict()) {
     return incoming_type;  // * MERGE Conflict => Conflict
@@ -497,40 +942,59 @@
 }
 
 void RegType::CheckInvariants() const {
-  bool checked = false;
   if (IsConstant() || IsConstantLo() || IsConstantHi()) {
-    // Constants: allocation_pc_or_constant_or_merged_types_ will hold the constant value, nothing
-    // else should be defined.
     CHECK(descriptor_.empty()) << *this;
     CHECK(klass_ == NULL) << *this;
-    checked = true;
   }
-  if (IsUnresolvedTypes()) {
-    if (IsUnresolvedMergedReference() || IsUnresolvedSuperClass()) {
-      // Unresolved super/merged types: allocation pc/merged types should be defined.
-      CHECK(descriptor_.empty()) << *this;
-      CHECK(klass_ == NULL) << *this;
-      CHECK_NE(allocation_pc_or_constant_or_merged_types_, 0U) << *this;
-    } else {
-      // Unresolved types: have a descriptor and no allocation pc/merged types.
-      CHECK(!descriptor_.empty()) << *this;
-      CHECK(klass_ == NULL) << *this;
-      if (!IsUnresolvedAndUninitializedReference()) {
-        CHECK_EQ(allocation_pc_or_constant_or_merged_types_, 0U) << *this;
-      }
-    }
-    checked = true;
-  }
-  if (IsReferenceTypes() && !checked) {
-    // A resolved reference type.
-    CHECK(descriptor_.empty()) << *this;
-    CHECK(klass_ != NULL) << *this;
-    CHECK(klass_->IsClass()) << *this;
-    if (!IsUninitializedReference()) {
-      CHECK_EQ(allocation_pc_or_constant_or_merged_types_, 0U) << *this;
-    }
-  }
-  CHECK(checked = true);
+}
+
+UninitializedType::UninitializedType(mirror::Class* klass, std::string& descriptor,
+                                     uint32_t allocation_pc, uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {
+}
+
+void UninitializedType::CheckInvariants() const {
+  CHECK_EQ(allocation_pc_, 0U) << *this;
+}
+
+void UninitialisedThisReferenceType::CheckInvariants() const {
+  UninitializedType::CheckInvariants();
+}
+
+UninitialisedThisReferenceType::UninitialisedThisReferenceType(mirror::Class* klass,
+  std::string& descriptor, uint16_t cache_id) : UninitializedType(klass, descriptor, 0, cache_id) {
+}
+
+void UnresolvedUninitialisedThisRefType::CheckInvariants() const {
+  UninitializedType::CheckInvariants();
+  CHECK(!descriptor_.empty()) << *this;
+  CHECK(klass_ == NULL) << *this;
+}
+
+void UnresolvedUninitializedRefType::CheckInvariants() const {
+  UninitializedType::CheckInvariants();
+  CHECK(!descriptor_.empty()) << *this;
+  CHECK(klass_ == NULL) << *this;
+}
+
+void UnresolvedMergedType::CheckInvariants() const {
+  // Unresolved merged types: merged types should be defined.
+  CHECK(descriptor_.empty()) << *this;
+  CHECK(klass_ == NULL) << *this;
+  CHECK_NE(merged_types_.first, 0U) << *this;
+  CHECK_NE(merged_types_.second, 0U) << *this;
+}
+
+void UnresolvedReferenceType::CheckInvariants() const {
+  CHECK(!descriptor_.empty()) << *this;
+  CHECK(klass_ == NULL) << *this;
+}
+
+void UnresolvedSuperClass::CheckInvariants() const {
+  // Unresolved merged types: merged types should be defined.
+  CHECK(descriptor_.empty()) << *this;
+  CHECK(klass_ == NULL) << *this;
+  CHECK_NE(unresolved_child_id_, 0U) << *this;
 }
 
 std::ostream& operator<<(std::ostream& os, const RegType& rhs) {
diff --git a/src/verifier/reg_type.h b/src/verifier/reg_type.h
index dc9a33a..94adfe3 100644
--- a/src/verifier/reg_type.h
+++ b/src/verifier/reg_type.h
@@ -22,6 +22,7 @@
 
 #include "jni.h"
 
+#include <limits>
 #include <stdint.h>
 #include <set>
 #include <string>
@@ -33,385 +34,766 @@
 namespace verifier {
 
 class RegTypeCache;
-
 /*
  * RegType holds information about the "type" of data held in a register.
  */
 class RegType {
  public:
-  enum Type {
-    // A special state that identifies a register as undefined.
-    kRegTypeUndefined = 0,
-    // The bottom type, used to denote the type of operations such as returning a void, throwing
-    // an exception or merging incompatible types, such as an int and a long.
-    kRegTypeConflict,
-    kRegTypeBoolean,        // Z.
-    kRegType1nrSTART = kRegTypeBoolean,
-    kRegTypeIntegralSTART = kRegTypeBoolean,
-    kRegTypeByte,           // B.
-    kRegTypeShort,          // S.
-    kRegTypeChar,           // C.
-    kRegTypeInteger,        // I.
-    kRegTypeIntegralEND = kRegTypeInteger,
-    kRegTypeFloat,          // F.
-    kRegType1nrEND = kRegTypeFloat,
-    kRegTypeLongLo,         // J - lower-numbered register; endian-independent.
-    kRegTypeLongHi,
-    kRegTypeDoubleLo,       // D.
-    kRegTypeDoubleHi,
-    kRegTypeLastFixedLocation = kRegTypeDoubleHi,
-    kRegTypePreciseConst,   // 32-bit constant - could be float or int.
-    kRegTypeImpreciseConst, // 32-bit constant derived value - could be float or int.
-    kRegTypePreciseConstLo, // Const wide, lower half - could be long or double.
-    kRegTypePreciseConstHi, // Const wide, upper half - could be long or double.
-    kRegTypeImpreciseConstLo, // Const derived wide, lower half - could be long or double.
-    kRegTypeImpreciseConstHi, // Const derived wide, upper half - could be long or double.
-    kRegTypeUnresolvedReference,        // Reference type that couldn't be resolved.
-    kRegTypeUninitializedReference,     // Freshly allocated reference type.
-    kRegTypeUninitializedThisReference, // Freshly allocated reference passed as "this".
-    kRegTypeUnresolvedAndUninitializedReference, // Freshly allocated unresolved reference type.
-                                        // Freshly allocated unresolved reference passed as "this".
-    kRegTypeUnresolvedAndUninitializedThisReference,
-    kRegTypeUnresolvedMergedReference,  // Tree of merged references (at least 1 is unresolved).
-    kRegTypeUnresolvedSuperClass,       // Super class of an unresolved type.
-    kRegTypeReference,                  // Reference type.
-    kRegTypePreciseReference,           // Precisely the given type.
-  };
-
-  Type GetType() const {
-    return type_;
+  // The high half that corresponds to this low half
+  const RegType& HighHalf(RegTypeCache* cache) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  inline virtual bool IsUndefined() const {
+    return false;
   }
-
-  bool IsUndefined() const { return type_ == kRegTypeUndefined; }
-  bool IsConflict() const { return type_ == kRegTypeConflict; }
-  bool IsBoolean() const { return type_ == kRegTypeBoolean; }
-  bool IsByte()    const { return type_ == kRegTypeByte; }
-  bool IsChar()    const { return type_ == kRegTypeChar; }
-  bool IsShort()   const { return type_ == kRegTypeShort; }
-  bool IsInteger() const { return type_ == kRegTypeInteger; }
-  bool IsLong()    const { return type_ == kRegTypeLongLo; }
-  bool IsFloat()   const { return type_ == kRegTypeFloat; }
-  bool IsDouble()  const { return type_ == kRegTypeDoubleLo; }
-  bool IsUnresolvedReference() const { return type_ == kRegTypeUnresolvedReference; }
-  bool IsUninitializedReference() const { return type_ == kRegTypeUninitializedReference; }
-  bool IsUninitializedThisReference() const { return type_ == kRegTypeUninitializedThisReference; }
-  bool IsUnresolvedAndUninitializedReference() const {
-    return type_ == kRegTypeUnresolvedAndUninitializedReference;
+  inline virtual bool IsConflict() const {
+    return false;
   }
-  bool IsUnresolvedAndUninitializedThisReference() const {
-    return type_ == kRegTypeUnresolvedAndUninitializedThisReference;
+  inline virtual bool IsBoolean() const {
+    return false;
   }
-  bool IsUnresolvedMergedReference() const {  return type_ == kRegTypeUnresolvedMergedReference; }
-  bool IsUnresolvedSuperClass() const {  return type_ == kRegTypeUnresolvedSuperClass; }
-  bool IsReference() const { return type_ == kRegTypeReference; }
-  bool IsPreciseReference() const { return type_ == kRegTypePreciseReference; }
-
-  bool IsUninitializedTypes() const {
-    return IsUninitializedReference() || IsUninitializedThisReference() ||
-        IsUnresolvedAndUninitializedReference() || IsUnresolvedAndUninitializedThisReference();
+  inline virtual bool IsByte() const {
+    return false;
   }
-  bool IsUnresolvedTypes() const {
-    return IsUnresolvedReference() || IsUnresolvedAndUninitializedReference() ||
-        IsUnresolvedAndUninitializedThisReference() || IsUnresolvedMergedReference() ||
-        IsUnresolvedSuperClass();
+  inline virtual bool IsChar() const {
+    return false;
   }
-  bool IsLowHalf() const {
-    return type_ == kRegTypeLongLo ||
-           type_ == kRegTypeDoubleLo ||
-           type_ == kRegTypePreciseConstLo ||
-           type_ == kRegTypeImpreciseConstLo;
+  inline virtual bool IsShort() const {
+    return false;
   }
-  bool IsHighHalf() const {
-    return type_ == kRegTypeLongHi ||
-           type_ == kRegTypeDoubleHi ||
-           type_ == kRegTypePreciseConstHi ||
-           type_ == kRegTypeImpreciseConstHi;
+  inline virtual bool IsInteger() const {
+    return false;
   }
-
-  bool IsLongOrDoubleTypes() const { return IsLowHalf(); }
-
-  // Check this is the low half, and that type_h is its matching high-half
-  bool CheckWidePair(const RegType& type_h) const {
-    if (IsLowHalf()) {
-      return (type_h.type_ == type_ + 1) ||
-          (IsPreciseConstantLo() && type_h.IsImpreciseConstantHi()) ||
-          (IsImpreciseConstantLo() && type_h.IsPreciseConstantHi());
-    }
+  inline virtual bool IsLongLo() const {
+    return false;
+  }
+  inline virtual bool IsLongHi() const {
+    return false;
+  }
+  inline virtual bool IsFloat() const {
+    return false;
+  }
+  inline virtual bool IsDouble() const {
+    return false;
+  }
+  inline virtual bool IsDoubleLo() const {
+    return false;
+  }
+  inline virtual bool IsDoubleHi() const {
+    return false;
+  }
+  inline virtual bool IsUnresolvedReference() const {
+    return false;
+  }
+  inline virtual bool IsUninitializedReference() const {
+    return false;
+  }
+  inline virtual bool IsUninitializedThisReference() const {
+    return false;
+  }
+  inline virtual bool IsUnresolvedAndUninitializedReference() const {
+    return false;
+  }
+  inline virtual bool IsUnresolvedAndUninitializedThisReference() const {
+    return false;
+  }
+  inline virtual bool IsUnresolvedMergedReference() const {
+    return false;
+  }
+  inline virtual bool IsUnresolvedSuperClass() const {
+    return false;
+  }
+  inline virtual bool IsReference() const {
+    return false;
+  }
+  inline virtual bool IsPreciseReference() const {
+    return false;
+  }
+  inline virtual bool IsPreciseConstant() const {
+    return false;
+  }
+  inline virtual bool IsPreciseConstantLo() const {
+    return false;
+  }
+  inline virtual bool IsPreciseConstantHi() const {
+    return false;
+  }
+  inline virtual bool IsImpreciseConstantLo() const {
+    return false;
+  }
+  inline virtual bool IsImpreciseConstantHi() const {
+    return false;
+  }
+  virtual bool IsImpreciseConstant() const {
     return false;
   }
 
-  // The high half that corresponds to this low half
-  const RegType& HighHalf(RegTypeCache* cache) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  bool IsPreciseConstant() const {
-    return type_ == kRegTypePreciseConst;
-  }
-  bool IsPreciseConstantLo() const {
-    return type_ == kRegTypePreciseConstLo;
-  }
-  bool IsPreciseConstantHi() const {
-    return type_ == kRegTypePreciseConstHi;
-  }
-  bool IsImpreciseConstantLo() const {
-    return type_ == kRegTypeImpreciseConstLo;
-  }
-  bool IsImpreciseConstantHi() const {
-    return type_ == kRegTypeImpreciseConstHi;
+  inline virtual bool IsConstantTypes() const {
+    return false;
   }
   bool IsConstant() const {
-    return type_ == kRegTypePreciseConst || type_ == kRegTypeImpreciseConst;
+    return (IsPreciseConstant() || IsImpreciseConstant());
   }
-
   bool IsConstantLo() const {
-    return type_ == kRegTypePreciseConstLo || type_ == kRegTypeImpreciseConstLo;
+    return (IsPreciseConstantLo() || IsImpreciseConstantLo());
+  }
+  bool IsPrecise() const {
+    return (IsPreciseConstantLo() || IsPreciseConstant() ||
+            IsPreciseConstantHi());
   }
   bool IsLongConstant() const {
     return IsConstantLo();
   }
   bool IsConstantHi() const {
-    return type_ == kRegTypePreciseConstHi || type_ == kRegTypeImpreciseConstHi;
+    return (IsPreciseConstantHi() || IsImpreciseConstantHi());
   }
   bool IsLongConstantHigh() const {
     return IsConstantHi();
   }
-
-  // If this is a 32-bit constant, what is the value? This value may be imprecise in which case
-  // the value represents part of the integer range of values that may be held in the register.
-  int32_t ConstantValue() const {
-    DCHECK(IsConstant());
-    return allocation_pc_or_constant_or_merged_types_;
+  bool IsUninitializedTypes() const {
+    return IsUninitializedReference() || IsUninitializedThisReference() ||
+           IsUnresolvedAndUninitializedReference() ||
+           IsUnresolvedAndUninitializedThisReference();
   }
-  int32_t ConstantValueLo() const {
-    DCHECK(IsConstantLo());
-    return allocation_pc_or_constant_or_merged_types_;
-  }
-  int32_t ConstantValueHi() const {
-    DCHECK(IsConstantHi());
-    return allocation_pc_or_constant_or_merged_types_;
+  bool IsUnresolvedTypes() const {
+    return IsUnresolvedReference() || IsUnresolvedAndUninitializedReference() ||
+           IsUnresolvedAndUninitializedThisReference() ||
+           IsUnresolvedMergedReference() || IsUnresolvedSuperClass();
   }
 
-  bool IsZero()         const { return IsPreciseConstant() && ConstantValue() == 0; }
-  bool IsOne()          const { return IsPreciseConstant() && ConstantValue() == 1; }
+  bool IsLowHalf() const {
+    return (IsLongLo() || IsDoubleLo() || IsPreciseConstantLo() ||
+            IsImpreciseConstantLo());
+  }
+  bool IsHighHalf() const {
+    return (IsLongHi() || IsDoubleHi() || IsPreciseConstantHi() ||
+            IsImpreciseConstantHi());
+  }
+  bool IsLongOrDoubleTypes() const {
+    return IsLowHalf();
+  }
+  // Check this is the low half, and that type_h is its matching high-half
+  inline bool CheckWidePair(const RegType& type_h) const {
+    return true;
+    if (IsLowHalf()) {
+      return ((IsPreciseConstantLo() && type_h.IsImpreciseConstantHi()) ||
+              (IsImpreciseConstantLo() && type_h.IsPreciseConstantHi()) ||
+              (IsDoubleLo() && type_h.IsDoubleHi()) ||
+              (IsLongLo() && type_h.IsLongHi()));
+    }
+    return false;
+  }
   bool IsConstantBoolean() const {
-    return IsConstant() && ConstantValue() >= 0 && ConstantValue() <= 1;
+    return IsConstant() && (ConstantValue() >= 0) && (ConstantValue() <= 1);
   }
-  bool IsConstantByte() const;
-  bool IsConstantShort() const;
-  bool IsConstantChar() const;
-
+  inline virtual bool IsConstantChar() const {
+    return false;
+  }
+  inline virtual bool IsConstantByte() const {
+    return false;
+  }
+  inline virtual bool IsConstantShort() const {
+    return false;
+  }
+  inline virtual bool IsOne() const {
+    return false;
+  }
+  inline virtual bool IsZero() const {
+    return false;
+  }
   bool IsReferenceTypes() const {
     return IsNonZeroReferenceTypes() || IsZero();
   }
-
   bool IsNonZeroReferenceTypes() const {
-    return IsReference() || IsPreciseReference() || IsUnresolvedReference() ||
-        IsUninitializedReference() || IsUninitializedThisReference() ||
-        IsUnresolvedAndUninitializedReference() || IsUnresolvedAndUninitializedThisReference() ||
-        IsUnresolvedMergedReference() || IsUnresolvedSuperClass();
+    return IsReference() || IsPreciseReference() ||
+           IsUninitializedReference() || IsUninitializedThisReference() ||
+           IsUnresolvedReference() || IsUnresolvedAndUninitializedReference() ||
+           IsUnresolvedAndUninitializedThisReference() ||
+           IsUnresolvedMergedReference() || IsUnresolvedSuperClass();
   }
-
   bool IsCategory1Types() const {
-    return (type_ >= kRegType1nrSTART && type_ <= kRegType1nrEND) || IsConstant();
+    return (IsBoolean() || IsByte() || IsShort() || IsChar() || IsInteger() ||
+            IsFloat() || IsConstant());
   }
-
   bool IsCategory2Types() const {
     return IsLowHalf();  // Don't expect explicit testing of high halves
   }
-
-  bool IsBooleanTypes() const { return IsBoolean() || IsConstantBoolean(); }
-  bool IsByteTypes() const { return IsByte() || IsBoolean() || IsConstantByte(); }
-  bool IsShortTypes() const { return IsShort() || IsByte() || IsBoolean() || IsConstantShort(); }
-  bool IsCharTypes() const { return IsChar() || IsBooleanTypes() || IsConstantChar(); }
-  bool IsIntegralTypes() const {
-    return (type_ >= kRegTypeIntegralSTART && type_ <= kRegTypeIntegralEND) || IsConstant();
+  bool IsBooleanTypes() const {
+    return IsBoolean() || IsConstantBoolean();
   }
-  bool IsArrayIndexTypes() const { return IsIntegralTypes(); }
-
+  bool IsByteTypes() const {
+    return IsByte() || IsBoolean() || IsConstantByte();
+  }
+  bool IsShortTypes() const {
+    return IsShort() || IsByte() || IsBoolean() || IsConstantShort();
+  }
+  bool IsCharTypes() const {
+    return IsChar() || IsBooleanTypes() || IsConstantChar();
+  }
+  bool IsIntegralTypes() const {
+    return (IsBoolean() || IsByte() || IsShort() || IsChar() || IsInteger() || IsConstant());
+  }
+  inline virtual int32_t ConstantValue() const {
+    CHECK(IsConstant());
+    return -1;
+  }
+  inline virtual int32_t ConstantValueLo() const {
+    CHECK(IsConstantLo());
+    return -1;
+  }
+  inline virtual int32_t ConstantValueHi() const {
+    CHECK(IsConstantHi());
+    return -1;
+  }
+  bool IsArrayIndexTypes() const {
+    return IsIntegralTypes();
+  }
   // Float type may be derived from any constant type
-  bool IsFloatTypes() const { return IsFloat() || IsConstant(); }
-
+  bool IsFloatTypes() const {
+    return IsFloat() || IsConstant();
+  }
   bool IsLongTypes() const {
-    return IsLong() || IsLongConstant();
+    return IsLongLo() || IsLongConstant();
   }
   bool IsLongHighTypes() const {
-    return type_ == kRegTypeLongHi ||
-           type_ == kRegTypePreciseConstHi ||
-           type_ == kRegTypeImpreciseConstHi;
+    return (IsLongConstantHigh() || IsPreciseConstantHi() ||
+            IsImpreciseConstantHi());
   }
   bool IsDoubleTypes() const {
-    return IsDouble() || IsLongConstant();
+    return IsDoubleLo() || IsLongConstant();
   }
   bool IsDoubleHighTypes() const {
-    return type_ == kRegTypeDoubleHi ||
-           type_ == kRegTypePreciseConstHi ||
-           type_ == kRegTypeImpreciseConstHi;
+    return (IsDoubleHi() || IsPreciseConstantHi() || IsImpreciseConstantHi());
   }
-
-  uint32_t GetAllocationPc() const {
-    DCHECK(IsUninitializedTypes());
-    return allocation_pc_or_constant_or_merged_types_;
+  inline virtual bool IsLong() const {
+    return false;
   }
-
   bool HasClass() const {
-    return IsReference() || IsPreciseReference();
+    return IsReference() || IsPreciseReference() || IsUninitializedReference() ||
+           IsUninitializedThisReference();
   }
-
-  mirror::Class* GetClass() const {
-    DCHECK(!IsUnresolvedReference());
-    DCHECK(klass_ != NULL);
-    return klass_;
-  }
-
   bool IsJavaLangObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   bool IsArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   bool IsObjectArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  Primitive::Type GetPrimitiveType() const {
-    if (IsNonZeroReferenceTypes()) {
-      return Primitive::kPrimNot;
-    } else if (IsBooleanTypes()) {
-      return Primitive::kPrimBoolean;
-    } else if (IsByteTypes()) {
-      return Primitive::kPrimByte;
-    } else if (IsShortTypes()) {
-      return Primitive::kPrimShort;
-    } else if (IsCharTypes()) {
-      return Primitive::kPrimChar;
-    } else if (IsFloat()) {
-      return Primitive::kPrimFloat;
-    } else if (IsIntegralTypes()) {
-      return Primitive::kPrimInt;
-    } else if (IsDouble()) {
-      return Primitive::kPrimDouble;
-    } else {
-      DCHECK(IsLongTypes());
-      return Primitive::kPrimLong;
-    }
-  }
-
+  Primitive::Type GetPrimitiveType() const ;
   bool IsJavaLangObjectArray() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   bool IsInstantiableTypes() const;
-
   std::string GetDescriptor() const {
     DCHECK(IsUnresolvedTypes() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass());
     return descriptor_;
   }
-
   uint16_t GetId() const {
     return cache_id_;
   }
-
-  // The top of a tree of merged types.
-  std::pair<uint16_t, uint16_t> GetTopMergedTypes() const {
-    DCHECK(IsUnresolvedMergedReference());
-    uint16_t type1 = static_cast<uint16_t>(allocation_pc_or_constant_or_merged_types_ & 0xFFFF);
-    uint16_t type2 = static_cast<uint16_t>(allocation_pc_or_constant_or_merged_types_ >> 16);
-    return std::pair<uint16_t, uint16_t>(type1, type2);
-  }
-
-  // The complete set of merged types.
-  std::set<uint16_t> GetMergedTypes(const RegTypeCache* cache) const;
-
-  uint16_t GetUnresolvedSuperClassChildId() const {
-    DCHECK(IsUnresolvedSuperClass());
-    return static_cast<uint16_t>(allocation_pc_or_constant_or_merged_types_ & 0xFFFF);
-  }
-
   const RegType& GetSuperClass(RegTypeCache* cache) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  std::string Dump(const RegTypeCache* reg_types = NULL) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
   // Can this type access other?
-  bool CanAccess(const RegType& other) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool CanAccess(const RegType& other) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Can this type access a member with the given properties?
   bool CanAccessMember(mirror::Class* klass, uint32_t access_flags) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Can this type be assigned by src?
-  bool IsAssignableFrom(const RegType& src) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  bool Equals(const RegType& other) const { return GetId() == other.GetId(); }
-
+  bool IsAssignableFrom(const RegType& src) const  SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool Equals(const RegType& other) const {
+    return GetId() == other.GetId();
+  }
   // Compute the merge of this register from one edge (path) with incoming_type from another.
-  const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
+  virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  mirror::Class* GetClass() const {
+    DCHECK(!IsUnresolvedReference());
+    DCHECK(klass_ != NULL);
+    DCHECK(HasClass());
+    return klass_;
+  }
+    /*
+     * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
+     * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
+     * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
+     * is the deepest (lowest upper bound) parent of S and T).
+     *
+     * This operation applies for regular classes and arrays, however, for interface types there needn't
+     * be a partial ordering on the types. We could solve the problem of a lack of a partial order by
+     * introducing sets of types, however, the only operation permissible on an interface is
+     * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
+     * types until an invoke-interface call on the interface typed reference at runtime and allow
+     * the perversion of Object being assignable to an interface type (note, however, that we don't
+     * allow assignment of Object or Interface to any concrete class and are therefore type safe).
+     *
+     * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
+     */
 
-  /*
-   * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
-   * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
-   * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
-   * is the deepest (lowest upper bound) parent of S and T).
-   *
-   * This operation applies for regular classes and arrays, however, for interface types there needn't
-   * be a partial ordering on the types. We could solve the problem of a lack of a partial order by
-   * introducing sets of types, however, the only operation permissible on an interface is
-   * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
-   * types until an invoke-interface call on the interface typed reference at runtime and allow
-   * the perversion of Object being assignable to an interface type (note, however, that we don't
-   * allow assignment of Object or Interface to any concrete class and are therefore type safe).
-   *
-   * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
-   */
   static mirror::Class* ClassJoin(mirror::Class* s, mirror::Class* t)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- private:
+  RegType(mirror::Class* klass, std::string descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : descriptor_(descriptor), klass_(klass), cache_id_(cache_id) {
+  }
+  inline virtual ~RegType() {
+  }
+  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   friend class RegTypeCache;
 
-  RegType(Type type, mirror::Class* klass,
-          uint32_t allocation_pc_or_constant_or_merged_types, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : type_(type), klass_(klass),
-        allocation_pc_or_constant_or_merged_types_(allocation_pc_or_constant_or_merged_types),
-        cache_id_(cache_id) {
-#ifndef NDEBUG
-    CheckInvariants();
-#endif
-  }
-
-  RegType(Type type, const std::string& descriptor, uint32_t allocation_pc, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : type_(type),
-        klass_(NULL),
-        descriptor_(descriptor),
-        allocation_pc_or_constant_or_merged_types_(allocation_pc),
-        cache_id_(cache_id) {
-#ifndef NDEBUG
-    CheckInvariants();
-#endif
-  }
-
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  const Type type_;  // The current type of the register
-
-  // For reference types, if known the type of the register...
+ protected:
+  const std::string descriptor_;
   mirror::Class* klass_;
-  // ...else a String for the descriptor.
-  std::string descriptor_;
-
-  // Overloaded field that:
-  //   - if IsConstant() holds a 32bit constant value
-  //   - is IsUninitializedReference()/IsUnresolvedAndUninitializedReference() holds the pc the
-  //     instance in the register was being allocated.
-  const uint32_t allocation_pc_or_constant_or_merged_types_;
-
-  // A RegType cache densely encodes types, this is the location in the cache for this type
   const uint16_t cache_id_;
 
   DISALLOW_COPY_AND_ASSIGN(RegType);
 };
+
+class ConflictType : public RegType {
+ public:
+  inline virtual bool IsConflict() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ConflictType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                      uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ConflictType* GetInstance();
+  static void Destroy();
+ private:
+  ConflictType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ConflictType* instance_;
+};
+
+class UndefinedType : public RegType {
+ public:
+  inline virtual bool IsUndefined() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static UndefinedType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                       uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static UndefinedType* GetInstance();
+  static void Destroy();
+ private:
+  UndefinedType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : RegType(klass, descriptor, cache_id) {
+  }
+  virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static UndefinedType* instance_;
+};
+
+class IntegerType : public RegType {
+ public:
+  inline virtual bool IsInteger() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static IntegerType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                     uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static IntegerType* GetInstance();
+  static void Destroy();
+ private:
+  IntegerType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static IntegerType* instance_;
+};
+
+class BooleanType : public RegType {
+ public:
+  inline virtual bool IsBoolean() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static BooleanType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                     uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static BooleanType* GetInstance();
+  static void Destroy();
+ private:
+  BooleanType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static BooleanType* instance;
+};
+
+class ByteType : public RegType {
+ public:
+  inline virtual bool IsByte() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ByteType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                  uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ByteType* GetInstance();
+  static void Destroy();
+ private:
+  ByteType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ByteType* instance_;
+};
+
+class ShortType : public RegType {
+ public:
+  inline virtual bool IsShort() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ShortType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                   uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ShortType* GetInstance();
+  static void Destroy();
+ private:
+  ShortType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ShortType* instance_;
+};
+
+class CharType : public RegType {
+ public:
+  inline virtual bool IsChar() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static CharType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                  uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static CharType* GetInstance();
+  static void Destroy();
+ private:
+  CharType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static CharType* instance_;
+};
+
+class FloatType : public RegType {
+ public:
+  inline virtual bool IsFloat() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static FloatType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                   uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static FloatType* GetInstance();
+  static void Destroy();
+ private:
+  FloatType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static FloatType* instance_;
+};
+
+class LongLoType : public RegType {
+ public:
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  inline virtual bool IsLongLo() const {
+    return true;
+  }
+  inline virtual bool IsLong() const {
+    return true;
+  }
+  static LongLoType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                    uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+   static LongLoType* GetInstance();
+  static void Destroy();
+ private:
+  LongLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static LongLoType* instance_;
+};
+
+class LongHiType : public RegType {
+ public:
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  inline virtual bool IsLongHi() const {
+    return true;
+  }
+  static LongHiType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                    uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static LongHiType* GetInstance();
+  static void Destroy();
+ private:
+  LongHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static LongHiType* instance_;
+};
+
+class DoubleLoType : public RegType {
+ public:
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  inline virtual bool IsDoubleLo() const {
+    return true;
+  }
+  inline virtual bool IsDouble() const {
+    return true;
+  }
+  static DoubleLoType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                      uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static DoubleLoType* GetInstance();
+  static void Destroy();
+ private:
+  DoubleLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static DoubleLoType* instance_;
+};
+
+class DoubleHiType : public RegType {
+ public:
+  virtual std::string Dump() const;
+  inline virtual bool IsDoubleHi() const {
+    return true;
+  }
+  static DoubleHiType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+                                      uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static DoubleHiType* GetInstance();
+  static void Destroy();
+ private:
+  DoubleHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static DoubleHiType* instance_;
+};
+
+class ConstantType : public RegType {
+ public:
+  ConstantType(uint32_t constat, uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  inline virtual ~ConstantType() {
+  }
+  const uint32_t constant_;
+  // If this is a 32-bit constant, what is the value? This value may be imprecise in which case
+  // the value represents part of the integer range of values that may be held in the register.
+  virtual int32_t ConstantValue() const;
+  virtual int32_t ConstantValueLo() const;
+  virtual int32_t ConstantValueHi() const;
+
+  bool IsZero() const {
+    return IsPreciseConstant() && ConstantValue() == 0;
+  }
+  bool IsOne() const {
+    return IsPreciseConstant() && ConstantValue() == 1;
+  }
+
+  bool IsConstantChar() const {
+    return IsConstant() && ConstantValue() >= 0 &&
+           ConstantValue() <= std::numeric_limits<jchar>::max();
+  }
+  bool IsConstantByte() const {
+    return IsConstant() &&
+           ConstantValue() >= std::numeric_limits<jbyte>::min() &&
+           ConstantValue() <= std::numeric_limits<jbyte>::max();
+  }
+  bool IsConstantShort() const {
+    return IsConstant() &&
+           ConstantValue() >= std::numeric_limits<jshort>::min() &&
+           ConstantValue() <= std::numeric_limits<jshort>::max();
+  }
+  inline virtual bool IsConstantTypes() const { return true; }
+};
+class PreciseConstType : public ConstantType {
+ public:
+  PreciseConstType(uint32_t constat, uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : ConstantType(constat, cache_id) {
+  }
+
+  inline virtual bool IsPreciseConstant() const {
+    return true;
+  }
+
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+class PreciseConstLoType : public ConstantType {
+ public:
+  PreciseConstLoType(uint32_t constat, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : ConstantType(constat, cache_id) {
+  }
+  inline virtual bool IsPreciseConstantLo() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+class PreciseConstHiType : public ConstantType {
+ public:
+  PreciseConstHiType(uint32_t constat, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : ConstantType(constat, cache_id) {
+  }
+  inline virtual bool IsPreciseConstantHi() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class ImpreciseConstType : public ConstantType {
+ public:
+  ImpreciseConstType(uint32_t constat, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual  bool IsImpreciseConstant() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+class ImpreciseConstLoType : public ConstantType {
+ public:
+  ImpreciseConstLoType(uint32_t constat, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : ConstantType(constat, cache_id) {
+  }
+  inline virtual bool IsImpreciseConstantLo() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+class ImpreciseConstHiType : public ConstantType {
+ public:
+  ImpreciseConstHiType(uint32_t constat, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : ConstantType(constat, cache_id) {
+  }
+  inline virtual bool IsImpreciseConstantHi() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+class UninitializedType : public RegType {
+ public:
+  UninitializedType(mirror::Class* klass, std::string& descriptor, uint32_t allocation_pc,
+                    uint16_t cache_id);
+  inline virtual ~UninitializedType() {
+  }
+
+  uint32_t GetAllocationPc() const {
+    DCHECK(IsUninitializedTypes());
+    return allocation_pc_;
+  }
+  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  const uint32_t allocation_pc_;
+};
+
+class UninitialisedReferenceType : public UninitializedType {
+ public:
+  UninitialisedReferenceType(mirror::Class* klass, std::string& descriptor, uint32_t allocation_pc,
+                             uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  inline virtual bool IsUninitializedReference() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class UnresolvedUninitializedRefType : public UninitializedType {
+ public:
+  UnresolvedUninitializedRefType(std::string& descriptor, uint32_t allocation_pc,
+                                 uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  inline virtual bool IsUnresolvedAndUninitializedReference() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class UninitialisedThisReferenceType : public UninitializedType {
+ public:
+  UninitialisedThisReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  inline virtual bool IsUninitializedThisReference() const {
+    return true;
+  }
+};
+class UnresolvedUninitialisedThisRefType : public UninitializedType {
+ public:
+  UnresolvedUninitialisedThisRefType(std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  inline virtual bool IsUnresolvedAndUninitializedThisReference() const {
+    return true;
+  }
+};
+
+class ReferenceType : public RegType {
+ public:
+  ReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  inline virtual bool IsReference() const {
+    return true;
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class PreciseReferenceType : public RegType {
+ public:
+  PreciseReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  inline virtual bool IsPreciseReference() const {
+    return true;
+  }
+};
+
+class UnresolvedReferenceType : public RegType {
+ public:
+  UnresolvedReferenceType(std::string& descriptor, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : RegType(NULL, descriptor, cache_id) {
+  }
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  inline virtual bool IsUnresolvedReference() const {
+    return true;
+  }
+};
+
+class UnresolvedSuperClass : public RegType {
+ public:
+  UnresolvedSuperClass(uint16_t child_id, RegTypeCache* reg_type_cache, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : RegType(NULL, "", cache_id), unresolved_child_id_(child_id),
+        reg_type_cache_(reg_type_cache) {
+  }
+  inline virtual bool IsUnresolvedSuperClass() const {
+    return true;
+  }
+  uint16_t GetUnresolvedSuperClassChildId() const {
+    DCHECK(IsUnresolvedSuperClass());
+    return static_cast<uint16_t>(unresolved_child_id_ & 0xFFFF);
+  }
+  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+ const uint16_t unresolved_child_id_;
+ const RegTypeCache* const reg_type_cache_;
+};
+
+class UnresolvedMergedType : public RegType {
+ public:
+  UnresolvedMergedType(uint16_t left_id, uint16_t right_id, const RegTypeCache* reg_type_cache, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : RegType(NULL, "", cache_id), reg_type_cache_(reg_type_cache) ,merged_types_(left_id, right_id) {
+  }
+  // The top of a tree of merged types.
+  std::pair<uint16_t, uint16_t> GetTopMergedTypes() const {
+    DCHECK(IsUnresolvedMergedReference());
+    return merged_types_;
+  }
+  // The complete set of merged types.
+  std::set<uint16_t> GetMergedTypes() const;
+  inline virtual bool IsUnresolvedMergedReference() const {
+    return true;
+  }
+  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  const RegTypeCache* const reg_type_cache_;
+  const std::pair<uint16_t, uint16_t> merged_types_;
+};
+
 std::ostream& operator<<(std::ostream& os, const RegType& rhs)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
 }  // namespace verifier
 }  // namespace art
 
diff --git a/src/verifier/reg_type_cache-inl.h b/src/verifier/reg_type_cache-inl.h
new file mode 100644
index 0000000..0c6e8d0
--- /dev/null
+++ b/src/verifier/reg_type_cache-inl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_VERIFIER_REG_TYPE_CACHE_INL_H_
+#define ART_SRC_VERIFIER_REG_TYPE_CACHE_INL_H_
+
+#include "reg_type.h"
+#include "reg_type_cache.h"
+#include "class_linker.h"
+
+namespace art {
+namespace verifier {
+template <class Type>
+Type* RegTypeCache::CreatePrimitiveTypeInstance(mirror::ClassLoader* loader, std::string descriptor) {
+  mirror::Class* klass = NULL;
+  // Try loading the class from linker.
+  if (!descriptor.empty()) {
+    klass = art::Runtime::Current()->GetClassLinker()->FindSystemClass(descriptor.c_str());
+  }
+  Type* entry = Type::CreateInstance(klass, descriptor, RegTypeCache::primitive_count_);
+  RegTypeCache::primitive_count_++;
+  return entry;
+}
+
+}  // namespace verifier
+}  // namespace art
+#endif  // ART_SRC_VERIFIER_REG_TYPE_CACHE_INL_H_
diff --git a/src/verifier/reg_type_cache.cc b/src/verifier/reg_type_cache.cc
index 96a6c24..c7a1b4f 100644
--- a/src/verifier/reg_type_cache.cc
+++ b/src/verifier/reg_type_cache.cc
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#include "reg_type_cache.h"
+#include "reg_type_cache-inl.h"
 
+#include "base/casts.h"
 #include "dex_file-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
@@ -23,356 +24,466 @@
 
 namespace art {
 namespace verifier {
-
-static RegType::Type RegTypeFromPrimitiveType(Primitive::Type prim_type) {
-  switch (prim_type) {
-    case Primitive::kPrimBoolean: return RegType::kRegTypeBoolean;
-    case Primitive::kPrimByte:    return RegType::kRegTypeByte;
-    case Primitive::kPrimShort:   return RegType::kRegTypeShort;
-    case Primitive::kPrimChar:    return RegType::kRegTypeChar;
-    case Primitive::kPrimInt:     return RegType::kRegTypeInteger;
-    case Primitive::kPrimLong:    return RegType::kRegTypeLongLo;
-    case Primitive::kPrimFloat:   return RegType::kRegTypeFloat;
-    case Primitive::kPrimDouble:  return RegType::kRegTypeDoubleLo;
-    case Primitive::kPrimVoid:
-    default:                      return RegType::kRegTypeConflict;
-  }
-}
-
-static RegType::Type RegTypeFromDescriptor(const std::string& descriptor) {
-  if (descriptor.length() == 1) {
-    switch (descriptor[0]) {
-      case 'Z': return RegType::kRegTypeBoolean;
-      case 'B': return RegType::kRegTypeByte;
-      case 'S': return RegType::kRegTypeShort;
-      case 'C': return RegType::kRegTypeChar;
-      case 'I': return RegType::kRegTypeInteger;
-      case 'J': return RegType::kRegTypeLongLo;
-      case 'F': return RegType::kRegTypeFloat;
-      case 'D': return RegType::kRegTypeDoubleLo;
-      case 'V':
-      default:  return RegType::kRegTypeConflict;
-    }
-  } else if (descriptor[0] == 'L' || descriptor[0] == '[') {
-    return RegType::kRegTypeReference;
-  } else {
-    return RegType::kRegTypeConflict;
-  }
-}
-
-const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const char* descriptor,
-                                            bool precise) {
-  return From(RegTypeFromDescriptor(descriptor), loader, descriptor, precise);
-}
+bool RegTypeCache::primitive_initialized_ = false;
+uint16_t RegTypeCache::primitive_start_ = 0;
+uint16_t RegTypeCache::primitive_count_ = 0;
 
 static bool MatchingPrecisionForClass(RegType* entry, bool precise)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return (entry->IsPreciseReference() == precise) || (entry->GetClass()->IsFinal() && !precise);
 }
 
-const RegType& RegTypeCache::From(RegType::Type type, mirror::ClassLoader* loader,
-                                  const char* descriptor, bool precise) {
-  if (type <= RegType::kRegTypeLastFixedLocation) {
-    // entries should be sized greater than primitive types
-    DCHECK_GT(entries_.size(), static_cast<size_t>(type));
-    RegType* entry = entries_[type];
-    if (entry == NULL) {
-      mirror::Class* c = NULL;
-      if (strlen(descriptor) != 0) {
-        c = Runtime::Current()->GetClassLinker()->FindSystemClass(descriptor);
-      }
-      entry = new RegType(type, c, 0, type);
-      entries_[type] = entry;
-    }
-    return *entry;
-  } else {
-    DCHECK(type == RegType::kRegTypeReference || type == RegType::kRegTypePreciseReference);
-    ClassHelper kh;
-    for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
-      RegType* cur_entry = entries_[i];
-      // check resolved and unresolved references, ignore uninitialized references
-      if (cur_entry->HasClass()) {
-        kh.ChangeClass(cur_entry->GetClass());
-        if (MatchingPrecisionForClass(cur_entry, precise) &&
-            (strcmp(descriptor, kh.GetDescriptor()) == 0)) {
-          return *cur_entry;
-        }
-      } else if (cur_entry->IsUnresolvedReference() &&
-                 cur_entry->GetDescriptor() == descriptor) {
-        return *cur_entry;
-      }
-    }
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    mirror::Class* c;
-    if (can_load_classes_) {
-      c = class_linker->FindClass(descriptor, loader);
-    } else {
-      c = class_linker->LookupClass(descriptor, loader);
-    }
-    if (c != NULL) {
-      // Able to resolve so create resolved register type that is precise if we
-      // know the type is final.
-      RegType* entry = new RegType(c->IsFinal() ? RegType::kRegTypePreciseReference
-                                                : RegType::kRegTypeReference,
-                                   c, 0, entries_.size());
-      entries_.push_back(entry);
-      return *entry;
-    } else {
-      // TODO: we assume unresolved, but we may be able to do better by validating whether the
-      // descriptor string is valid
-      // Unable to resolve so create unresolved register type
-      if (can_load_classes_) {
-        DCHECK(Thread::Current()->IsExceptionPending());
-        Thread::Current()->ClearException();
-      } else {
-        DCHECK(!Thread::Current()->IsExceptionPending());
-      }
-      if (IsValidDescriptor(descriptor)) {
-        RegType* entry =
-            new RegType(RegType::kRegTypeUnresolvedReference, descriptor, 0, entries_.size());
-        entries_.push_back(entry);
-        return *entry;
-      } else {
-        // The descriptor is broken return the unknown type as there's nothing sensible that
-        // could be done at runtime
+void RegTypeCache::FillPrimitiveTypes() {
+  entries_.push_back(UndefinedType::GetInstance());
+  entries_.push_back(ConflictType::GetInstance());
+  entries_.push_back(BooleanType::GetInstance());
+  entries_.push_back(ByteType::GetInstance());
+  entries_.push_back(ShortType::GetInstance());
+  entries_.push_back(CharType::GetInstance());
+  entries_.push_back(IntegerType::GetInstance());
+  entries_.push_back(LongLoType::GetInstance());
+  entries_.push_back(LongHiType::GetInstance());
+  entries_.push_back(FloatType::GetInstance());
+  entries_.push_back(DoubleLoType::GetInstance());
+  entries_.push_back(DoubleHiType::GetInstance());
+  DCHECK_EQ(entries_.size(), primitive_count_);
+}
+
+const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const char* descriptor, bool precise) {
+  CHECK(RegTypeCache::primitive_initialized_);
+  if (std::string(descriptor).length() == 1) {
+    switch (descriptor[0]) {
+      case 'Z':
+        return Boolean();
+      case 'B':
+        return Byte();
+      case 'S':
+        return Short();
+      case 'C':
+        return Char();
+      case 'I':
+        return Integer();
+      case 'J':
+        return LongLo();
+      case 'F':
+        return Float();
+      case 'D':
+        return DoubleLo();
+      case 'V':  // For void types, conflict types.
+      default:
         return Conflict();
-      }
     }
+  } else if (descriptor[0] == 'L' || descriptor[0] == '[') {
+    return From(loader, descriptor, precise);
+  } else {
+    return Conflict();
+  }
+};
+
+const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const {
+  DCHECK_LT(id, entries_.size());
+  RegType* result = entries_[id];
+  DCHECK(result != NULL);
+  return *result;
+}
+
+const RegType& RegTypeCache::RegTypeFromPrimitiveType(
+    Primitive::Type prim_type) const {
+  CHECK(RegTypeCache::primitive_initialized_);
+  switch (prim_type) {
+    case Primitive::kPrimBoolean:
+      return *BooleanType::GetInstance();
+    case Primitive::kPrimByte:
+      return *ByteType::GetInstance();
+    case Primitive::kPrimShort:
+      return *ShortType::GetInstance();
+    case Primitive::kPrimChar:
+      return *CharType::GetInstance();
+    case Primitive::kPrimInt:
+      return *IntegerType::GetInstance();
+    case Primitive::kPrimLong:
+      return *LongLoType::GetInstance();
+    case Primitive::kPrimFloat:
+      return *FloatType::GetInstance();
+    case Primitive::kPrimDouble:
+      return *DoubleLoType::GetInstance();
+    case Primitive::kPrimVoid:
+    default:
+      return *ConflictType::GetInstance();
   }
 }
 
+bool RegTypeCache::MatchDescriptor(size_t idx, std::string& descriptor, bool precise) {
+  ClassHelper kh;
+  RegType* cur_entry = entries_[idx];
+  // Check if we have matching descriptors and precision
+  // in cases where the descriptor available
+  if (cur_entry->descriptor_ != "" &&
+      MatchingPrecisionForClass(cur_entry, precise) &&
+      descriptor == cur_entry->descriptor_) {
+    return true;
+  }
+  // check resolved and unresolved references, ignore uninitialized references
+  if (cur_entry->HasClass()) {
+    kh.ChangeClass(cur_entry->GetClass());
+    // So we might have cases where we have the class but not the descriptor
+    // for that class we need the class helper to get the descriptor
+    // and match it with the one we are given.
+    if (MatchingPrecisionForClass(cur_entry, precise) &&
+        (strcmp(descriptor.c_str(), kh.GetDescriptor()) == 0)) {
+      return true;
+    }
+  } else if (cur_entry->IsUnresolvedReference() && cur_entry->GetDescriptor() == descriptor) {
+    return true;
+  }
+  return false;
+}
+
+mirror::Class* RegTypeCache::ResolveClass(std::string descriptor, mirror::ClassLoader* loader) {
+  // Class was not found, must create new type.
+  // Try resolving class
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  mirror::Class* klass = NULL;
+  if (can_load_classes_) {
+    klass = class_linker->FindClass(descriptor.c_str(), loader);
+  } else {
+    klass = class_linker->LookupClass(descriptor.c_str(), loader);
+  }
+  return klass;
+}
+void RegTypeCache::ClearException() {
+  if (can_load_classes_) {
+    DCHECK(Thread::Current()->IsExceptionPending());
+    Thread::Current()->ClearException();
+  } else {
+    DCHECK(!Thread::Current()->IsExceptionPending());
+  }
+}
+const RegType& RegTypeCache::From(mirror::ClassLoader* loader, std::string descriptor, bool precise) {
+  // Try resolving class.
+  mirror::Class* klass = ResolveClass(descriptor, loader);
+  if (klass != NULL) {
+    // Class resolved, first look for the class in the list of entries
+    for (size_t i = primitive_count_; i < entries_.size(); i++) {
+      if (entries_[i]->HasClass()) {
+        if (MatchDescriptor(i, descriptor, precise)) {
+          return *(entries_[i]);
+        }
+      }
+    }
+    // Class was not found, must create new type.
+
+    // Create a type if:
+    // 1-The class is instantiable ( not Abstract or Interface ), we should
+    //   abort failing the verification if we get that.
+    // 2- And, the class should be instantiable (Not interface, Abstract or a
+    //    primitive type) OR it is imprecise.
+
+    // Create a precise type if :
+    // 1-The class is final.
+    // 2-OR the precise was passed as true .
+    CHECK(!precise || klass->IsInstantiable());
+    RegType* entry;
+    // Create an imprecise type if we can'tt tell for a fact that it is precise.
+    if (klass->IsFinal() || precise) {
+      entry = new PreciseReferenceType(klass, descriptor, entries_.size());
+    } else {
+      entry = new ReferenceType(klass, descriptor, entries_.size());
+    }
+    entries_.push_back(entry);
+    return *entry;
+  } else {  // Class not resolved.
+    // We tried loading the class and failed, this might get an exception raised
+    // so we want to clear it before we go on.
+    ClearException();
+    // Unable to resolve class. Look through unresolved types in the catch and see
+    // if we have it created before.
+    for (size_t i = primitive_count_; i < entries_.size(); i++) {
+      if (entries_[i]->IsUnresolvedReference() &&
+          entries_[i]->descriptor_ == descriptor) {
+        return *(entries_[i]);
+      }
+    }
+    if (IsValidDescriptor(descriptor.c_str())) {
+      RegType* entry = new UnresolvedReferenceType(descriptor, entries_.size());
+      entries_.push_back(entry);
+      return *entry;
+    } else {
+      // The descriptor is broken return the unknown type as there's nothing sensible that
+      // could be done at runtime
+      return Conflict();
+    }
+  }
+}
 const RegType& RegTypeCache::FromClass(mirror::Class* klass, bool precise) {
   if (klass->IsPrimitive()) {
-    RegType::Type type = RegTypeFromPrimitiveType(klass->GetPrimitiveType());
-    // entries should be sized greater than primitive types
-    DCHECK_GT(entries_.size(), static_cast<size_t>(type));
-    RegType* entry = entries_[type];
-    if (entry == NULL) {
-      entry = new RegType(type, klass, 0, type);
-      entries_[type] = entry;
-    }
-    return *entry;
+    return RegTypeFromPrimitiveType(klass->GetPrimitiveType());
+
   } else {
-    for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+    // Look for the reference in the list of entries to have.
+    for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
       if ((cur_entry->HasClass()) &&
           MatchingPrecisionForClass(cur_entry, precise) && cur_entry->GetClass() == klass) {
         return *cur_entry;
       }
     }
-    RegType* entry = new RegType(precise ? RegType::kRegTypePreciseReference
-                                         : RegType::kRegTypeReference,
-                                 klass, 0, entries_.size());
+    // No reference to the class was found, create new reference.
+    RegType* entry;
+    std::string empty = "";
+    if (precise) {
+      entry = new PreciseReferenceType(klass, empty, entries_.size());
+    } else {
+      entry = new ReferenceType(klass, empty, entries_.size());
+    }
     entries_.push_back(entry);
     return *entry;
   }
 }
 
+RegTypeCache::~RegTypeCache() {
+  CHECK_LE(primitive_count_, entries_.size());
+  // Delete only the non primitive types.
+  if (primitive_count_  == static_cast<uint16_t>(entries_.size())) {
+    // All entries are primitive, nothing to delete.
+    return;
+  }
+  std::vector<RegType*>::iterator non_primitive_begin = entries_.begin();
+  std::advance(non_primitive_begin, primitive_count_);
+  STLDeleteContainerPointers(non_primitive_begin, entries_.end());
+}
+
+void RegTypeCache::ShutDown() {
+  if (RegTypeCache::primitive_initialized_) {
+    UndefinedType::Destroy();
+    ConflictType::Destroy();
+    BooleanType::Destroy();
+    ByteType::Destroy();
+    ShortType::Destroy();
+    CharType::Destroy();
+    IntegerType::Destroy();
+    LongLoType::Destroy();
+    LongHiType::Destroy();
+    FloatType::GetInstance();
+    DoubleLoType::Destroy();
+    DoubleHiType::Destroy();
+   RegTypeCache::primitive_initialized_ = false;
+   RegTypeCache::primitive_count_ = 0;
+  }
+}
+
+void RegTypeCache::CreatePrimitiveTypes() {
+  CreatePrimitiveTypeInstance<UndefinedType>(NULL, "");
+  CreatePrimitiveTypeInstance<ConflictType>(NULL, "");
+  CreatePrimitiveTypeInstance<BooleanType>(NULL, "Z");
+  CreatePrimitiveTypeInstance<ByteType>(NULL, "B");
+  CreatePrimitiveTypeInstance<ShortType>(NULL, "S");
+  CreatePrimitiveTypeInstance<CharType>(NULL, "C");
+  CreatePrimitiveTypeInstance<IntegerType>(NULL, "I");
+  CreatePrimitiveTypeInstance<LongLoType>(NULL, "J");
+  CreatePrimitiveTypeInstance<LongHiType>(NULL, "J");
+  CreatePrimitiveTypeInstance<FloatType>(NULL, "F");
+  CreatePrimitiveTypeInstance<DoubleLoType>(NULL, "D");
+  CreatePrimitiveTypeInstance<DoubleHiType>(NULL, "D");
+}
+
 const RegType& RegTypeCache::FromUnresolvedMerge(const RegType& left, const RegType& right) {
   std::set<uint16_t> types;
   if (left.IsUnresolvedMergedReference()) {
-    types = left.GetMergedTypes(this);
+    RegType& non_const(const_cast<RegType&>(left));
+    types = (down_cast<UnresolvedMergedType*>(&non_const))->GetMergedTypes();
   } else {
     types.insert(left.GetId());
   }
   if (right.IsUnresolvedMergedReference()) {
-    std::set<uint16_t> right_types = right.GetMergedTypes(this);
+    RegType& non_const(const_cast<RegType&>(right));
+    std::set<uint16_t> right_types = (down_cast<UnresolvedMergedType*>(&non_const))->GetMergedTypes();
     types.insert(right_types.begin(), right_types.end());
   } else {
     types.insert(right.GetId());
   }
   // Check if entry already exists.
-  for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+  for (size_t i = primitive_count_; i < entries_.size(); i++) {
     RegType* cur_entry = entries_[i];
     if (cur_entry->IsUnresolvedMergedReference()) {
-      std::set<uint16_t> cur_entry_types = cur_entry->GetMergedTypes(this);
+      std::set<uint16_t> cur_entry_types =
+          (down_cast<UnresolvedMergedType*>(cur_entry))->GetMergedTypes();
       if (cur_entry_types == types) {
         return *cur_entry;
       }
     }
   }
   // Create entry.
-  uint32_t merged_ids = static_cast<uint32_t>(left.GetId()) << 16 |
-                        static_cast<uint32_t>(right.GetId());
-  RegType* entry = new RegType(RegType::kRegTypeUnresolvedMergedReference, NULL, merged_ids,
-                               entries_.size());
+  RegType* entry = new UnresolvedMergedType(left.GetId(), right.GetId(), this, entries_.size());
   entries_.push_back(entry);
-#ifndef DEBUG
-  std::set<uint16_t> check_types = entry->GetMergedTypes(this);
+#ifndef NDEBUG
+  UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry);
+  std::set<uint16_t> check_types = tmp_entry->GetMergedTypes();
   CHECK(check_types == types);
 #endif
   return *entry;
 }
-
 const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) {
   // Check if entry already exists.
-   for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
-     RegType* cur_entry = entries_[i];
-     if (cur_entry->IsUnresolvedSuperClass()) {
-       uint16_t unresolved_super_child_id = cur_entry->GetUnresolvedSuperClassChildId();
-       if (unresolved_super_child_id == child.GetId()) {
-         return *cur_entry;
-       }
-     }
-   }
-   // Create entry.
-   RegType* entry = new RegType(RegType::kRegTypeUnresolvedSuperClass, NULL, child.GetId(),
-                                entries_.size());
-   entries_.push_back(entry);
-   return *entry;
-}
-
-const RegType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) {
-  RegType* entry;
-  if (type.IsUnresolvedTypes()) {
-    std::string descriptor(type.GetDescriptor());
-    for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
-      RegType* cur_entry = entries_[i];
-      if (cur_entry->IsUnresolvedAndUninitializedReference() &&
-          cur_entry->GetAllocationPc() == allocation_pc &&
-          cur_entry->GetDescriptor() == descriptor) {
+  for (size_t i = primitive_count_; i < entries_.size(); i++) {
+    RegType* cur_entry = entries_[i];
+    if (cur_entry->IsUnresolvedSuperClass()) {
+      UnresolvedSuperClass* tmp_entry =
+          down_cast<UnresolvedSuperClass*>(cur_entry);
+      uint16_t unresolved_super_child_id =
+          tmp_entry->GetUnresolvedSuperClassChildId();
+      if (unresolved_super_child_id == child.GetId()) {
         return *cur_entry;
       }
     }
-    entry = new RegType(RegType::kRegTypeUnresolvedAndUninitializedReference,
-                        descriptor, allocation_pc, entries_.size());
+  }
+  RegType* entry = new UnresolvedSuperClass(child.GetId(), this, entries_.size());
+  entries_.push_back(entry);
+  return *entry;
+}
+const RegType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) {
+  RegType* entry = NULL;
+  RegType* cur_entry = NULL;
+  if (type.IsUnresolvedTypes()) {
+    std::string descriptor(type.GetDescriptor());
+    for (size_t i = primitive_count_; i < entries_.size(); i++) {
+      cur_entry = entries_[i];
+      if (cur_entry->IsUnresolvedAndUninitializedReference() &&
+          down_cast<UnresolvedUninitializedRefType*>(cur_entry)->GetAllocationPc() == allocation_pc &&
+          (cur_entry->GetDescriptor() == descriptor)) {
+        return *cur_entry;
+      }
+    }
+    entry = new UnresolvedUninitializedRefType(descriptor, allocation_pc, entries_.size());
   } else {
     mirror::Class* klass = type.GetClass();
-    for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
-      RegType* cur_entry = entries_[i];
+    for (size_t i = primitive_count_; i < entries_.size(); i++) {
+      cur_entry = entries_[i];
       if (cur_entry->IsUninitializedReference() &&
-          cur_entry->GetAllocationPc() == allocation_pc &&
+          down_cast<UninitialisedReferenceType*>(cur_entry)
+              ->GetAllocationPc() == allocation_pc &&
           cur_entry->GetClass() == klass) {
         return *cur_entry;
       }
     }
-    entry = new RegType(RegType::kRegTypeUninitializedReference,
-                        klass, allocation_pc, entries_.size());
+    std::string descriptor = "";
+    entry = new UninitialisedReferenceType(klass, descriptor, allocation_pc, entries_.size());
   }
   entries_.push_back(entry);
   return *entry;
 }
-
 const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
   RegType* entry;
   if (uninit_type.IsUnresolvedTypes()) {
     std::string descriptor(uninit_type.GetDescriptor());
-    for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+    for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
-      if (cur_entry->IsUnresolvedReference() && cur_entry->GetDescriptor() == descriptor) {
+      if (cur_entry->IsUnresolvedReference() &&
+          cur_entry->GetDescriptor() == descriptor) {
         return *cur_entry;
       }
     }
-    entry = new RegType(RegType::kRegTypeUnresolvedReference, descriptor, 0, entries_.size());
+    entry = new UnresolvedReferenceType(descriptor, entries_.size());
   } else {
     mirror::Class* klass = uninit_type.GetClass();
-    for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+    for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
       if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
         return *cur_entry;
       }
     }
-    entry = new RegType(RegType::kRegTypePreciseReference, klass, 0, entries_.size());
+    std::string descriptor = "";
+    entry = new PreciseReferenceType(klass, descriptor, entries_.size());
   }
   entries_.push_back(entry);
   return *entry;
 }
-
 const RegType& RegTypeCache::ByteConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return FromCat1Const(std::numeric_limits<jbyte>::min(), false);
 }
-
 const RegType& RegTypeCache::ShortConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return FromCat1Const(std::numeric_limits<jshort>::min(), false);
 }
-
 const RegType& RegTypeCache::IntConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return FromCat1Const(std::numeric_limits<jint>::max(), false);
 }
-
 const RegType& RegTypeCache::UninitializedThisArgument(const RegType& type) {
-  // TODO: implement descriptor version.
   RegType* entry;
   if (type.IsUnresolvedTypes()) {
     std::string descriptor(type.GetDescriptor());
-    for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+    for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
       if (cur_entry->IsUnresolvedAndUninitializedThisReference() &&
           cur_entry->GetDescriptor() == descriptor) {
         return *cur_entry;
       }
     }
-    entry = new RegType(RegType::kRegTypeUnresolvedAndUninitializedThisReference, descriptor, 0,
-                        entries_.size());
+    entry = new UnresolvedUninitialisedThisRefType(descriptor, entries_.size());
   } else {
     mirror::Class* klass = type.GetClass();
-    for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+    for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
-      if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) {
+      if (cur_entry->IsUninitializedThisReference() &&
+          cur_entry->GetClass() == klass) {
         return *cur_entry;
       }
     }
-    entry = new RegType(RegType::kRegTypeUninitializedThisReference, klass, 0, entries_.size());
+    std::string descriptor = "";
+    entry = new UninitialisedThisReferenceType(klass, descriptor, entries_.size());
   }
   entries_.push_back(entry);
   return *entry;
 }
-
-const RegType& RegTypeCache::FromType(RegType::Type type) {
-  CHECK(type < RegType::kRegTypeReference);
-  switch (type) {
-    case RegType::kRegTypeBoolean:  return From(type, NULL, "Z", true);
-    case RegType::kRegTypeByte:     return From(type, NULL, "B", true);
-    case RegType::kRegTypeShort:    return From(type, NULL, "S", true);
-    case RegType::kRegTypeChar:     return From(type, NULL, "C", true);
-    case RegType::kRegTypeInteger:  return From(type, NULL, "I", true);
-    case RegType::kRegTypeFloat:    return From(type, NULL, "F", true);
-    case RegType::kRegTypeLongLo:
-    case RegType::kRegTypeLongHi:   return From(type, NULL, "J", true);
-    case RegType::kRegTypeDoubleLo:
-    case RegType::kRegTypeDoubleHi: return From(type, NULL, "D", true);
-    default:                        return From(type, NULL, "", true);
-  }
-}
-
 const RegType& RegTypeCache::FromCat1Const(int32_t value, bool precise) {
-  RegType::Type wanted_type =
-      precise ? RegType::kRegTypePreciseConst : RegType::kRegTypeImpreciseConst;
-  for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+  for (size_t i = primitive_count_; i < entries_.size(); i++) {
     RegType* cur_entry = entries_[i];
-    if (cur_entry->GetType() == wanted_type && cur_entry->ConstantValue() == value) {
+    if (cur_entry->IsConstant() && cur_entry->IsPreciseConstant() == precise &&
+        (down_cast<ConstantType*>(cur_entry))->ConstantValue() == value) {
       return *cur_entry;
     }
   }
-  RegType* entry = new RegType(wanted_type, NULL, value, entries_.size());
+  RegType* entry;
+  if (precise) {
+    entry = new PreciseConstType(value, entries_.size());
+  } else {
+    entry = new ImpreciseConstType(value, entries_.size());
+  }
   entries_.push_back(entry);
   return *entry;
 }
 
 const RegType& RegTypeCache::FromCat2ConstLo(int32_t value, bool precise) {
-  RegType::Type wanted_type =
-      precise ? RegType::kRegTypePreciseConstLo : RegType::kRegTypeImpreciseConstLo;
-  for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+  for (size_t i = primitive_count_; i < entries_.size(); i++) {
     RegType* cur_entry = entries_[i];
-    if (cur_entry->GetType() == wanted_type && cur_entry->ConstantValueLo() == value) {
+    if (cur_entry->IsConstantLo() && (cur_entry->IsPrecise() == precise) &&
+        (down_cast<ConstantType*>(cur_entry))->ConstantValueLo() == value) {
       return *cur_entry;
     }
   }
-  RegType* entry = new RegType(wanted_type, NULL, value, entries_.size());
+  RegType* entry;
+  if (precise) {
+    entry = new PreciseConstLoType(value, entries_.size());
+  } else {
+    entry = new ImpreciseConstLoType(value, entries_.size());
+  }
   entries_.push_back(entry);
   return *entry;
 }
 
 const RegType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) {
-  RegType::Type wanted_type =
-      precise ? RegType::kRegTypePreciseConstHi : RegType::kRegTypeImpreciseConstHi;
-  for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+  for (size_t i = primitive_count_; i < entries_.size(); i++) {
     RegType* cur_entry = entries_[i];
-    if (cur_entry->GetType() == wanted_type && cur_entry->ConstantValueHi() == value) {
+    if (cur_entry->IsConstantHi() && (cur_entry->IsPrecise() == precise) &&
+        (down_cast<ConstantType*>(cur_entry))->ConstantValueHi() == value) {
       return *cur_entry;
     }
   }
-  RegType* entry = new RegType(wanted_type, NULL, value, entries_.size());
+  RegType* entry;
+  if (precise) {
+    entry = new PreciseConstHiType(value, entries_.size());
+  } else {
+    entry = new ImpreciseConstHiType(value, entries_.size());
+  }
   entries_.push_back(entry);
   return *entry;
 }
diff --git a/src/verifier/reg_type_cache.h b/src/verifier/reg_type_cache.h
index adab18c..cacd517 100644
--- a/src/verifier/reg_type_cache.h
+++ b/src/verifier/reg_type_cache.h
@@ -17,10 +17,13 @@
 #ifndef ART_SRC_VERIFIER_REG_TYPE_CACHE_H_
 #define ART_SRC_VERIFIER_REG_TYPE_CACHE_H_
 
+#include "base/casts.h"
 #include "base/macros.h"
 #include "base/stl_util.h"
 #include "reg_type.h"
+#include "runtime.h"
 
+#include <stdint.h>
 #include <vector>
 
 namespace art {
@@ -30,26 +33,30 @@
 }  // namespace mirror
 namespace verifier {
 
+class RegType;
+
 class RegTypeCache {
  public:
-  explicit RegTypeCache(bool can_load_classes)
-      : entries_(RegType::kRegTypeLastFixedLocation + 1), can_load_classes_(can_load_classes) {
-    Undefined();  // ensure Undefined is initialized
+  explicit RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) {
+    FillPrimitiveTypes();
   }
-  ~RegTypeCache() {
-    STLDeleteElements(&entries_);
+  ~RegTypeCache();
+  static void Init() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if(!RegTypeCache::primitive_initialized_) {
+      CHECK_EQ(RegTypeCache::primitive_count_, 0);
+      CreatePrimitiveTypes();
+      CHECK_EQ(RegTypeCache::primitive_count_, 12);
+      RegTypeCache::primitive_initialized_ = true;
+    }
   }
-
-  const RegType& GetFromId(uint16_t id) const {
-    DCHECK_LT(id, entries_.size());
-    RegType* result = entries_[id];
-    DCHECK(result != NULL);
-    return *result;
-  }
-
-  const RegType& From(RegType::Type type, mirror::ClassLoader* loader, const char* descriptor,
-                      bool precise)
+  static void ShutDown();
+  const art::verifier::RegType& GetFromId(uint16_t id) const;
+  const RegType& From(mirror::ClassLoader* loader, std::string descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template <class Type>
+  static Type* CreatePrimitiveTypeInstance(mirror::ClassLoader*, std::string)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FillPrimitiveTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& FromClass(mirror::Class* klass, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& FromCat1Const(int32_t value, bool precise)
@@ -60,74 +67,66 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& FromDescriptor(mirror::ClassLoader* loader, const char* descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const RegType& FromType(RegType::Type)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& FromUnresolvedMerge(const RegType& left, const RegType& right)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& FromUnresolvedSuperClass(const RegType& child)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  const RegType& Boolean() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeBoolean);
-  }
-  const RegType& Byte() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeByte);
-  }
-  const RegType& Char() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeChar);
-  }
-  const RegType& Short() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeShort);
-  }
-  const RegType& Integer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeInteger);
-  }
-  const RegType& Float() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeFloat);
-  }
-  const RegType& LongLo() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeLongLo);
-  }
-  const RegType& LongHi() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeLongHi);
-  }
-  const RegType& DoubleLo() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeDoubleLo);
-  }
-  const RegType& DoubleHi() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeDoubleHi);
-  }
-
-  const RegType& JavaLangClass(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return From(precise ? RegType::kRegTypeReference
-                        : RegType::kRegTypePreciseReference,
-                NULL, "Ljava/lang/Class;", precise);
-  }
-  const RegType& JavaLangObject(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return From(precise ? RegType::kRegTypeReference
-                        : RegType::kRegTypePreciseReference,
-                NULL, "Ljava/lang/Object;", precise);
-  }
   const RegType& JavaLangString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // String is final and therefore always precise.
-    return From(RegType::kRegTypePreciseReference, NULL, "Ljava/lang/String;", true);
+    return From(NULL, "Ljava/lang/String;", true);
   }
-  const RegType& JavaLangThrowable(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return From(precise ? RegType::kRegTypeReference
-                        : RegType::kRegTypePreciseReference,
-                NULL, "Ljava/lang/Throwable;", precise);
-  }
-
-  const RegType& Undefined() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeUndefined);
-  }
-  const RegType& Conflict() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return FromType(RegType::kRegTypeConflict);
+  const RegType& JavaLangThrowable(bool precise)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return From(NULL, "Ljava/lang/Throwable;", precise);
   }
   const RegType& Zero() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return FromCat1Const(0, true);
   }
-
+  size_t GetCacheSize() {
+    return entries_.size();
+  }
+  const RegType& Boolean() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return *BooleanType::GetInstance();
+  }
+  const RegType& Byte() {
+    return *ByteType::GetInstance();
+  }
+  const RegType& Char()  {
+    return *CharType::GetInstance();
+  }
+  const RegType& Short()  {
+    return *ShortType::GetInstance();
+  }
+  const RegType& Integer() {
+    return *IntegerType::GetInstance();
+  }
+  const RegType& Float() {
+    return *FloatType::GetInstance();
+  }
+  const RegType& LongLo() {
+    return *LongLoType::GetInstance();
+  }
+  const RegType& LongHi() {
+    return *LongHiType::GetInstance();
+  }
+  const RegType& DoubleLo() {
+    return *DoubleLoType::GetInstance();
+  }
+  const RegType& DoubleHi() {
+    return *DoubleHiType::GetInstance();
+  }
+  const RegType& Undefined() {
+    return *UndefinedType::GetInstance();
+  }
+  const RegType& Conflict() {
+    return *ConflictType::GetInstance();
+  }
+  const RegType& JavaLangClass(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return From(NULL, "Ljava/lang/Class;", precise);
+  }
+  const RegType& JavaLangObject(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return From(NULL, "Ljava/lang/Object;", precise);
+  }
   const RegType& Uninitialized(const RegType& type, uint32_t allocation_pc)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Create an uninitialized 'this' argument for the given type.
@@ -135,26 +134,28 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& FromUninitialized(const RegType& uninit_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // Representatives of various constant types. When merging constants we can't infer a type,
-  // (an int may later be used as a float) so we select these representative values meaning future
-  // merges won't know the exact constant value but have some notion of its size.
   const RegType& ByteConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& ShortConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& IntConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   const RegType& GetComponentType(const RegType& array, mirror::ClassLoader* loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const RegType& RegTypeFromPrimitiveType(Primitive::Type) const;
 
  private:
-  // The allocated entries
   std::vector<RegType*> entries_;
+  static bool primitive_initialized_;
+  static uint16_t primitive_start_;
+  static uint16_t primitive_count_;
+  static void CreatePrimitiveTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Whether or not we're allowed to load classes.
   const bool can_load_classes_;
-
   DISALLOW_COPY_AND_ASSIGN(RegTypeCache);
+  mirror::Class* ResolveClass(std::string descriptor, mirror::ClassLoader* loader)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void ClearException();
+  bool MatchDescriptor(size_t idx, std::string& descriptor, bool precise)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
 }  // namespace verifier
diff --git a/src/verifier/reg_type_test.cc b/src/verifier/reg_type_test.cc
index c66477c..333f9b0 100644
--- a/src/verifier/reg_type_test.cc
+++ b/src/verifier/reg_type_test.cc
@@ -15,17 +15,18 @@
  */
 
 #include "reg_type.h"
+#include "reg_type_cache-inl.h"
 
-#include "reg_type_cache.h"
-
+#include "base/casts.h"
 #include "common_test.h"
+#include <set>
 
 namespace art {
 namespace verifier {
 
 class RegTypeTest : public CommonTest {};
-
 TEST_F(RegTypeTest, Primitives) {
+
   ScopedObjectAccess soa(Thread::Current());
   RegTypeCache cache(true);
 
@@ -278,12 +279,185 @@
   EXPECT_FALSE(double_reg_type.IsArrayIndexTypes());
 }
 
-// TODO: test reference RegType
-// TODO: test constant RegType
-// TODO: test VerifyAgainst
-// TODO: test Merge
-// TODO: test Equals
-// TODO: test ClassJoin
+
+class RegTypeReferenceTest : public CommonTest {};
+
+TEST_F(RegTypeReferenceTest, JavalangObjectImprecise) {
+  ScopedObjectAccess soa(Thread::Current());
+  // Tests matching precisions. A reference type that was created precise doesn't
+  // match the one that is imprecise.
+  RegTypeCache cache(true);
+  const RegType& imprecise_obj = cache.JavaLangObject(false);
+  const RegType& precise_obj = cache.JavaLangObject(true);
+  const RegType& precise_obj_2 = cache.FromDescriptor(NULL, "Ljava/lang/Object;", true);
+
+  EXPECT_TRUE(precise_obj.Equals(precise_obj_2));
+  EXPECT_FALSE(imprecise_obj.Equals(precise_obj));
+  EXPECT_FALSE(imprecise_obj.Equals(precise_obj));
+  EXPECT_FALSE(imprecise_obj.Equals(precise_obj_2));
+}
+
+TEST_F(RegTypeReferenceTest, UnresolvedType) {
+  ScopedObjectAccess soa(Thread::Current());
+  // Tests creating unresolved types. Miss for the first time asking the cache and
+  // a hit second time.
+  RegTypeCache cache(true);
+  const RegType& ref_type_0 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+  EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
+
+  const RegType& ref_type_1 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+  EXPECT_TRUE(ref_type_0.Equals(ref_type_1));
+
+  const RegType& unresolved_super_class =  cache.FromUnresolvedSuperClass(ref_type_0);
+  EXPECT_TRUE(unresolved_super_class.IsUnresolvedSuperClass());
+}
+
+TEST_F(RegTypeReferenceTest, UnresolvedUnintializedType) {
+  ScopedObjectAccess soa(Thread::Current());
+  // Tests creating types uninitialized types from unresolved types.
+  RegTypeCache cache(true);
+  const RegType& ref_type_0 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+  EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
+  const RegType& ref_type = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+  EXPECT_TRUE(ref_type_0.Equals(ref_type));
+
+  // Create an uninitialized type of this unresolved type
+  const RegType& unresolved_unintialised = cache.Uninitialized(ref_type, 1101ull);
+  EXPECT_TRUE(unresolved_unintialised.IsUnresolvedAndUninitializedReference());
+  EXPECT_TRUE(unresolved_unintialised.IsUninitializedTypes());
+
+  // Create an uninitialized type of this unresolved type with different  PC
+  const RegType& ref_type_unresolved_unintialised_1 =  cache.Uninitialized(ref_type, 1102ull);
+  EXPECT_TRUE(unresolved_unintialised.IsUnresolvedAndUninitializedReference());
+  EXPECT_FALSE(unresolved_unintialised.Equals(ref_type_unresolved_unintialised_1));
+
+  // Create an uninitialized type of this unresolved type with the same PC
+  const RegType& unresolved_unintialised_2 =
+      cache.Uninitialized(ref_type, 1101ull);
+  EXPECT_TRUE(unresolved_unintialised.Equals(unresolved_unintialised_2));
+}
+
+TEST_F(RegTypeReferenceTest, Dump) {
+  ScopedObjectAccess soa(Thread::Current());
+  // Tests creating types uninitialized types from unresolved types.
+  RegTypeCache cache(true);
+
+  const RegType& unresolved_ref = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+  const RegType& unresolved_ref_another = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExistEither;", true);
+  const RegType& resolved_ref = cache.JavaLangString();
+
+  const RegType& resolved_unintialiesd = cache.Uninitialized(resolved_ref, 10);
+  const RegType& unresolved_unintialized = cache.Uninitialized(unresolved_ref, 12);
+  const RegType& unresolved_merged = cache.FromUnresolvedMerge(unresolved_ref, unresolved_ref_another);
+
+  std::string expected = "Unresolved Reference: java.lang.DoesNotExist";
+  EXPECT_EQ(expected, unresolved_ref.Dump());
+  expected = "Precise Reference: java.lang.String";
+  EXPECT_EQ( expected, resolved_ref.Dump());
+  expected ="Uninitialized Reference: java.lang.String Allocation PC: 10";
+  EXPECT_EQ(expected, resolved_unintialiesd.Dump());
+  expected = "Unresolved And Uninitialized Reference: java.lang.DoesNotExist Allocation PC: 12";
+  EXPECT_EQ(expected, unresolved_unintialized.Dump());
+  expected = "UnresolvedMergedReferences(Unresolved Reference: java.lang.DoesNotExist, Unresolved Reference: java.lang.DoesNotExistEither)";
+  EXPECT_EQ(expected, unresolved_merged.Dump());
+}
+
+
+TEST_F(RegTypeReferenceTest, JavalangString) {
+  // Add a class to the cache then look for the same class and make sure it is  a
+  // Hit the second time. Then check for the same effect when using
+  // The JavaLangObject method instead of FromDescriptor. String class is final.
+  ScopedObjectAccess soa(Thread::Current());
+  RegTypeCache cache(true);
+  const RegType& ref_type = cache.JavaLangString();
+  const RegType& ref_type_2 = cache.JavaLangString();
+  const RegType& ref_type_3 = cache.FromDescriptor(NULL, "Ljava/lang/String;", true);
+
+  EXPECT_TRUE(ref_type.Equals(ref_type_2));
+  EXPECT_TRUE(ref_type_2.Equals(ref_type_3));
+  EXPECT_TRUE(ref_type.IsPreciseReference());
+
+  // Create an uninitialized type out of this:
+  const RegType& ref_type_unintialized = cache.Uninitialized(ref_type, 0110ull);
+  EXPECT_TRUE(ref_type_unintialized.IsUninitializedReference());
+  EXPECT_FALSE(ref_type_unintialized.IsUnresolvedAndUninitializedReference());
+
+}
+TEST_F(RegTypeReferenceTest, JavalangObject) {
+  // Add a class to the cache then look for the same class and make sure it is  a
+  // Hit the second time. Then I am checking for the same effect when using
+  // The JavaLangObject method instead of FromDescriptor. Object Class in not final.
+  ScopedObjectAccess soa(Thread::Current());
+  RegTypeCache cache(true);
+  const RegType& ref_type = cache.JavaLangObject(true);
+  const RegType& ref_type_2 = cache.JavaLangObject(true);
+  const RegType& ref_type_3 = cache.FromDescriptor(NULL, "Ljava/lang/Object;", true);
+
+  EXPECT_TRUE(ref_type.Equals(ref_type_2));
+  EXPECT_TRUE(ref_type_3.Equals(ref_type_2));
+  EXPECT_EQ(ref_type.GetId(), ref_type_3.GetId());
+}
+TEST_F(RegTypeReferenceTest, Merging) {
+  // Tests merging logic
+  //String and object , LUB is object.
+  ScopedObjectAccess soa(Thread::Current());
+  RegTypeCache cache_new(true);
+  const RegType& string = cache_new.JavaLangString();
+  const RegType& Object = cache_new.JavaLangObject(true);
+  EXPECT_TRUE(string.Merge(Object, &cache_new).IsJavaLangObject());
+  // Merge two unresolved types.
+  const RegType& ref_type_0 = cache_new.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+  EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
+  const RegType& ref_type_1 = cache_new.FromDescriptor(NULL, "Ljava/lang/DoesNotExistToo;", true);
+  EXPECT_FALSE(ref_type_0.Equals(ref_type_1));
+
+  const RegType& merged = ref_type_1.Merge(ref_type_0, &cache_new);
+  EXPECT_TRUE(merged.IsUnresolvedMergedReference());
+  RegType& merged_nonconst = const_cast<RegType&>(merged);
+
+  std::set<uint16_t> merged_ids = (down_cast<UnresolvedMergedType*>(&merged_nonconst))->GetMergedTypes();
+  EXPECT_EQ(ref_type_0.GetId(), *(merged_ids.begin()));
+  EXPECT_EQ(ref_type_1.GetId(), *((++merged_ids.begin())));
+}
+
+TEST_F(RegTypeTest, ConstLoHi) {
+  // Tests creating primitive types types.
+  ScopedObjectAccess soa(Thread::Current());
+  RegTypeCache cache(true);
+  const RegType& ref_type_const_0 = cache.FromCat1Const(10, true);
+  const RegType& ref_type_const_1 = cache.FromCat1Const(10, true);
+  const RegType& ref_type_const_2 = cache.FromCat1Const(30, true);
+  const RegType& ref_type_const_3 = cache.FromCat1Const(30, false);
+
+  EXPECT_TRUE(ref_type_const_0.Equals(ref_type_const_1));
+  EXPECT_FALSE(ref_type_const_0.Equals(ref_type_const_2));
+  EXPECT_FALSE(ref_type_const_0.Equals(ref_type_const_3));
+
+  const RegType& ref_type_const_wide_0 = cache.FromCat2ConstHi(50, true);
+  const RegType& ref_type_const_wide_1 = cache.FromCat2ConstHi(50, true);
+  EXPECT_TRUE(ref_type_const_wide_0.Equals(ref_type_const_wide_1));
+
+  const RegType& ref_type_const_wide_2 = cache.FromCat2ConstLo(50, true);
+  const RegType& ref_type_const_wide_3 = cache.FromCat2ConstLo(50, true);
+  const RegType& ref_type_const_wide_4 = cache.FromCat2ConstLo(55, true);
+
+  EXPECT_TRUE(ref_type_const_wide_2.Equals(ref_type_const_wide_3));
+  EXPECT_FALSE(ref_type_const_wide_2.Equals(ref_type_const_wide_4));
+}
+
+
+TEST_F(RegTypeTest, ConstPrecision) {
+
+  // Tests creating primitive types types.
+  ScopedObjectAccess soa(Thread::Current());
+  RegTypeCache cache_new(true);
+  const RegType& imprecise_const = cache_new.FromCat1Const(10, false);
+  const RegType& precise_const = cache_new.FromCat1Const(10, true);
+
+  EXPECT_TRUE(imprecise_const.IsImpreciseConstant());
+  EXPECT_TRUE(precise_const.IsPreciseConstant());
+  EXPECT_FALSE(imprecise_const.Equals(precise_const));
+}
 
 }  // namespace verifier
 }  // namespace art
diff --git a/src/verifier/register_line.cc b/src/verifier/register_line.cc
index 74f83da..544a9ee 100644
--- a/src/verifier/register_line.cc
+++ b/src/verifier/register_line.cc
@@ -74,24 +74,19 @@
 }
 
 void RegisterLine::SetResultTypeToUnknown() {
-  result_[0] = RegType::kRegTypeUndefined;
-  result_[1] = RegType::kRegTypeUndefined;
+  result_[0] = verifier_->GetRegTypeCache()->Undefined().GetId();
+  result_[1] = result_[0];
 }
 
 void RegisterLine::SetResultRegisterType(const RegType& new_type) {
   DCHECK(!new_type.IsLowHalf());
   DCHECK(!new_type.IsHighHalf());
   result_[0] = new_type.GetId();
-  result_[1] = RegType::kRegTypeUndefined;
-  if (new_type.IsLowHalf()) {
-    DCHECK_EQ(new_type.HighHalf(verifier_->GetRegTypeCache()).GetId(), new_type.GetId() + 1);
-    result_[1] = new_type.GetId() + 1;
-  } else {
-    result_[1] = RegType::kRegTypeUndefined;
-  }
+  result_[1] = verifier_->GetRegTypeCache()->Undefined().GetId();
 }
 
-void RegisterLine::SetResultRegisterTypeWide(const RegType& new_type1, const RegType& new_type2) {
+void RegisterLine::SetResultRegisterTypeWide(const RegType& new_type1,
+                                             const RegType& new_type2) {
   DCHECK(new_type1.CheckWidePair(new_type2));
   result_[0] = new_type1.GetId();
   result_[1] = new_type2.GetId();
@@ -118,16 +113,18 @@
   return this_type;
 }
 
-bool RegisterLine::VerifyRegisterType(uint32_t vsrc, const RegType& check_type) {
+bool RegisterLine::VerifyRegisterType(uint32_t vsrc,
+                                      const RegType& check_type) {
   // Verify the src register type against the check type refining the type of the register
   const RegType& src_type = GetRegisterType(vsrc);
-  if (!check_type.IsAssignableFrom(src_type)) {
+  if (!(check_type.IsAssignableFrom(src_type))) {
     // Hard fail if one of the types is primitive, since they are concretely known.
     enum VerifyError fail_type = (!check_type.IsNonZeroReferenceTypes() ||
-                                  !src_type.IsNonZeroReferenceTypes()) ?
-                                  VERIFY_ERROR_BAD_CLASS_HARD : VERIFY_ERROR_BAD_CLASS_SOFT;
-    verifier_->Fail(fail_type) << "register v" << vsrc << " has type " << src_type
-                               << " but expected " << check_type;
+                                  !src_type.IsNonZeroReferenceTypes())
+                                 ? VERIFY_ERROR_BAD_CLASS_HARD
+                                 : VERIFY_ERROR_BAD_CLASS_SOFT;
+    verifier_->Fail(fail_type) << "register v" << vsrc << " has type "
+                               << src_type << " but expected " << check_type;
     return false;
   }
   if (check_type.IsLowHalf()) {
@@ -185,11 +182,11 @@
   std::string result;
   for (size_t i = 0; i < num_regs_; i++) {
     result += StringPrintf("%zd:[", i);
-    result += GetRegisterType(i).Dump(verifier_->GetRegTypeCache());
+    result += GetRegisterType(i).Dump();
     result += "],";
   }
-  typedef std::deque<uint32_t>::const_iterator It; // TODO: C++0x auto
-  for (It it = monitors_.begin(), end = monitors_.end(); it != end ; ++it) {
+  typedef std::deque<uint32_t>::const_iterator It;  // TODO: C++0x auto
+  for (It it = monitors_.begin(), end = monitors_.end(); it != end; ++it) {
     result += StringPrintf("{%d},", *it);
   }
   return result;
@@ -240,7 +237,7 @@
   } else {
     DCHECK(verifier_->GetRegTypeCache()->GetFromId(result_[1]).IsUndefined());
     SetRegisterType(vdst, type);
-    result_[0] = RegType::kRegTypeUndefined;
+    result_[0] = verifier_->GetRegTypeCache()->Undefined().GetId();
   }
 }
 
@@ -257,13 +254,15 @@
   } else {
     DCHECK(type_l.CheckWidePair(type_h));  // Set should never allow this case
     SetRegisterTypeWide(vdst, type_l, type_h);  // also sets the high
-    result_[0] = RegType::kRegTypeUndefined;
-    result_[1] = RegType::kRegTypeUndefined;
+    result_[0] = verifier_->GetRegTypeCache()->Undefined().GetId();
+    result_[1] = verifier_->GetRegTypeCache()->Undefined().GetId();
+
   }
 }
 
 void RegisterLine::CheckUnaryOp(const DecodedInstruction& dec_insn,
-                                const RegType& dst_type, const RegType& src_type) {
+                                const RegType& dst_type,
+                                const RegType& src_type) {
   if (VerifyRegisterType(dec_insn.vB, src_type)) {
     SetRegisterType(dec_insn.vA, dst_type);
   }
diff --git a/src/verifier/register_line.h b/src/verifier/register_line.h
index 8253f51..5719082 100644
--- a/src/verifier/register_line.h
+++ b/src/verifier/register_line.h
@@ -52,10 +52,11 @@
 class RegisterLine {
  public:
   RegisterLine(size_t num_regs, MethodVerifier* verifier)
-      : line_(new uint16_t[num_regs]), verifier_(verifier), num_regs_(num_regs) {
+      : line_(new uint16_t[num_regs]),
+        verifier_(verifier),
+        num_regs_(num_regs) {
     memset(line_.get(), 0, num_regs_ * sizeof(uint16_t));
-    result_[0] = RegType::kRegTypeUndefined;
-    result_[1] = RegType::kRegTypeUndefined;
+    SetResultTypeToUnknown();
   }
 
   // Implement category-1 "move" instructions. Copy a 32-bit value from "vsrc" to "vdst".
@@ -78,7 +79,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Set the invisible result register to unknown
-  void SetResultTypeToUnknown();
+  void SetResultTypeToUnknown() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Set the type of register N, verifying that the register is valid.  If "newType" is the "Lo"
   // part of a 64-bit value, register N+1 will be set to "newType+1".