Add notion of precise register types to verifier.

When a class may have sub-classes we don't know if a method is
overridden. Add an ability to the verifier to track when we have precise
type information. This allows the verifier differentiate the case of having
something that must be of the type from the case where something is that
type or its sub-classes.

Change-Id: I9995be7d6c147db3b22aa390b776d9c2eb93edd8
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 {