Merge "Fix typo." into dalvik-dev
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index ad238b8..67507bc 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -1054,7 +1054,8 @@
     os << "Native method\n";
     return;
   }
-  DCHECK(code_item_ != NULL);
+  reg_types_.Dump(os);
+  os << "Dumping instructions and register lines:\n";
   const Instruction* inst = Instruction::At(code_item_->insns_);
   for (size_t dex_pc = 0; dex_pc < code_item_->insns_size_in_code_units_;
       dex_pc += insn_flags_[dex_pc].GetLengthInCodeUnits()) {
@@ -1128,7 +1129,7 @@
         // it's effectively considered initialized the instant we reach here (in the sense that we
         // can return without doing anything or call virtual methods).
         {
-          const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, descriptor);
+          const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
           reg_line->SetRegisterType(arg_start + cur_arg, reg_type);
         }
         break;
@@ -1527,7 +1528,8 @@
       const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vB);
       // Register holds class, ie its type is class, on error it will hold Conflict.
       work_line_->SetRegisterType(dec_insn.vA,
-                                  res_type.IsConflict() ? res_type : reg_types_.JavaLangClass());
+                                  res_type.IsConflict() ? res_type
+                                                        : reg_types_.JavaLangClass(true));
       break;
     }
     case Instruction::MONITOR_ENTER:
@@ -1667,7 +1669,7 @@
       break;
     case Instruction::THROW: {
       const RegType& res_type = work_line_->GetRegisterType(dec_insn.vA);
-      if (!reg_types_.JavaLangThrowable().IsAssignableFrom(res_type)) {
+      if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(res_type)) {
         Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "thrown class " << res_type << " not instanceof Throwable";
       }
       break;
@@ -1785,7 +1787,7 @@
       VerifyAGet(dec_insn, reg_types_.Long(), true);
       break;
     case Instruction::AGET_OBJECT:
-      VerifyAGet(dec_insn, reg_types_.JavaLangObject(), false);
+      VerifyAGet(dec_insn, reg_types_.JavaLangObject(false), false);
       break;
 
     case Instruction::APUT_BOOLEAN:
@@ -1807,7 +1809,7 @@
       VerifyAPut(dec_insn, reg_types_.Long(), true);
       break;
     case Instruction::APUT_OBJECT:
-      VerifyAPut(dec_insn, reg_types_.JavaLangObject(), false);
+      VerifyAPut(dec_insn, reg_types_.JavaLangObject(false), false);
       break;
 
     case Instruction::IGET_BOOLEAN:
@@ -1829,7 +1831,7 @@
       VerifyISGet(dec_insn, reg_types_.Long(), true, false);
       break;
     case Instruction::IGET_OBJECT:
-      VerifyISGet(dec_insn, reg_types_.JavaLangObject(), false, false);
+      VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, false);
       break;
 
     case Instruction::IPUT_BOOLEAN:
@@ -1851,7 +1853,7 @@
       VerifyISPut(dec_insn, reg_types_.Long(), true, false);
       break;
     case Instruction::IPUT_OBJECT:
-      VerifyISPut(dec_insn, reg_types_.JavaLangObject(), false, false);
+      VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, false);
       break;
 
     case Instruction::SGET_BOOLEAN:
@@ -1873,7 +1875,7 @@
       VerifyISGet(dec_insn, reg_types_.Long(), true, true);
       break;
     case Instruction::SGET_OBJECT:
-      VerifyISGet(dec_insn, reg_types_.JavaLangObject(), false, true);
+      VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, true);
       break;
 
     case Instruction::SPUT_BOOLEAN:
@@ -1895,7 +1897,7 @@
       VerifyISPut(dec_insn, reg_types_.Long(), true, true);
       break;
     case Instruction::SPUT_OBJECT:
-      VerifyISPut(dec_insn, reg_types_.JavaLangObject(), false, true);
+      VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, true);
       break;
 
     case Instruction::INVOKE_VIRTUAL:
@@ -1916,7 +1918,7 @@
       } else {
         descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
       }
-      const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor);
+      const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
       work_line_->SetResultRegisterType(return_type);
       just_set_result = true;
       break;
@@ -1977,7 +1979,8 @@
          */
         work_line_->MarkRefsAsInitialized(this_type);
       }
-      const RegType& return_type = reg_types_.FromDescriptor(class_loader_, return_type_descriptor);
+      const RegType& return_type = reg_types_.FromDescriptor(class_loader_, return_type_descriptor,
+                                                             false);
       work_line_->SetResultRegisterType(return_type);
       just_set_result = true;
       break;
@@ -1995,7 +1998,7 @@
         } else {
           descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
         }
-        const RegType& return_type =  reg_types_.FromDescriptor(class_loader_, descriptor);
+        const RegType& return_type =  reg_types_.FromDescriptor(class_loader_, descriptor, false);
         work_line_->SetResultRegisterType(return_type);
         just_set_result = true;
       }
@@ -2045,7 +2048,7 @@
       } else {
         descriptor = MethodHelper(abs_method).GetReturnTypeDescriptor();
       }
-      const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor);
+      const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
       work_line_->SetResultRegisterType(return_type);
       work_line_->SetResultRegisterType(return_type);
       just_set_result = true;
@@ -2466,8 +2469,8 @@
   const RegType& referrer = GetDeclaringClass();
   Class* klass = dex_cache_->GetResolvedType(class_idx);
   const RegType& result =
-      klass != NULL ? reg_types_.FromClass(klass)
-                    : reg_types_.FromDescriptor(class_loader_, descriptor);
+      klass != NULL ? reg_types_.FromClass(klass, klass->IsFinal())
+                    : reg_types_.FromDescriptor(class_loader_, descriptor, false);
   if (result.IsConflict()) {
     Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "accessing broken descriptor '" << descriptor
         << "' in " << referrer;
@@ -2495,14 +2498,14 @@
       for (; iterator.HasNext(); iterator.Next()) {
         if (iterator.GetHandlerAddress() == (uint32_t) work_insn_idx_) {
           if (iterator.GetHandlerTypeIndex() == DexFile::kDexNoIndex16) {
-            common_super = &reg_types_.JavaLangThrowable();
+            common_super = &reg_types_.JavaLangThrowable(false);
           } else {
             const RegType& exception = ResolveClassAndCheckAccess(iterator.GetHandlerTypeIndex());
             if (common_super == NULL) {
               // Unconditionally assign for the first handler. We don't assert this is a Throwable
               // as that is caught at runtime
               common_super = &exception;
-            } else if (!reg_types_.JavaLangThrowable().IsAssignableFrom(exception)) {
+            } else if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(exception)) {
               // We don't know enough about the type and the common path merge will result in
               // Conflict. Fail here knowing the correct thing can be done at runtime.
               Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "unexpected non-exception class " << exception;
@@ -2511,7 +2514,7 @@
               // odd case, but nothing to do
             } else {
               common_super = &common_super->Merge(exception, &reg_types_);
-              CHECK(reg_types_.JavaLangThrowable().IsAssignableFrom(*common_super));
+              CHECK(reg_types_.JavaLangThrowable(false).IsAssignableFrom(*common_super));
             }
           }
         }
@@ -2677,7 +2680,8 @@
       return NULL;
     }
     if (method_type != METHOD_INTERFACE && !actual_arg_type.IsZero()) {
-      const RegType& res_method_class = reg_types_.FromClass(res_method->GetDeclaringClass());
+      Class* klass = res_method->GetDeclaringClass();
+      const RegType& res_method_class = reg_types_.FromClass(klass, klass->IsFinal());
       if (!res_method_class.IsAssignableFrom(actual_arg_type)) {
         Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "'this' argument '" << actual_arg_type
             << "' not instance of '" << res_method_class << "'";
@@ -2707,7 +2711,7 @@
           << " missing signature component";
       return NULL;
     }
-    const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, descriptor);
+    const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
     uint32_t get_reg = is_range ? dec_insn.vC + actual_args : dec_insn.arg[actual_args];
     if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
       return res_method;
@@ -2904,7 +2908,8 @@
     // Cannot infer and check type, however, access will cause null pointer exception
     return field;
   } else {
-    const RegType& field_klass = reg_types_.FromClass(field->GetDeclaringClass());
+    Class* klass = field->GetDeclaringClass();
+    const RegType& field_klass = reg_types_.FromClass(klass, klass->IsFinal());
     if (obj_type.IsUninitializedTypes() &&
         (!IsConstructor() || GetDeclaringClass().Equals(obj_type) ||
             !field_klass.Equals(GetDeclaringClass()))) {
@@ -2947,7 +2952,7 @@
     descriptor = dex_file_->GetFieldTypeDescriptor(field_id);
     loader = class_loader_;
   }
-  const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor);
+  const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
   if (is_primitive) {
     if (field_type.Equals(insn_type) ||
         (field_type.IsFloat() && insn_type.IsIntegralTypes()) ||
@@ -2996,7 +3001,7 @@
     descriptor = dex_file_->GetFieldTypeDescriptor(field_id);
     loader = class_loader_;
   }
-  const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor);
+  const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
   if (field != NULL) {
     if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
       Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
@@ -3104,16 +3109,17 @@
   const DexFile::ProtoId& proto_id = dex_file_->GetMethodPrototype(method_id);
   uint16_t return_type_idx = proto_id.return_type_idx_;
   const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(return_type_idx));
-  return reg_types_.FromDescriptor(class_loader_, descriptor);
+  return reg_types_.FromDescriptor(class_loader_, descriptor, false);
 }
 
 const RegType& MethodVerifier::GetDeclaringClass() {
   if (foo_method_ != NULL) {
-    return reg_types_.FromClass(foo_method_->GetDeclaringClass());
+    Class* klass = foo_method_->GetDeclaringClass();
+    return reg_types_.FromClass(klass, klass->IsFinal());
   } else {
     const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx_);
     const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
-    return reg_types_.FromDescriptor(class_loader_, descriptor);
+    return reg_types_.FromDescriptor(class_loader_, descriptor, false);
   }
 }
 
diff --git a/src/verifier/reg_type.cc b/src/verifier/reg_type.cc
index f555223..e02fbf4 100644
--- a/src/verifier/reg_type.cc
+++ b/src/verifier/reg_type.cc
@@ -46,11 +46,12 @@
     "Unresolved Merged References",
     "Unresolved Super Class",
     "Reference",
+    "Precise Reference",
 };
 
 std::string RegType::Dump(const RegTypeCache* reg_types) const {
-  DCHECK(type_ >=  kRegTypeUndefined && type_ <= kRegTypeReference);
-  DCHECK(arraysize(type_strings) == (kRegTypeReference + 1));
+  DCHECK(type_ >=  kRegTypeUndefined && type_ <= kRegTypePreciseReference);
+  DCHECK(arraysize(type_strings) == (kRegTypePreciseReference + 1));
   std::string result;
   if (IsUnresolvedMergedReference()) {
     if (reg_types == NULL) {
@@ -142,7 +143,7 @@
   if (!IsUnresolvedTypes()) {
     Class* super_klass = GetClass()->GetSuperClass();
     if (super_klass != NULL) {
-      return cache->FromClass(super_klass);
+      return cache->FromClass(super_klass, IsPreciseReference());
     } else {
       return cache->Zero();
     }
@@ -150,7 +151,7 @@
     if (!IsUnresolvedMergedReference() && !IsUnresolvedSuperClass() &&
         GetDescriptor()->CharAt(0) == '[') {
       // Super class of all arrays is Object.
-      return cache->JavaLangObject();
+      return cache->JavaLangObject(true);
     } else {
       return cache->FromUnresolvedSuperClass(*this);
     }
@@ -301,7 +302,7 @@
     if (IsZero() || incoming_type.IsZero()) {
       return SelectNonConstant(*this, incoming_type);  // 0 MERGE ref => ref
     } else if (IsJavaLangObject() || incoming_type.IsJavaLangObject()) {
-      return reg_types->JavaLangObject();  // Object MERGE ref => Object
+      return reg_types->JavaLangObject(false);  // Object MERGE ref => Object
     } else if (IsUnresolvedTypes() || incoming_type.IsUnresolvedTypes()) {
       // We know how to merge an unresolved type with itself, 0 or Object. In this case we
       // have two sub-classes and don't know how to merge. Create a new string-based unresolved
@@ -319,12 +320,12 @@
       DCHECK(c1 != NULL && !c1->IsPrimitive());
       DCHECK(c2 != NULL && !c2->IsPrimitive());
       Class* join_class = ClassJoin(c1, c2);
-      if (c1 == join_class) {
+      if (c1 == join_class && !IsPreciseReference()) {
         return *this;
-      } else if (c2 == join_class) {
+      } else if (c2 == join_class && !incoming_type.IsPreciseReference()) {
         return incoming_type;
       } else {
-        return reg_types->FromClass(join_class);
+        return reg_types->FromClass(join_class, false);
       }
     }
   } else {
diff --git a/src/verifier/reg_type.h b/src/verifier/reg_type.h
index 3064f30..205867d 100644
--- a/src/verifier/reg_type.h
+++ b/src/verifier/reg_type.h
@@ -65,6 +65,7 @@
     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 {
@@ -93,6 +94,8 @@
   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();
@@ -154,7 +157,7 @@
   }
 
   bool IsNonZeroReferenceTypes() const {
-    return IsReference() || IsUnresolvedReference() ||
+    return IsReference() || IsPreciseReference() || IsUnresolvedReference() ||
         IsUninitializedReference() || IsUninitializedThisReference() ||
         IsUnresolvedAndUninitializedReference() || IsUnresolvedAndUninitializedThisReference() ||
         IsUnresolvedMergedReference() || IsUnresolvedSuperClass();
@@ -198,6 +201,10 @@
     return allocation_pc_or_constant_or_merged_types_;
   }
 
+  bool HasClass() const {
+    return IsReference() || IsPreciseReference();
+  }
+
   Class* GetClass() const {
     DCHECK(!IsUnresolvedReference());
     DCHECK(klass_or_descriptor_ != NULL);
@@ -212,7 +219,7 @@
   bool IsArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     if (IsUnresolvedTypes() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass()) {
       return GetDescriptor()->CharAt(0) == '[';
-    } else if (IsReference()) {
+    } else if (HasClass()) {
       return GetClass()->IsArrayClass();
     } else {
       return false;
@@ -224,7 +231,7 @@
       // Primitive arrays will always resolve
       DCHECK(GetDescriptor()->CharAt(1) == 'L' || GetDescriptor()->CharAt(1) == '[');
       return GetDescriptor()->CharAt(0) == '[';
-    } else if (IsReference()) {
+    } else if (HasClass()) {
       Class* type = GetClass();
       return type->IsArrayClass() && !type->GetComponentType()->IsPrimitive();
     } else {
@@ -256,7 +263,7 @@
   }
 
   bool IsJavaLangObjectArray() const {
-    if (IsReference()) {
+    if (HasClass()) {
       Class* type = GetClass();
       return type->IsArrayClass() && type->GetComponentType()->IsObjectClass();
     }
diff --git a/src/verifier/reg_type_cache.cc b/src/verifier/reg_type_cache.cc
index 37086c9..847cde9 100644
--- a/src/verifier/reg_type_cache.cc
+++ b/src/verifier/reg_type_cache.cc
@@ -57,11 +57,18 @@
   }
 }
 
-const RegType& RegTypeCache::FromDescriptor(ClassLoader* loader, const char* descriptor) {
-  return From(RegTypeFromDescriptor(descriptor), loader, descriptor);
+const RegType& RegTypeCache::FromDescriptor(ClassLoader* loader, const char* descriptor,
+                                            bool precise) {
+  return From(RegTypeFromDescriptor(descriptor), loader, descriptor, precise);
 }
 
-const RegType& RegTypeCache::From(RegType::Type type, ClassLoader* loader, const char* descriptor) {
+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, 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));
@@ -76,14 +83,15 @@
     }
     return *entry;
   } else {
-    DCHECK(type == RegType::kRegTypeReference);
+    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->IsReference()) {
+      if (cur_entry->HasClass()) {
         kh.ChangeClass(cur_entry->GetClass());
-        if (strcmp(descriptor, kh.GetDescriptor()) == 0) {
+        if (MatchingPrecisionForClass(cur_entry, precise) &&
+            (strcmp(descriptor, kh.GetDescriptor()) == 0)) {
           return *cur_entry;
         }
       } else if (cur_entry->IsUnresolvedReference() &&
@@ -93,8 +101,11 @@
     }
     Class* klass = Runtime::Current()->GetClassLinker()->FindClass(descriptor, loader);
     if (klass != NULL) {
-      // Able to resolve so create resolved register type
-      RegType* entry = new RegType(type, klass, 0, entries_.size());
+      // Able to resolve so create resolved register type that is precise if we
+      // know the type is final.
+      RegType* entry = new RegType(klass->IsFinal() ? RegType::kRegTypePreciseReference
+                                                    : RegType::kRegTypeReference,
+                                   klass, 0, entries_.size());
       entries_.push_back(entry);
       return *entry;
     } else {
@@ -119,7 +130,7 @@
   }
 }
 
-const RegType& RegTypeCache::FromClass(Class* klass) {
+const RegType& RegTypeCache::FromClass(Class* klass, bool precise) {
   if (klass->IsPrimitive()) {
     RegType::Type type = RegTypeFromPrimitiveType(klass->GetPrimitiveType());
     // entries should be sized greater than primitive types
@@ -133,11 +144,14 @@
   } else {
     for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
-      if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
+      if ((cur_entry->HasClass()) &&
+          MatchingPrecisionForClass(cur_entry, precise) && cur_entry->GetClass() == klass) {
         return *cur_entry;
       }
     }
-    RegType* entry = new RegType(RegType::kRegTypeReference, klass, 0, entries_.size());
+    RegType* entry = new RegType(precise ? RegType::kRegTypePreciseReference
+                                         : RegType::kRegTypeReference,
+                                 klass, 0, entries_.size());
     entries_.push_back(entry);
     return *entry;
   }
@@ -243,11 +257,11 @@
     Class* klass = uninit_type.GetClass();
     for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
-      if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
+      if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
         return *cur_entry;
       }
     }
-    entry = new RegType(RegType::kRegTypeReference, klass, 0, entries_.size());
+    entry = new RegType(RegType::kRegTypePreciseReference, klass, 0, entries_.size());
   }
   entries_.push_back(entry);
   return *entry;
@@ -284,17 +298,17 @@
 const RegType& RegTypeCache::FromType(RegType::Type type) {
   CHECK(type < RegType::kRegTypeReference);
   switch (type) {
-    case RegType::kRegTypeBoolean:  return From(type, NULL, "Z");
-    case RegType::kRegTypeByte:     return From(type, NULL, "B");
-    case RegType::kRegTypeShort:    return From(type, NULL, "S");
-    case RegType::kRegTypeChar:     return From(type, NULL, "C");
-    case RegType::kRegTypeInteger:  return From(type, NULL, "I");
-    case RegType::kRegTypeFloat:    return From(type, NULL, "F");
+    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");
+    case RegType::kRegTypeLongHi:   return From(type, NULL, "J", true);
     case RegType::kRegTypeDoubleLo:
-    case RegType::kRegTypeDoubleHi: return From(type, NULL, "D");
-    default:                        return From(type, NULL, "");
+    case RegType::kRegTypeDoubleHi: return From(type, NULL, "D", true);
+    default:                        return From(type, NULL, "", true);
   }
 }
 
@@ -315,9 +329,20 @@
   if (array.IsUnresolvedTypes()) {
     std::string descriptor(array.GetDescriptor()->ToModifiedUtf8());
     std::string component(descriptor.substr(1, descriptor.size() - 1));
-    return FromDescriptor(loader, component.c_str());
+    return FromDescriptor(loader, component.c_str(), false);
   } else {
-    return FromClass(array.GetClass()->GetComponentType());
+    Class* klass = array.GetClass()->GetComponentType();
+    return FromClass(klass, klass->IsFinal());
+  }
+}
+
+void RegTypeCache::Dump(std::ostream& os) {
+  os << "Register Types:\n";
+  for (size_t i = 0; i < entries_.size(); i++) {
+    RegType* cur_entry = entries_[i];
+    if (cur_entry != NULL) {
+      os << "\t" << i << ": " << cur_entry->Dump() << "\n";
+    }
   }
 }
 
diff --git a/src/verifier/reg_type_cache.h b/src/verifier/reg_type_cache.h
index 5a2c49c..36fd2c7 100644
--- a/src/verifier/reg_type_cache.h
+++ b/src/verifier/reg_type_cache.h
@@ -40,12 +40,12 @@
     return *result;
   }
 
-  const RegType& From(RegType::Type type, ClassLoader* loader, const char* descriptor)
+  const RegType& From(RegType::Type type, ClassLoader* loader, const char* descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const RegType& FromClass(Class* klass)
+  const RegType& FromClass(Class* klass, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& FromCat1Const(int32_t value);
-  const RegType& FromDescriptor(ClassLoader* loader, const char* descriptor)
+  const RegType& FromDescriptor(ClassLoader* loader, const char* descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& FromType(RegType::Type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -77,17 +77,24 @@
     return FromType(RegType::kRegTypeDoubleLo);
   }
 
-  const RegType& JavaLangClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return From(RegType::kRegTypeReference, NULL, "Ljava/lang/Class;");
+  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() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return From(RegType::kRegTypeReference, NULL, "Ljava/lang/Object;");
+  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_) {
-    return From(RegType::kRegTypeReference, NULL, "Ljava/lang/String;");
+    // String is final and therefore always precise.
+    return From(RegType::kRegTypePreciseReference, NULL, "Ljava/lang/String;", true);
   }
-  const RegType& JavaLangThrowable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return From(RegType::kRegTypeReference, NULL, "Ljava/lang/Throwable;");
+  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_) {
@@ -118,6 +125,8 @@
   const RegType& GetComponentType(const RegType& array, ClassLoader* loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   // The allocated entries
   std::vector<RegType*> entries_;